summary refs log blame commit diff stats
path: root/doc/uml/128002
blob: 0149fe5fbf8bba6b7db2df838423fe3cb8a81efb (plain) (tree)
8db3c4b1 ^
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: #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 */
//: A big convenience high-level languages provide is the ability to name memory
//: locations. In mu, a transform called 'convert-names' provides this
//: convenience.

:(scenario convert_names)
recipe main [
  x:integer <- copy 0:literal
]
+name: assign x 1
+run: instruction main/0
+mem: storing 0 in location 1

:(scenario convert_names_warns)
% Hide_warnings = true;
recipe main [
  x:integer <- copy y:integer
]
+warn: use before set: y in main

:(after "int main")
  Transform.push_back(transform_names);

:(before "End Globals")
map<recipe_number, map<string, index_t> > Name;
:(after "Clear Other State For recently_added_recipes")
for (index_t i = 0; i < recently_added_recipes.size(); ++i) {
  Name.erase(recently_added_recipes[i]);
}

:(code)
void transform_names(const recipe_number r) {
  map<string, index_t>& names = Name[r];
  // store the indices 'used' so far in the map
  index_t& curr_idx = names[""];
  ++curr_idx;  // avoid using index 0, benign skip in some other cases
//?   cout << "Recipe " << r << ": " << Recipe[r].name << '\n'; //? 3
//?   cout << Recipe[r].steps.size() << '\n'; //? 2
  for (index_t i = 0; i < Recipe[r].steps.size(); ++i) {
//?     cout << "instruction " << i << '\n'; //? 2
    instruction& inst = Recipe[r].steps[i];
    // Per-recipe Transforms
    // map names to addresses
    for (index_t in = 0; in < inst.ingredients.size(); ++in) {
//?       cout << "ingredients\n"; //? 2
      if (is_raw(inst.ingredients[in])) continue;
//?       cout << "ingredient " << inst.ingredients[in].name << '\n'; //? 3
//?       cout << "ingredient " << inst.ingredients[in].to_string() << '\n'; //? 1
      if (inst.ingredients[in].name == "default-space")
        inst.ingredients[in].initialized = true;
      if (inst.ingredients[in].types.empty())
        raise << "missing type in " << inst.to_string() << '\n';
      assert(!inst.ingredients[in].types.empty());
      if (inst.ingredients[in].types[0]  // not a literal
          && !inst.ingredients[in].initialized
          && !is_number(inst.ingredients[in].name)) {
        if (!already_transformed(inst.ingredients[in], names)) {
          raise << "use before set: " << inst.ingredients[in].name << " in " << Recipe[r].name << '\n';
        }
        inst.ingredients[in].set_value(lookup_name(inst.ingredients[in], r));
//?         cout << "lookup ingredient " << Recipe[r].name << "/" << i << ": " << inst.ingredients[in].to_string() << '\n'; //? 1
      }
    }
    for (index_t out = 0; out < inst.products.size(); ++out) {
//?       cout << "products\n"; //? 1
      if (is_raw(inst.products[out])) continue;
//?       cout << "product " << out << '/' << inst.products.size() << " " << inst.products[out].name << '\n'; //? 4
//?       cout << inst.products[out].types[0] << '\n'; //? 1
      if (inst.products[out].name == "default-space")
        inst.products[out].initialized = true;
      if (inst.products[out].types[0]  // not a literal
          && !inst.products[out].initialized
          && !is_number(inst.products[out].name)) {
        if (names.find(inst.products[out].name) == names.end()) {
          trace("name") << "assign " << inst.products[out].name << " " << curr_idx;
          names[inst.products[out].name] = curr_idx;
          curr_idx += size_of(inst.products[out]);
        }
        inst.products[out].set_value(lookup_name(inst.products[out], r));
//?         cout << "lookup product " << Recipe[r].name << "/" << i << ": " << inst.products[out].to_string() << '\n'; //? 1
      }
    }
  }
}

bool already_transformed(const reagent& r, const map<string, index_t>& names) {
  return names.find(r.name) != names.end();
}

index_t lookup_name(const reagent& r, const recipe_number default_recipe) {
  return Name[default_recipe][r.name];
}

