about summary refs log tree commit diff stats
path: root/.gitignore
diff options
context:
space:
mode:
authortoonn <toonn@toonn.io>2021-12-13 22:09:05 +0100
committertoonn <toonn@toonn.io>2021-12-13 22:09:05 +0100
commit7cbdd92a66e5f0d08672b4b9fc36492a7dc1eed6 (patch)
tree253667f6f0e4874b5c3cecf2031d76fdb0e8d873 /.gitignore
parent0b77fb8aba2da25ea452c14f6876fde6b50b3838 (diff)
parent9da2b4c79323a3f34da8d54198364d549a29ff00 (diff)
downloadranger-7cbdd92a66e5f0d08672b4b9fc36492a7dc1eed6.tar.gz
Merge remote-tracking branch 'shervinsahba/master'
Diffstat (limited to '.gitignore')
0 files changed, 0 insertions, 0 deletions
'#n104'>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 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
:(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 {
  string name;
  vector<instruction> steps;
  // End Recipe Fields
};

:(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
  string name;  // only if !is_label
  recipe_number operation;  // Recipe_number[name]
  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 {
  vector<pair<string, vector<string> > > properties;
  string name;
  int value;
  bool initialized;
  vector<type_number> types;
  reagent(string s);
  reagent();
  void set_value(int v) { value = v; initialized = true; }
  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")
// Mu 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 Initialization.
  int integer = Type_number["integer"] = Next_type_number++;
  Type_number["location"] = Type_number["integer"];  // wildcard type
  Type[integer].name = "integer";
  int address = Type_number["address"] = Next_type_number++;
  Type[address].name = "address";
  int boolean = Type_number["boolean"] = Next_type_number++;
  Type[boolean].name = "boolean";
  int array = Type_number["array"] = Next_type_number++;
  Type[array].name = "array";
  // End Mu Types Initialization.
}
:(before "End Setup")
  setup_types();

:(before "End Types")
// You can construct arbitrary new types. Types are either 'records', containing
// 'fields' of other types, or 'array's of a single type repeated over and over.
//
// 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.
struct type_info {
  string name;
  bool is_record;
  size_t size;  // only if is_record; primitives and addresses have size 1 while arrays are dynamic
  vector<vector<type_number> > elements;  // only if is_record
  vector<string> element_names;  // only if is_record
  // End type_info Fields.
  type_info() :is_record(false), size(0) {}
};

:(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();
  Next_recipe_number = 0;
  Recipe_number["idle"] = IDLE;
  assert(Next_recipe_number == IDLE);
  Next_recipe_number++;
  // Primitive Recipe Numbers.
  Recipe_number["copy"] = COPY;
  assert(Next_recipe_number == COPY);
  Next_recipe_number++;
  // End Primitive Recipe Numbers.
  assert(Next_recipe_number < 100);
  Next_recipe_number = 100;
}
:(before "End Setup")
  setup_recipes();



//: Helpers

:(code)
// indent members to avoid generating prototypes for them
  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) :value(0), initialized(false) {
    istringstream in(s);
    in >> std::noskipws;
    // properties
    while (!in.eof()) {
      istringstream row(slurp_until(in, '/'));
      row >> std::noskipws;
      string name = slurp_until(row, ':');
      vector<string> values;
      while (!row.eof())
        values.push_back(slurp_until(row, ':'));
      properties.push_back(pair<string, vector<string> >(name, values));
    }
    // structures for the first row of properties
    name = properties[0].first;
    for (size_t i = 0; i < properties[0].second.size(); ++i) {
      types.push_back(Type_number[properties[0].second[i]]);
    }
    if (name == "_" && types.empty()) {
      types.push_back(0);
      properties[0].second.push_back("dummy");
    }
    else if (types.empty()) {  // hacky test for string
      types.push_back(0);
      properties[0].second.push_back("literal-string");
    }
  }
  reagent::reagent() :value(0), initialized(false) {}
  string reagent::to_string() {
    ostringstream out;
    out << "{name: \"" << name << "\", value: " << value << ", type: ";
    for (size_t i = 0; i < types.size(); ++i) {
      out << types[i];
      if (i < types.size()-1) out << "-";
    }
    if (!properties.empty()) {
      out << ", properties: [";
      for (size_t i = 0; i < properties.size(); ++i) {
        out << "\"" << properties[i].first << "\": ";
        for (size_t j = 0; j < properties[i].second.size(); ++j) {
          out << "\"" << properties[i].second[j] << "\"";
          if (j < properties[i].second.size()-1) out << ":";
        }
        if (i < properties.size()-1) out << ", ";
        else out << "]";
      }
    }
    out << "}";
    return out.str();
  }

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

void dump_memory() {
  map<int, int> ordered(Memory.begin(), Memory.end());
  for (map<int, int>::iterator p = ordered.begin(); p != ordered.end(); ++p) {
    cout << p->first << ": " << p->second << '\n';
  }
}
:(before "End Includes")
#include <map>
using std::map;