about summary refs log blame commit diff stats
path: root/continuation2.mu
blob: 45a65e9ff63796809aa8eeb2d19cae766399ac06 (plain) (tree)
1
2
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color
# Example program showing that a 'paused' continuation can be 'resumed'
# multiple times from the same point (but with changes to data).
#
# To run:
#   $ git clone https://github.com/akkartik/mu
#   $ cd mu
#   $ ./mu continuation2.mu
#
# Expected output:
#   1
#   2
#   3

def main [
  local-scope
  l:&:list:num <- copy null
  l <- push 3, l
  l <- push 2, l
  l <- push 1, l
  k:continuation <- call-with-continuation-mark 100/mark, create-yielder, l
  {
    x:num, done?:bool <- call k
    break-if done?
    $print x 10/newline
    loop
  }
]

def create-yielder l:&:list:num -> n:num, done?:bool [
  local-scope
  load-inputs
  return-continuation-until-mark 100/mark
  done? <- equal l, null
  return-if done?, 0/dummy
  n <- first l
  l <- rest l
]
n class="s">" << end(); break; } if (!is_mu_recipe(inst.ingredients.at(0))) { raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'call' should be a recipe, but got " << inst.ingredients.at(0).original_string << '\n' << end(); break; } break; } :(before "End Primitive Recipe Implementations") case CALL: { // Begin Call if (Trace_stream) { ++Trace_stream->callstack_depth; trace("trace") << "indirect 'call': incrementing callstack depth to " << Trace_stream->callstack_depth << end(); assert(Trace_stream->callstack_depth < 9000); // 9998-101 plus cushion } const instruction& caller_instruction = current_instruction(); Current_routine->calls.push_front(call(ingredients.at(0).at(0))); ingredients.erase(ingredients.begin()); // drop the callee finish_call_housekeeping(caller_instruction, ingredients); continue; } //:: check types for 'call' instructions :(scenario call_check_literal_recipe) % Hide_errors = true; recipe main [ 1:number <- call f, 34 ] recipe f x:boolean -> y:boolean [ local-scope load-ingredients y <- copy x ] +error: main: ingredient 0 has the wrong type at '1:number <- call f, 34' +error: main: product 0 has the wrong type at '1:number <- call f, 34' :(scenario call_check_variable_recipe) % Hide_errors = true; recipe main [ {1: (recipe boolean -> boolean)} <- copy f 2:number <- call {1: (recipe boolean -> boolean)}, 34 ] recipe f x:boolean -> y:boolean [ local-scope load-ingredients y <- copy x ] +error: main: ingredient 0 has the wrong type at '2:number <- call {1: (recipe boolean -> boolean)}, 34' +error: main: product 0 has the wrong type at '2:number <- call {1: (recipe boolean -> boolean)}, 34' :(after "Transform.push_back(check_instruction)") Transform.push_back(check_indirect_calls_against_header); // idempotent :(code) void check_indirect_calls_against_header(const recipe_ordinal r) { trace(9991, "transform") << "--- type-check 'call' instructions inside recipe " << get(Recipe, r).name << end(); const recipe& caller = get(Recipe, r); for (long long int i = 0; i < SIZE(caller.steps); ++i) { const instruction& inst = caller.steps.at(i); if (inst.operation != CALL) continue; if (inst.ingredients.empty()) continue; // error raised above const reagent& callee = inst.ingredients.at(0); if (!is_mu_recipe(callee)) continue; // error raised above const recipe callee_header = is_literal(callee) ? get(Recipe, callee.value) : from_reagent(inst.ingredients.at(0)); if (!callee_header.has_header) continue; for (long int i = /*skip callee*/1; i < min(SIZE(inst.ingredients), SIZE(callee_header.ingredients)+/*skip callee*/1); ++i) { if (!types_coercible(callee_header.ingredients.at(i-/*skip callee*/1), inst.ingredients.at(i))) raise_error << maybe(caller.name) << "ingredient " << i-/*skip callee*/1 << " has the wrong type at '" << to_string(inst) << "'\n" << end(); } for (long int i = 0; i < min(SIZE(inst.products), SIZE(callee_header.products)); ++i) { if (is_dummy(inst.products.at(i))) continue; if (!types_coercible(callee_header.products.at(i), inst.products.at(i))) raise_error << maybe(caller.name) << "product " << i << " has the wrong type at '" << to_string(inst) << "'\n" << end(); } } } recipe from_reagent(const reagent& r) { assert(r.properties.at(0).second->value == "recipe"); recipe result_header; // will contain only ingredients and products, nothing else result_header.has_header = true; const string_tree* curr = r.properties.at(0).second->right; for (; curr; curr=curr->right) { if (curr->value == "->") { curr = curr->right; // skip delimiter break; } result_header.ingredients.push_back("recipe:"+curr->value); } for (; curr; curr=curr->right) { result_header.products.push_back("recipe:"+curr->value); } return result_header; } bool is_mu_recipe(reagent r) { if (!r.type) return false; if (r.properties.at(0).second->value == "recipe") return true; if (r.properties.at(0).second->value == "recipe-literal") return true; // End is_mu_recipe Cases return false; } :(scenario copy_typecheck_recipe_variable) % Hide_errors = true; recipe main [ 3:number <- copy 34 # abc def {1: (recipe number -> number)} <- copy f # store literal in a matching variable {2: (recipe boolean -> boolean)} <- copy {1: (recipe number -> number)} # mismatch between recipe variables ] recipe f x:number -> y:number [ local-scope load-ingredients y <- copy x ] +error: main: can't copy {1: (recipe number -> number)} to {2: (recipe boolean -> boolean)}; types don't match :(scenario copy_typecheck_recipe_variable_2) % Hide_errors = true; recipe main [ {1: (recipe number -> number)} <- copy f # mismatch with a recipe literal ] recipe f x:boolean -> y:boolean [ local-scope load-ingredients y <- copy x ] +error: main: can't copy f to {1: (recipe number -> number)}; types don't match :(before "End Matching Types For Literal(to)") if (is_mu_recipe(to)) { if (!contains_key(Recipe, from.value)) { raise_error << "trying to store recipe " << from.name << " into " << to_string(to) << " but there's no such recipe\n" << end(); return false; } const recipe& rrhs = get(Recipe, from.value); const recipe& rlhs = from_reagent(to); for (long int i = 0; i < min(SIZE(rlhs.ingredients), SIZE(rrhs.ingredients)); ++i) { if (!types_match(rlhs.ingredients.at(i), rrhs.ingredients.at(i))) return false; } for (long int i = 0; i < min(SIZE(rlhs.products), SIZE(rrhs.products)); ++i) { if (!types_match(rlhs.products.at(i), rrhs.products.at(i))) return false; } return true; }