diff options
Diffstat (limited to 'cpp/010vm')
-rw-r--r-- | cpp/010vm | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/cpp/010vm b/cpp/010vm new file mode 100644 index 00000000..3b8a7c96 --- /dev/null +++ b/cpp/010vm @@ -0,0 +1,145 @@ +// A program is a book of 'recipes' (functions) + +:(after "Types") +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; + int integer = Type_number["integer"] = Next_type_number++; + Type[integer].size = 1; +} +:(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. +struct type_info { + int 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) {} +}; + +:(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"] = 0; + Next_recipe_number = 1; + Recipe_number["copy"] = Next_recipe_number++; +} +:(before "End Types") +const int idle = 0; // always the first entry in the recipe book +:(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) { + istringstream in(s); + name = slurp_until(in, ':'); + types.push_back(Type_number[slurp_until(in, '/')]); // todo: multiple types + } + string reagent::to_string() { + ostringstream out; + out << "{name: \"" << name << "\", type: " << types[0] << "}"; // 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(); +} + + + +:(before "End Setup") |