about summary refs log tree commit diff stats
path: root/039location_array.cc
Commit message (Expand)AuthorAgeFilesLines
* 3309Kartik K. Agaram2016-09-091-8/+14
* 3239Kartik K. Agaram2016-08-211-1/+1
* 3120Kartik K. Agaram2016-07-211-1/+1
* 2990Kartik K. Agaram2016-05-201-1/+1
* 2931 - be explicit about making copiesKartik K. Agaram2016-05-061-1/+1
* 2894Kartik K. Agaram2016-05-031-0/+40
href='#n79'>79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
:(after "Types")
// A program is a book of 'recipes' (functions)
typedef int recipe_number;
:(before "End Globals")
unordered_map<string, recipe_number> Recipe_number;
unordered_map<recipe_number, recipe> Recipe;
int Next_recipe_number = 1;

:(before "End Types")
// Recipes are lists of instructions. To run a recipe, the computer runs its
// instructions.
struct recipe {
  vector<instruction> steps;
};

:(before "struct recipe")
// Each instruction is either of the form:
//   product1, product2, product3, ... <- operation ingredient1, ingredient2, ingredient3, ...
// or just a single 'label' followed by a colon
//   label:
// Labels don't do anything, they're just waypoints.
struct instruction {
  bool is_label;
  string label;  // only if is_label
  recipe_number operation;  // only if !is_label
  vector<reagent> ingredients;  // only if !is_label
  vector<reagent> products;  // only if !is_label
  instruction();
  void clear();
};

:(before "struct instruction")
// Ingredients and products are a single species -- a reagent. Reagents refer
// either to numbers or to locations in memory along with 'type' tags telling
// us how to interpret them. They also can contain arbitrary other lists of
// properties besides types, but we're getting ahead of ourselves.
struct reagent {
  string name;
  vector<type_number> types;
  vector<pair<string, property> > properties;
  reagent(string s);
  string to_string();
};

:(before "struct reagent")
struct property {
  vector<string> values;
};

:(before "End Globals")
// Locations refer to a common 'memory'. Each location can store a number.
unordered_map<int, int> Memory;
:(before "End Setup")
  Memory.clear();

:(after "Types")
// Types encode how the numbers stored in different parts of memory are
// interpreted. A location tagged as a 'character' type will interpret the
// number 97 as the letter 'a', while a different location of type 'integer'
// would not.
//
// Unlike most computers today, mu stores types in a single big table, shared
// by all the mu programs on the computer. This is useful in providing a
// seamless experience to help understand arbitrary mu programs.
typedef int type_number;
:(before "End Globals")
unordered_map<string, type_number> Type_number;
unordered_map<type_number, type_info> Type;
int Next_type_number = 1;
:(code)
void setup_types() {
  Type.clear();  Type_number.clear();
  Type_number["literal"] = 0;
  Next_type_number = 1;
  // Mu Types.
  int integer = Type_number["integer"] = Next_type_number++;
  Type[integer].size = 1;
  int address = Type_number["address"] = Next_type_number++;
  Type[address].size = 1;
  int boolean = Type_number["boolean"] = Next_type_number++;
  Type[boolean].size = 1;
  // End Mu Types.
}
:(before "End Setup")
  setup_types();

:(before "End Types")
// You can construct arbitrary new types. Types are either 'records', containing
// 'fields' of other types, 'array's of a single type repeated over and over,
// or 'addresses' pointing at a location elsewhere in memory.
//
// For example:
//  storing bank balance next to a person's name might require a record, and
//  high scores in a game might need an array of numbers.
// You'll see examples using addresses later.
struct type_info {
  size_t size;
  bool is_address;
  bool is_record;
  bool is_array;
  vector<type_number> target;  // only if is_address
  vector<vector<type_number> > elements;  // only if is_record or is_array
  type_info() :size(0), is_address(false), is_record(false), is_array(false) {}
};

:(before "End Globals")
const int IDLE = 0;  // always the first entry in the recipe book
const int COPY = 1;
:(code)
// It's all very well to construct recipes out of other recipes, but we need
// to know how to do *something* out of the box. For the following
// recipes there are only codes, no entries in the book, because mu just knows
// what to do for them.
void setup_recipes() {
  Recipe.clear();  Recipe_number.clear();
  Recipe_number["idle"] = IDLE;
  Next_recipe_number = 1;
  // Primitive Recipe Numbers.
  Recipe_number["copy"] = COPY;
  Next_recipe_number++;
  // End Primitive Recipe Numbers.
}
:(before "End Setup")
  setup_recipes();



:(code)
// Helpers
  instruction::instruction() :is_label(false), operation(IDLE) {}
  void instruction::clear() { is_label=false; label.clear(); operation=IDLE; ingredients.clear(); products.clear(); }

  // Reagents have the form <name>:<type>:<type>:.../<property>/<property>/...
  reagent::reagent(string s) {
//?     cout << s << '\n'; //? 1
    istringstream in(s);
    name = slurp_until(in, ':');
    istringstream ts(slurp_until(in, '/'));
    string t;
    while (!(t = slurp_until(ts, ':')).empty()) {
      types.push_back(Type_number[t]);
    }
//?     cout << types.size() << '\n'; //? 1
    // todo: properties
  }
  string reagent::to_string() {
    ostringstream out;
    out << "{name: \"" << name << "\", type: ";
    for (size_t i = 0; i < types.size(); ++i) {
      out << types[i];
      if (i < types.size()-1) out << "-";
    }
    out << "}";  // todo: properties
    return out.str();
  }

string slurp_until(istream& in, char delim) {
  ostringstream out;
  char c;
  while (in >> c) {
    if (c == delim) {
      break;
    }
    out << c;
  }
  return out.str();
}