https://github.com/akkartik/mu/blob/master/027call_ingredient.cc
  1 //: Calls can take ingredients just like primitives. To access a recipe's
  2 //: ingredients, use 'next-ingredient'.
  3 
  4 :(scenario next_ingredient)
  5 def main [
  6   f 2
  7 ]
  8 def f [
  9   12:num <- next-ingredient
 10   13:num <- add 1, 12:num
 11 ]
 12 +mem: storing 3 in location 13
 13 
 14 :(scenario next_ingredient_missing)
 15 def main [
 16   f
 17 ]
 18 def f [
 19   _, 12:num <- next-ingredient
 20 ]
 21 +mem: storing 0 in location 12
 22 
 23 :(before "End call Fields")
 24 vector<vector<double> > ingredient_atoms;
 25 vector<reagent> ingredients;
 26 int next_ingredient_to_process;
 27 :(before "End call Constructor")
 28 next_ingredient_to_process = <
discard """
  output: '''Version 2 was called.
This has the highest precedence.
This has the second-highest precedence.
This has the lowest precedence.'''
"""

# bug #2220
when true:
  type A[T] = object
  type B = A[int]

  proc q[X](x: X) =
    echo "Version 1 was called."

  proc q(x: B) =
    echo "Version 2 was called."

  q(B()) # This call reported as ambiguous.

# bug #2219
template testPred(a: expr) =
  block:
    type A = object of RootObj
    type B = object of A
    type SomeA = A|A # A hack to make "A" a typeclass.

    when a >= 3:
      proc p[X](x: X) =
        echo "This has the highest precedence."
    when a >= 2:
      proc p[X: A](x: X) =
        echo "This has the second-highest precedence."
    when a >= 1:
      proc p[X: SomeA](x: X) =
        echo "This has the lowest precedence."

    p(B())

testPred(3)
testPred(2)
testPred(1)
zeros to match its type 81 products.at(0).resize(size_of(current_instruction().products.at(0))); 82 products.at(1).push_back(0); 83 } 84 break; 85 } 86 87 :(scenario next_ingredient_fail_on_missing) 88 % Hide_errors = true; 89 def main [ 90 f 91 ] 92 def f [ 93 11:num <- next-ingredient 94 ] 95 +error: f: no ingredient to save in '11:num' 96 97 :(scenario rewind_ingredients) 98 def main [ 99 f 2 100 ] 101 def f [ 102 12:num <- next-ingredient # consume ingredient 103 _, 1:bool <- next-ingredient # will not find any ingredients 104 rewind-ingredients 105 13:num, 2:bool <- next-ingredient # will find ingredient again 106 ] 107 +mem: storing 2 in location 12 108 +mem: storing 0 in location 1 109 +mem: storing 2 in location 13 110 +mem: storing 1 in location 2 111 112 :(before "End Primitive Recipe Declarations") 113 REWIND_INGREDIENTS, 114 :(before "End Primitive Recipe Numbers") 115 put(Recipe_ordinal, "rewind-ingredients", REWIND_INGREDIENTS); 116 put(Recipe_ordinal, "rewind-inputs", REWIND_INGREDIENTS); 117 :(before "End Primitive Recipe Checks") 118 case REWIND_INGREDIENTS: { 119 break; 120 } 121 :(before "End Primitive Recipe Implementations") 122 case REWIND_INGREDIENTS: { 123 current_call().next_ingredient_to_process = 0; 124 break; 125 } 126 127 //: another primitive: 'ingredient' for random access 128 129 :(scenario ingredient) 130 def main [ 131 f 1, 2 132 ] 133 def f [ 134 12:num <- ingredient 1 # consume second ingredient first 135 13:num, 1:bool <- next-ingredient # next-ingredient tries to scan past that 136 ] 137 +mem: storing 2 in location 12 138 +mem: storing 0 in location 1 139 140 :(before "End Primitive Recipe Declarations") 141 INGREDIENT, 142 :(before "End Primitive Recipe Numbers") 143 put(Recipe_ordinal, "ingredient", INGREDIENT); 144 put(Recipe_ordinal, "input", INGREDIENT); 145 :(before "End Primitive Recipe Checks") 146 case INGREDIENT: { 147 if (SIZE(inst.ingredients) != 1) { 148 raise << maybe(get(Recipe, r).name) << "'ingredient' expects exactly one ingredient, but got '" << to_original_string(inst) << "'\n" << end(); 149 break; 150 } 151 if (!is_literal(inst.ingredients.at(0)) && !is_mu_number(inst.ingredients.at(0))) { 152 raise << maybe(get(Recipe, r).name) << "'ingredient' expects a literal ingredient, but got '" << inst.ingredients.at(0).original_string << "'\n" << end(); 153 break; 154 } 155 break; 156 } 157 :(before "End Primitive Recipe Implementations") 158 case INGREDIENT: { 159 if (static_cast<int>(ingredients.at(0).at(0)) < SIZE(current_call().ingredient_atoms)) { 160 current_call().next_ingredient_to_process = ingredients.at(0).at(0); 161 products.push_back( 162 current_call().ingredient_atoms.at(current_call().next_ingredient_to_process)); 163 assert(SIZE(products) == 1); products.resize(2); // push a new vector 164 products.at(1).push_back(1); 165 ++current_call().next_ingredient_to_process; 166 } 167 else { 168 if (SIZE(current_instruction().products) > 1) { 169 products.resize(2); 170 products.at(0).push_back(0); // todo: will fail noisily if we try to read a compound value 171 products.at(1).push_back(0); 172 } 173 } 174 break; 175 } 176 177 //: a particularly common array type is the text, or address:array:character 178 :(code) 179 bool is_mu_text(reagent/*copy*/ x) { 180 // End Preprocess is_mu_text(reagent x) 181 return x.type 182 && !x.type->atom 183 && x.type->left->atom 184 && x.type->left->value == Address_type_ordinal 185 && x.type->right 186 && !x.type->right->atom 187 && x.type->right->left->atom 188 && x.type->right->left->value == Array_type_ordinal 189 && x.type->right->right 190 && !x.type->right->right->atom 191 && x.type->right->right->left->value == Character_type_ordinal 192 && x.type->right->right->right == NULL; 193 }