about summary refs log tree commit diff stats
path: root/mu.arc.t
Commit message (Expand)AuthorAgeFilesLines
* 881Kartik K. Agaram2015-03-101-0/+1
* 742 - turns out chessboard test logs were incompleteKartik K. Agaram2015-02-111-9/+4
* 722 - split at substring, and assorted helpersKartik K. Agaram2015-02-081-0/+70
* 720 - substring matching and searchingKartik K. Agaram2015-02-081-0/+169
* 718 - disable raw memory warnings in testsKartik K. Agaram2015-02-081-0/+2
* 712Kartik K. Agaram2015-02-071-0/+14
* 711 - extract method: string-copyKartik K. Agaram2015-02-071-0/+1
* 708Kartik K. Agaram2015-02-051-10/+10
* 706Kartik K. Agaram2015-02-041-0/+83
* 705 - clean up traces before we try to parse themKartik K. Agaram2015-02-031-14/+16
* 689Kartik K. Agaram2015-01-311-1/+3
* 677 - more improvements for names in shared spacesKartik K. Agaram2015-01-291-1/+54
* 676 - allow routines to share *names* for localsKartik K. Agaram2015-01-291-0/+26
* 675Kartik K. Agaram2015-01-291-2/+2
* 635Kartik K. Agaram2015-01-261-1/+39
* 634Kartik K. Agaram2015-01-261-0/+35
* 630 - routines can now allocate unlimited memoryKartik K. Agaram2015-01-261-0/+2
* 629Kartik K. Agaram2015-01-261-1/+33
* 628Kartik K. Agaram2015-01-261-0/+27
* 627Kartik K. Agaram2015-01-261-0/+25
* 626 - start eliminating the memory-per-routine limitKartik K. Agaram2015-01-261-0/+23
* 625 - guard against errors with input-output argsKartik K. Agaram2015-01-251-0/+30
* 624 - no, that's all wrong, scratch 623Kartik K. Agaram2015-01-251-53/+23
* 623 - 'nochange' to guard against race conditionsKartik K. Agaram2015-01-251-23/+53
* 616 - buffered-stdin handles backspaceKartik K. Agaram2015-01-251-0/+34
* 604 - new function to buffer stdinKartik K. Agaram2015-01-241-0/+72
* 600 - fake keyboardKartik K. Agaram2015-01-221-3/+31
* 599Kartik K. Agaram2015-01-211-1/+0
* 598 - clear up a minor mysteryKartik K. Agaram2015-01-211-0/+1
* 597Kartik K. Agaram2015-01-211-0/+14
* 592Kartik K. Agaram2015-01-181-2/+5
* 582 - first tests for printing to screenKartik K. Agaram2015-01-171-0/+26
* 576 - helper for printing integersKartik K. Agaram2015-01-171-0/+35
* 569 - ah, the right way to do generic functionsKartik K. Agaram2015-01-141-0/+2
* 564Kartik K. Agaram2015-01-141-679/+679
* 542Kartik K. Agaram2015-01-121-0/+52
* 529 - 'sleep' can now wait for a routine to completeKartik K. Agaram2015-01-101-0/+26
* 528Kartik K. Agaram2015-01-101-3/+4
* 525 - 'fork' now returns a routine idKartik K. Agaram2015-01-101-0/+30
* 524Kartik K. Agaram2015-01-101-14/+14
* 522 - another arg for 'fork'Kartik K. Agaram2015-01-101-5/+23
* 519 - ooh, use metadata to disambiguate argsKartik K. Agaram2015-01-101-5/+5
* 515 - support time limits for threadsKartik K. Agaram2015-01-101-0/+124
* 514Kartik K. Agaram2015-01-091-16/+18
* 512 - update html renderingKartik K. Agaram2015-01-091-191/+227
* 511 - make 'sleep' clearerKartik K. Agaram2015-01-081-13/+13
* 510Kartik K. Agaram2015-01-081-2/+2
* 509Kartik K. Agaram2015-01-081-23/+23
* 506 - continue 505Kartik K. Agaram2015-01-061-21/+27
* 505 - simplify tagged-valueKartik K. Agaram2015-01-051-37/+26
eric.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: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
//: Comparison primitives

