//: Helper for various programming environments: run arbitrary Mu code and //: return some result in text form. :(scenario run_interactive_code) def main [ 1:num/raw <- copy 0 2:text <- new [1:num/raw <- copy 34] run-sandboxed 2:text 3:num/raw <- copy 1:num/raw ] +mem: storing 34 in location 3 :(scenario run_interactive_empty) def main [ 1:text <- copy 0/unsafe 2:text <- run-sandboxed 1:text ] # result is null +mem: storing 0 in location 2 //: As the name suggests, 'run-sandboxed' will prevent certain operations that //: regular Mu code can perform. :(before "End Globals") bool Sandbox_mode = false; //: for starters, users can't override 'main' when the environment is running :(before "End Load Recipe Name") if (Sandbox_mode && result.name == "main") { slurp_balanced_bracket(in); return -1; } //: run code in 'interactive mode', i.e. with errors off and return: //: stringified output in case we want to print it to screen //: any errors encountered //: simulated screen any prints went to //: any 'app' layer traces generated :(before "End Primitive Recipe Declarations") RUN_SANDBOXED, :(before "End Primitive Recipe Numbers") put(Recipe_ordinal, "run-sandboxed", RUN_SANDBOXED); :(before "End Primitive Recipe Checks") case RUN_SANDBOXED: { if (SIZE(inst.ingredients) != 1) { raise << maybe(get(Recipe, r).name) << "'run-sandboxed' requires exactly one ingredient, but got '" << inst.original_string << "'\n" << end(); break; } if (!is_mu_text(inst.ingredients.at(0))) { raise << maybe(get(Recipe, r).name) << "first ingredient of 'run-sandboxed' should be a string, but got '" << to_string(inst.ingredients.at(0)) << "'\n" << end(); break; } break; } :(before "End Primitive Recipe Implementations") case RUN_SANDBOXED: { bool new_code_pushed_to_stack = run_interactive(ingredients.at(0).at(0)); if (!new_code_pushed_to_stack) { products.resize(5); products.at(0).push_back(0); products.at(1).push_back(trace_error_contents()); products.at(2).push_back(0); products.at(3).push_back(trace_app_contents()); products.at(4).push_back(1); // completed run_code_end(); break; // done with this instruction } else { continue; // not done with caller; don't increment current_step_index() } } //: To show results in the sandbox Mu uses a hack: it saves the products //: returned by each instruction while Track_most_recent_products is true, and //: keeps the most recent such result around so that it can be returned as the //: result of a sandbox. :(before "End Globals") bool Track_most_recent_products = false; string Most_recent_products; :(before "End Setup") Track_most_recent_products = false; Most_recent_products = ""; :(before "End Globals") trace_stream* Save_trace_stream = NULL; string Save_trace_file; :(code) // reads a string, tries to call it as code (treating it as a test), saving // all errors. // returns true if successfully called (no errors found during load and transform) bool run_interactive(int address) { assert(contains_key(Recipe_ordinal, "interactive") && get(Recipe_ordinal, "interactive") != 0); // try to sandbox the run as best you can // todo: test this if (!Current_scenario) { for (int i = 1; i < Reserved_for_tests; ++i) Memory.erase(i); } string command = trim(strip_comments(read_mu_text(address))); Name[get(Recipe_ordinal, "interactive")].clear(); run_code_begin(/*should_stash_snapshots*/true); if (command.empty()) return false; // don't kill the current routine on parse errors routine* save_current_routine = Current_routine; Current_routine = NULL; // call run(string) but without the scheduling load(string("recipe! interactive [\n") + "new-default-space\n" + // disable automatic abandon so tests can see changes "screen:&:screen <- next-ingredient\n" + "$start-tracking-products\n" + command + "\n" + "$stop-tracking-products\n" + "return screen\n" + "]\n"); transform_all(); Current_routine = save_current_routine; if (trace_count("error") > 0) return false; // now call 'sandbox' which will run 'interactive' in a separate routine, // and wait for it if (Save_trace_stream) { ++Save_trace_stream->callstack_depth; trace(9999, "trace") << "run-sandboxed: incrementing callstack depth to " << Save_trace_stream->callstack_depth << end(); assert(Save_trace_stream->callstack_depth < 9000); // 9998-101 plus cushion } Current_routine->calls.push_front(call(get(Recipe_ordinal, "sandbox"))); return true; } //: Carefully update all state to exactly how it was -- including snapshots. :(before "End Globals") map Recipe_ordinal_snapshot_stash; map Recipe_snap
#
#
#            Nim's Runtime Library
#        (c) Copyright 2015 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

# Pragmas for RTL generation. Has to be an include, because user-defined
# pragmas cannot be exported.

# There are 3 different usages:
# 1) Ordinary imported code.
# 2) Imported from nimrtl.
#    -> defined(useNimRtl) or appType == "lib" and not defined(createNimRtl)
# 3) Exported into nimrtl.
#    -> appType == "lib" and defined(createNimRtl)
when not defined(nimNewShared):
  {.pragma: gcsafe.}

when defined(createNimRtl):
  when defined(useNimRtl): 
    {.error: "Cannot create and use nimrtl at the same time!".}
  elif appType != "lib":
    {.error: "nimrtl must be built as a library!".}

when defined(createNimRtl): 
  {.pragma: rtl, exportc: "nimrtl_$1", dynlib, gcsafe.}
  {.pragma: inl.}
  {.pragma: compilerRtl, compilerproc, exportc: "nimrtl_$1", dynlib.}
elif defined(useNimRtl):
  when defined(windows): 
    const nimrtl* = "nimrtl.dll"
  elif defined(macosx):
    const nimrtl* = "nimrtl.dylib"
  else: 
    const nimrtl* = "libnimrtl.so"
  {.pragma: rtl, importc: "nimrtl_$1", dynlib: nimrtl, gcsafe.}
  {.pragma: inl.}
  {.pragma: compilerRtl, compilerproc, importc: "nimrtl_$1", dynlib: nimrtl.}
else:
  {.pragma: rtl, gcsafe.}
  {.pragma: inl, inline.}
  {.pragma: compilerRtl, compilerproc.}

when not defined(nimsuperops):
  {.pragma: <