about summary refs log blame commit diff stats
path: root/cpp/025name
blob: f226d8e682cf9a4f7c800a148be0bd4ce04d15dc (plain) (tree)
1
2
                                                                                
                                                                      















                                                               

                     









                                                       














                                                                                                                                                 

                                                                           
                                                      
                                          








                                                                                                       
                                      
                                                             
                                                                                                                   
                                                            

                                                       
                                        











                                                                                         
 

















                                                                                                                                         






                                                   







                                                    











                                                       
//: A big convenience high-level languages provide is the ability to name memory
//: locations. In mu, a transform called 'convert-names' provides this
//: convenience.

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

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

:(before "End Globals")
unordered_map<recipe_number, unordered_map<string, int> > Name;
:(before "End Setup")
Name.clear();

:(code)
void transform_names(const recipe_number r) {
  unordered_map<string, int>& names = Name[r];
  int curr_idx = 1;
//?   cout << "Recipe " << r << '\n'; //? 2
//?   cout << Recipe[r].steps.size(); //? 1
  for (size_t i = 0; i < Recipe[r].steps.size(); ++i) {
//?     cout << "instruction " << i << '\n'; //? 2
    instruction& inst = Recipe[r].steps[i];
    // 1: replace element names of records 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);
      assert(!inst.ingredients[1].types.empty());
      assert(inst.ingredients[1].types[0] == 0);
      if (inst.ingredients[1].name.find_first_not_of("0123456789") == string::npos) continue;
      // since first non-address in base type must be a record, we don't have to canonize
      type_number record = skip_addresses(inst.ingredients[0].types);
      inst.ingredients[1].value = find_element_name(record, inst.ingredients[1].name);
      inst.ingredients[1].initialized = true;
      trace("name") << "field " << inst.ingredients[1].name << " of type " << Type[record].name << " is at offset " << inst.ingredients[1].value;
    }
    // 2: map names to addresses
    for (size_t in = 0; in < inst.ingredients.size(); ++in) {
//?       cout << "ingredient " << inst.ingredients[in].name << '\n'; //? 1
      if (inst.ingredients[in].name != "default_space"
          && inst.ingredients[in].types[0]
          && inst.ingredients[in].name.find_first_not_of("0123456789-.") != string::npos) {
        if (names.find(inst.ingredients[in].name) == names.end()) {
          // todo: test
          cerr << "user before set: " << inst.ingredients[in].name << " in " << Recipe[r].name << '\n';
        }
        inst.ingredients[in].value = names[inst.ingredients[in].name];
        inst.ingredients[in].initialized = true;
      }
    }
    // 3: replace names with addresses
    for (size_t out = 0; out < inst.products.size(); ++out) {
//?       cout << "product " << out << '/' << inst.products.size() << " " << inst.products[out].name << '\n'; //? 3
//?       cout << inst.products[out].types[0] << '\n'; //? 1
      if (inst.products[out].name != "_"
          && inst.products[out].name != "default_space"
          && inst.products[out].types[0]
          && inst.products[out].name.find_first_not_of("0123456789-.") != string::npos) {
        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;
        }
        inst.products[out].value = names[inst.products[out].name];
        inst.products[out].initialized = true;
      }
    }
  }
}

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

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

:(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

//: update our running example record 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_record_elements")
recipe main [
  a:integer <- get 0:point, y:offset
  b:integer <- get 0:point, x:offset
]
+name: field y of type point is at offset 1
+name: field x of type point is at offset 0