:(before "End Primitive Recipe Declarations")
EQUAL,
:(before "End Primitive Recipe Numbers")
put(Recipe_ordinal, "equal", EQUAL);
:(before "End Primitive Recipe Checks")
case EQUAL: {
  if (SIZE(inst.ingredients) <= 1) {
    raise << maybe(get(Recipe, r).name) << "'equal' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  const reagent& exemplar = inst.ingredients.at(0);
  for (int i = /*skip exemplar*/1;  i < SIZE(inst.ingredients);  ++i) {
    if (!types_match(inst.ingredients.at(i), exemplar) && !types_match(exemplar, inst.ingredients.at(i))) {
      raise << maybe(get(Recipe, r).name) << "'equal' expects ingredients to be all of the same type, but got '" << to_original_string(inst) << "'\n" << end();
      goto finish_checking_instruction;
    }
  }
  if (SIZE(inst.products) > 1) {
    raise << maybe(get(Recipe, r).name) << "'equal' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
    raise << maybe(get(Recipe, r).name) << "'equal' should yield a boolean, but got '" << inst.products.at(0).original_string << "'\n" << end();
    break;
  }
  break;
}
:(before "End Primitive Recipe Implementations")
case EQUAL: {
  vector<double>& exemplar = ingredients.at(0);
  bool result = true;
  for (int i = /*skip exemplar*/1;  i < SIZE(ingredients);  ++i) {
    if (SIZE(ingredients.at(i)) != SIZE(exemplar)) {
      result = false;
      break;
    }
    if (!equal(ingredients.at(i).begin(), ingredients.at(i).end(), exemplar.begin())) {
      result = false;
      break;
    }
  }
  products.resize(1);
  products.at(0).push_back(result);
  break;
}

:(scenario equal)
def main [
  1:num <- copy 34
  2:num <- copy 33
  3:bool <- equal 1:num, 2:num
]
+mem: location 1 is 34
+mem: location 2 is 33
+mem: storing 0 in location 3

:(scenario equal_2)
def main [
  1:num <- copy 34
  2:num <- copy 34
  3:bool <- equal 1:num, 2:num
]
+mem: location 1 is 34
+mem: location 2 is 34
+mem: storing 1 in location 3

:(scenario equal_multiple)
def main [
  1:bool <- equal 34, 34, 34
]
+mem: storing 1 in location 1

:(scenario equal_multiple_2)
def main [
  1:bool <- equal 34, 34, 35
]
+mem: storing 0 in location 1

:(before "End Primitive Recipe Declarations")
NOT_EQUAL,
:(before "End Primitive Recipe Numbers")
put(Recipe_ordinal, "not-equal", NOT_EQUAL);
:(before "End Primitive Recipe Checks")
case NOT_EQUAL: {
  if (SIZE(inst.ingredients) != 2) {
    raise << maybe(get(Recipe, r).name) << "'equal' needs two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  const reagent& exemplar = inst.ingredients.at(0);
  if (!types_match(inst.ingredients.at(1), exemplar) && !types_match(exemplar, inst.ingredients.at(1))) {
    raise << maybe(get(Recipe, r).name) << "'equal' expects ingredients to be all of the same type, but got '" << to_original_string(inst) << "'\n" << end();
    goto finish_checking_instruction;
  }
  if (SIZE(inst.products) > 1) {
    raise << maybe(get(Recipe, r).name) << "'equal' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
    raise << maybe(get(Recipe, r).name) << "'equal' should yield a boolean, but got '" << inst.products.at(0).original_string << "'\n" << end();
    break;
  }
  break;
}
:(before "End Primitive Recipe Implementations")
case NOT_EQUAL: {
  vector<double>& exemplar = ingredients.at(0);
  products.resize(1);
  if (SIZE(ingredients.at(1)) != SIZE(exemplar)) {
    products.at(0).push_back(true);
    break;
  }
  bool equal_ingredients = equal(ingredients.at(1).begin(), ingredients.at(1).end(), exemplar.begin());
  products.at(0).push_back(!equal_ingredients);
  break;
}

:(scenario not_equal)
def main [
  1:num <- copy 34
  2:num <- copy 33
  3:bool <- not-equal 1:num, 2:num
]
+mem: location 1 is 34
+mem: location 2 is 33
+mem: storing 1 in location 3

:(scenario not_equal_2)
def main [
  1:num <- copy 34
  2:num <- copy 34
  3:bool <- not-equal 1:num, 2:num
]
+mem: location 1 is 34
+mem: location 2 is 34
+mem: storing 0 in location 3

:(before "End Primitive Recipe Declarations")
GREATER_THAN,
:(before "End Primitive Recipe Numbers")
put(Recipe_ordinal, "greater-than", GREATER_THAN);
:(before "End Primitive Recipe Checks")
case GREATER_THAN: {
  if (SIZE(inst.ingredients) <= 1) {
    raise << maybe(get(Recipe, r).name) << "'greater-than' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
    if (!is_mu_number(inst.ingredients.at(i))) {
      raise << maybe(get(Recipe, r).name) << "'greater-than' can only compare numbers; got '" << inst.ingredients.at(i).original_string << "'\n" << end();
      goto finish_checking_instruction;
    }
  }
  if (SIZE(inst.products) > 1) {
    raise << maybe(get(Recipe, r).name) << "'greater-than' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
    raise << maybe(get(Recipe, r).name) << "'greater-than' should yield a boolean, but got '" << inst.products.at(0).original_string << "'\n" << end();
    break;
  }
  break;
}
:(before "End Primitive Recipe Implementations")
case GREATER_THAN: {
  bool result = true;
  for (int i = /**/1;  i < SIZE(ingredients);  ++i) {
    if (ingredients.at(i-1).at(0) <= ingredients.at(i).at(0)) {
      result = false;
    }
  }
  products.resize(1);
  products.at(0).push_back(result);
  break;
}

:(scenario greater_than)
def main [
  1:num <- copy 34
  2:num <- copy 33
  3:bool <- greater-than 1:num, 2:num
]
+mem: storing 1 in location 3

:(scenario greater_than_2)
def main [
  1:num <- copy 34
  2:num <- copy 34
  3:bool <- greater-than 1:num, 2:num
]
+mem: storing 0 in location 3

:(scenario greater_than_multiple)
def main [
  1:bool <- greater-than 36, 35, 34
]
+mem: storing 1 in location 1

:(scenario greater_than_multiple_2)
def main [
  1:bool <- greater-than 36, 35, 35
]
+mem: storing 0 in location 1

:(before "End Primitive Recipe Declarations")
LESSER_THAN,
:(before "End Primitive Recipe Numbers")
put(Recipe_ordinal, "lesser-than", LESSER_THAN);
:(before "End Primitive Recipe Checks")
case LESSER_THAN: {
  if (SIZE(inst.ingredients) <= 1) {
    raise << maybe(get(Recipe, r).name) << "'lesser-than' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
    if (!is_mu_number(inst.ingredients.at(i))) {
      raise << maybe(get(Recipe, r).name) << "'lesser-than' can only compare numbers; got '" << inst.ingredients.at(i).original_string << "'\n" << end();
      goto finish_checking_instruction;
    }
  }
  if (SIZE(inst.products) > 1) {
    raise << maybe(get(Recipe, r).name) << "'lesser-than' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
    raise << maybe(get(Recipe, r).name) << "'lesser-than' should yield a boolean, but got '" << inst.products.at(0).original_string << "'\n" << end();
    break;
  }
  break;
}
:(before "End Primitive Recipe Implementations")
case LESSER_THAN: {
  bool result = true;
  for (int i = /**/1;  i < SIZE(ingredients);  ++i) {
    if (ingredients.at(i-1).at(0) >= ingredients.at(i).at(0)) {
      result = false;
    }
  }
  products.resize(1);
  products.at(0).push_back(result);
  break;
}

:(scenario lesser_than)
def main [
  1:num <- copy 32
  2:num <- copy 33
  3:bool <- lesser-than 1:num, 2:num
]
+mem: storing 1 in location 3

:(scenario lesser_than_2)
def main [
  1:num <- copy 34
  2:num <- copy 33
  3:bool <- lesser-than 1:num, 2:num
]
+mem: storing 0 in location 3

:(scenario lesser_than_multiple)
def main [
  1:bool <- lesser-than 34, 35, 36
]
+mem: storing 1 in location 1

:(scenario lesser_than_multiple_2)
def main [
  1:bool <- lesser-than 34, 35, 35
]
+mem: storing 0 in location 1

:(before "End Primitive Recipe Declarations")
GREATER_OR_EQUAL,
:(before "End Primitive Recipe Numbers")
put(Recipe_ordinal, "greater-or-equal", GREATER_OR_EQUAL);
:(before "End Primitive Recipe Checks")
case GREATER_OR_EQUAL: {
  if (SIZE(inst.ingredients) <= 1) {
    raise << maybe(get(Recipe, r).name) << "'greater-or-equal' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
    if (!is_mu_number(inst.ingredients.at(i))) {
      raise << maybe(get(Recipe, r).name) << "'greater-or-equal' can only compare numbers; got '" << inst.ingredients.at(i).original_string << "'\n" << end();
      goto finish_checking_instruction;
    }
  }
  if (SIZE(inst.products) > 1) {
    raise << maybe(get(Recipe, r).name) << "'greater-or-equal' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
    raise << maybe(get(Recipe, r).name) << "'greater-or-equal' should yield a boolean, but got '" << inst.products.at(0).original_string << "'\n" << end();
    break;
  }
  break;
}
:(before "End Primitive Recipe Implementations")
case GREATER_OR_EQUAL: {
  bool result = true;
  for (int i = /**/1;  i < SIZE(ingredients);  ++i) {
    if (ingredients.at(i-1).at(0) < ingredients.at(i).at(0)) {
      result = false;
    }
  }
  products.resize(1);
  products.at(0).push_back(result);
  break;
}

:(scenario greater_or_equal)
def main [
  1:num <- copy 34
  2:num <- copy 33
  3:bool <- greater-or-equal 1:num, 2:num
]
+mem: storing 1 in location 3

:(scenario greater_or_equal_2)
def main [
  1:num <- copy 34
  2:num <- copy 34
  3:bool <- greater-or-equal 1:num, 2:num
]
+mem: storing 1 in location 3

:(scenario greater_or_equal_3)
def main [
  1:num <- copy 34
  2:num <- copy 35
  3:bool <- greater-or-equal 1:num, 2:num
]
+mem: storing 0 in location 3

:(scenario greater_or_equal_multiple)
def main [
  1:bool <- greater-or-equal 36, 35, 35
]
+mem: storing 1 in location 1

:(scenario greater_or_equal_multiple_2)
def main [
  1:bool <- greater-or-equal 36, 35, 36
]
+mem: storing 0 in location 1

:(before "End Primitive Recipe Declarations")
LESSER_OR_EQUAL,
:(before "End Primitive Recipe Numbers")
put(Recipe_ordinal, "lesser-or-equal", LESSER_OR_EQUAL);
:(before "End Primitive Recipe Checks")
case LESSER_OR_EQUAL: {
  if (SIZE(inst.ingredients) <= 1) {
    raise << maybe(get(Recipe, r).name) << "'lesser-or-equal' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
    if (!is_mu_number(inst.ingredients.at(i))) {
      raise << maybe(get(Recipe, r).name) << "'lesser-or-equal' can only compare numbers; got '" << inst.ingredients.at(i).original_string << "'\n" << end();
      goto finish_checking_instruction;
    }
  }
  if (SIZE(inst.products) > 1) {
    raise << maybe(get(Recipe, r).name) << "'greater-or-equal' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
    raise << maybe(get(Recipe, r).name) << "'greater-or-equal' should yield a boolean, but got '" << inst.products.at(0).original_string << "'\n" << end();
    break;
  }
  break;
}
:(before "End Primitive Recipe Implementations")
case LESSER_OR_EQUAL: {
  bool result = true;
  for (int i = /**/1;  i < SIZE(ingredients);  ++i) {
    if (ingredients.at(i-1).at(0) > ingredients.at(i).at(0)) {
      result = false;
    }
  }
  products.resize(1);
  products.at(0).push_back(result);
  break;
}

:(scenario lesser_or_equal)
def main [
  1:num <- copy 32
  2:num <- copy 33
  3:bool <- lesser-or-equal 1:num, 2:num
]
+mem: storing 1 in location 3

:(scenario lesser_or_equal_2)
def main [
  1:num <- copy 33
  2:num <- copy 33
  3:bool <- lesser-or-equal 1:num, 2:num
]
+mem: storing 1 in location 3

:(scenario lesser_or_equal_3)
def main [
  1:num <- copy 34
  2:num <- copy 33
  3:bool <- lesser-or-equal 1:num, 2:num
]
+mem: storing 0 in location 3

:(scenario lesser_or_equal_multiple)
def main [
  1:bool <- lesser-or-equal 34, 35, 35
]
+mem: storing 1 in location 1

:(scenario lesser_or_equal_multiple_2)
def main [
  1:bool <- lesser-or-equal 34, 35, 34
]
+mem: storing 0 in location 1

:(before "End Primitive Recipe Declarations")
MAX,
:(before "End Primitive Recipe Numbers")
put(Recipe_ordinal, "max", MAX);
:(before "End Primitive Recipe Checks")
case MAX: {
  if (SIZE(inst.ingredients) <= 1) {
    raise << maybe(get(Recipe, r).name) << "'max' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
    if (!is_mu_number(inst.ingredients.at(i))) {
      raise << maybe(get(Recipe, r).name) << "'max' can only compare numbers; got '" << inst.ingredients.at(i).original_string << "'\n" << end();
      goto finish_checking_instruction;
    }
  }
  if (SIZE(inst.products) > 1) {
    raise << maybe(get(Recipe, r).name) << "'max' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
    raise << maybe(get(Recipe, r).name) << "'max' should yield a number, but got '" << inst.products.at(0).original_string << "'\n" << end();
    break;
  }
  break;
}
:(before "End Primitive Recipe Implementations")
case MAX: {
  int result = ingredients.at(0).at(0);
  for (int i = /**/1;  i < SIZE(ingredients);  ++i) {
    if (ingredients.at(i).at(0) > result) {
      result = ingredients.at(i).at(0);
    }
  }
  products.resize(1);
  products.at(0).push_back(result);
  break;
}

:(before "End Primitive Recipe Declarations")
MIN,
:(before "End Primitive Recipe Numbers")
put(Recipe_ordinal, "min", MIN);
:(before "End Primitive Recipe Checks")
case MIN: {
  if (SIZE(inst.ingredients) <= 1) {
    raise << maybe(get(Recipe, r).name) << "'min' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
    if (!is_mu_number(inst.ingredients.at(i))) {
      raise << maybe(get(Recipe, r).name) << "'min' can only compare numbers; got '" << inst.ingredients.at(i).original_string << "'\n" << end();
      goto finish_checking_instruction;
    }
  }
  if (SIZE(inst.products) > 1) {
    raise << maybe(get(Recipe, r).name) << "'min' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
    break;
  }
  if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
    raise << maybe(get(Recipe, r).name) << "'min' should yield a number, but got '" << inst.products.at(0).original_string << "'\n" << end();
    break;
  }
  break;
}
:(before "End Primitive Recipe Implementations")
case MIN: {
  int result = ingredients.at(0).at(0);
  for (int i = /**/1;  i < SIZE(ingredients);  ++i) {
    if (ingredients.at(i).at(0) < result) {
      result = ingredients.at(i).at(0);
    }
  }
  products.resize(1);
  products.at(0).push_back(result);
  break;
}