about summary refs log tree commit diff stats
path: root/cpp/012run
blob: 1a95f408b4788bcd07db0b8d446caa8dd5caa1bf (plain) (blame)
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
:(scenarios run)
:(scenario copy_literal)
recipe main [
  1:integer <- copy 23:literal
]
+run: instruction main/0
+run: ingredient 0 is 23
+mem: storing in location 1

:(scenario copy)
recipe main [
  1:integer <- copy 23:literal
  2:integer <- copy 1:integer
]
+run: instruction main/1
+run: ingredient 0 is 1
+mem: location 1 is 23
+mem: storing in location 2

:(before "End Types")
// Each recipe can be 'called' many many times in a program. Each call needs a
// little extra information.
struct call {
  recipe_number running_recipe;
  size_t pc;
  vector<vector<int> > incoming_atoms;
  size_t next_ingredient_to_process;
  vector<vector<int> > outgoing_atoms;
  call(recipe_number r) :running_recipe(r), pc(0), next_ingredient_to_process(0) {}
};
typedef stack<call> call_stack;

struct routine {
  size_t alloc;
  size_t alloc_max;
  call_stack calls;
  size_t limit;
  size_t running_since;
  // todo: sleep conditions
};

:(code)
void run(string form) {
  recipe_number r = add_recipes(form);
  routine rr;
  rr.calls.push(call(r));
  run(rr);
}

void run(routine rr) {
// #defines save us the trouble of updating aliases when dependent variables
// change.
#define TOP_RECIPE Recipe[rr.calls.top().running_recipe]
#define instructions TOP_RECIPE.steps
  while (!rr.calls.empty()) {
    while (rr.calls.top().pc >= instructions.size()) {
      rr.calls.pop();
      if (rr.calls.empty()) return;
      // todo: no results returned warning
      ++rr.calls.top().pc;
    }
    size_t& pc = rr.calls.top().pc;
//?     cout << "instruction " << TOP_RECIPE.name << '/' << pc << '\n'; //? 2
    trace("run") << "instruction " << TOP_RECIPE.name << '/' << pc;
    switch (instructions[pc].operation) {
    // Primitive Recipe Implementations.
    case COPY: {
      trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name;
      vector<int> data = read_memory(instructions[pc].ingredients[0]);
      write_memory(instructions[pc].products[0], data);
      break;
    }
    // End Primitive Recipe Implementations.
    default: {
      // unknown op = try to call a defined recipe
      // TODO: this should be later, in the same layer as next_ingredient
//?       cout << "non primitive op: " << instructions[pc].operation << '\n'; //? 1
      if (Recipe.find(instructions[pc].operation) == Recipe.end()) {
        raise << "undefined operation " << instructions[pc].operation << '\n';
        break;
      }
//?       cout << "calling " << instructions[pc].operation << '\n'; //? 2
      call callee(instructions[pc].operation);
      for (vector<reagent>::iterator p = instructions[pc].ingredients.begin(); p != instructions[pc].ingredients.end(); ++p) {
//?         cout << "push back: " << p->to_string() << '\n'; //? 1
        callee.incoming_atoms.push_back(read_memory(*p));
      }
      rr.calls.push(callee);
      continue;  // not done with caller; don't increment pc
    }}
    ++pc;
  }
#undef TOP_RECIPE
#undef instructions
}

vector<int> read_memory(reagent x) {
//?   cout << "read_memory: " << x.to_string() << '\n'; //? 1
  vector<int> result;
  if (x.types[0] == 0) {  // literal
    result.push_back(to_int(x.name));
    return result;
  }
  int base = to_int(x.name);
  for (size_t offset = 0; offset < Type[x.types[0]].size; ++offset) {
    int val = Memory[base+offset];
    trace("mem") << "location " << base+offset << " is " << val;
    result.push_back(val);
  }
  return result;
}

void write_memory(reagent x, vector<int> data) {
  int base = to_int(x.name);
  size_t size = size_of(x);
  if (size != data.size()) raise << "size mismatch in storing to " << x.to_string();
  for (size_t offset = 0; offset < size; ++offset) {
    trace("mem") << "storing in location " << base+offset;
    Memory[base+offset] = data[offset];
  }
}

:(code)
int to_int(string n) {
  char* end = NULL;
  int result = strtol(n.c_str(), &end, /*any base*/0);
  assert(*end == '\0');
  return result;
}

size_t size_of(reagent r) {
  type_info t = Type[r.types[0]];
  if (!t.is_record && !t.is_array) return t.size;
  return t.size;  // TODO
}