type_number skip_addresses(const vector<type_number>& types) {
  for (index_t i = 0; i < types.size(); ++i) {
    if (types[i] != Type_number["address"]) return types[i];
  }
  raise << "expected a container" << '\n' << die();
  return -1;
}

int find_element_name(const type_number t, const string& name) {
  const type_info& container = Type[t];
//?   cout << "looking for element " << name << " in type " << container.name << " with " << container.element_names.size() << " elements\n"; //? 1
  for (index_t i = 0; i < container.element_names.size(); ++i) {
    if (container.element_names[i] == name) return i;
  }
  raise << "unknown element " << name << " in container " << t << '\n' << die();
  return -1;
}

bool is_raw(const reagent& r) {
  for (index_t i = /*skip value+type*/1; i < r.properties.size(); ++i) {
    if (r.properties[i].first == "raw") return true;
  }
  return false;
}

:(scenario convert_names_passes_dummy)
# _ is just a dummy result that never gets consumed
recipe main [
  _, x:integer <- copy 0:literal
]
+name: assign x 1
-name: assign _ 1

//: one reserved word that we'll need later
:(scenario convert_names_passes_default_space)
recipe main [
  default-space:integer, x:integer <- copy 0:literal
]
+name: assign x 1
-name: assign default-space 1

//: an escape hatch to suppress name conversion that we'll use later
:(scenario convert_names_passes_raw)
recipe main [
  x:integer/raw <- copy 0:literal
]
-name: assign x 1

//:: Support element names for containers in 'get' and 'get-address'.

//: update our running example container for the next test
:(before "End Mu Types Initialization")
Type[point].element_names.push_back("x");
Type[point].element_names.push_back("y");
:(scenario convert_names_transforms_container_elements)
recipe main [
  a:integer <- get 0:point, y:offset
  b:integer <- get 0:point, x:offset
]
+name: element y of type point is at offset 1
+name: element x of type point is at offset 0

:(after "Per-recipe Transforms")
// replace element names of containers with offsets
if (inst.operation == Recipe_number["get"]
    || inst.operation == Recipe_number["get-address"]) {
  // at least 2 args, and second arg is offset
  assert(inst.ingredients.size() >= 2);
//?   cout << inst.ingredients[1].to_string() << '\n'; //? 1
  assert(isa_literal(inst.ingredients[1]));
  if (inst.ingredients[1].name.find_first_not_of("0123456789") == string::npos) continue;
  // since first non-address in base type must be a container, we don't have to canonize
  type_number base_type = skip_addresses(inst.ingredients[0].types);
  inst.ingredients[1].set_value(find_element_name(base_type, inst.ingredients[1].name));
  trace("name") << "element " << inst.ingredients[1].name << " of type " << Type[base_type].name << " is at offset " << inst.ingredients[1].value;
}

//: this test is actually illegal so can't call run
:(scenarios transform)
:(scenario convert_names_handles_containers)
recipe main [
  a:point <- copy 0:literal
  b:integer <- copy 0:literal
]
+name: assign a 1
+name: assign b 3

//:: Support variant names for exclusive containers in 'maybe-convert'.

:(scenarios run)
:(scenario maybe_convert_named)
recipe main [
  12:integer <- copy 1:literal
  13:integer <- copy 35:literal
  14:integer <- copy 36:literal
  20:address:point <- maybe-convert 12:integer-or-point, p:variant
]
+name: variant p of type integer-or-point has tag 1
+mem: storing 13 in location 20

:(after "Per-recipe Transforms")
// convert variant names of exclusive containers
if (inst.operation == Recipe_number["maybe-convert"]) {
  // at least 2 args, and second arg is offset
  assert(inst.ingredients.size() >= 2);
  assert(isa_literal(inst.ingredients[1]));
  if (inst.ingredients[1].name.find_first_not_of("0123456789") == string::npos) continue;
  // since first non-address in base type must be an exclusive container, we don't have to canonize
  type_number base_type = skip_addresses(inst.ingredients[0].types);
  inst.ingredients[1].set_value(find_element_name(base_type, inst.ingredients[1].name));
  trace("name") << "variant " << inst.ingredients[1].name << " of type " << Type[base_type].name << " has tag " << inst.ingredients[1].value;
}