1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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
|
// 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;
// Mu Types.
int integer = Type_number["integer"] = 1;
Type[integer].size = 1;
Next_type_number++;
// 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.
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) {}
};
:(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) {
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")
|