about summary refs log tree commit diff stats
Commit message (Collapse)AuthorAgeFilesLines
* 6039Kartik Agaram2020-02-212-0/+22
|
* 6038Kartik Agaram2020-02-201-8112/+8313
|
* 6037 - first passing test for pointer lookupKartik Agaram2020-02-202-67/+192
|
* 6036Kartik Agaram2020-02-202-5/+6
|
* 6035Kartik Agaram2020-02-202-18/+18
|
* 6034Kartik Agaram2020-02-202-20/+20
|
* 6033 - save pointer lookup state while parsingKartik Agaram2020-02-202-30/+37
|
* 6032 - make room for '*' pointer lookups in stmtsKartik Agaram2020-02-202-31/+89
|
* 6031 - bugfix in selecting codegen patternKartik Agaram2020-02-202-6/+23
|
* 6030Kartik Agaram2020-02-202-11/+9
|
* 6029Kartik Agaram2020-02-202-4/+4
|
* 6028Kartik Agaram2020-02-201-4/+4
|
* 6027Kartik Agaram2020-02-201-1/+0
| | | | | | Changing `switchbuf` globally is too heavyweight a change just to do the right thing when hitting `:T`. I don't even use it anymore since I got `<Leader>t`; why was I hitting `:T` just to navigate to `last_run`, again?
* 6026Kartik Agaram2020-02-182-20/+20
|
* 6025Kartik Agaram2020-02-182-6715/+7029
|
* 6024 - finally, commandline parsing in MuKartik Agaram2020-02-181-4/+22
|
* 6023 - bug: vars with both stack-offset and regKartik Agaram2020-02-182-10/+20
| | | | | This was initially disquieting; was I writing enough tests? Then I noticed I had TODOs for some missing checks.
* 6022 - initial sketch of array lengthKartik Agaram2020-02-182-0/+75
| | | | | This is a particularly large abstraction leak: SubX arrays track their lengths in bytes, and therefore Mu as well.
* 6022Kartik Agaram2020-02-182-1/+4
| | | | Forgot to actually use the new type-dispatch in commit 6017.
* 6021Kartik Agaram2020-02-182-0/+22
|
* 6020Kartik Agaram2020-02-182-55/+47
| | | | Some deduplication, though this may be a premature abstraction.
* 6019 - finish supporting all branch primitivesKartik Agaram2020-02-184-10/+238
| | | | | | | | I'd been thinking I didn't need unconditional `break` instructions, but I just realized that non-local unconditional breaks have a use. Stop over-thinking this, just support everything. The code is quite duplicated.
* 6018Kartik Agaram2020-02-171-3935/+3975
|
* 6017 - simplify type-dispatch for primitivesKartik Agaram2020-02-172-26/+66
| | | | | | | | | | | | We'll be doing type-checking in a separate phase in future. For now we need only to distinguish between literals and non-literals for x86 primitive instructions. I was tempted to support x86 set__ instructions for this change: https://c9x.me/x86/html/file_module_x86_id_288.html That will happen at some point. And I'll simplify a bunch of branches for results of predicate functions when it happens.
* 6016Kartik Agaram2020-02-172-10/+10
|
* 6015Kartik Agaram2020-02-1727-236/+317
|
* 6014Kartik Agaram2020-02-1711-75/+75
|
* 6013Kartik Agaram2020-02-161-2/+2
|
* 6012Kartik Agaram2020-02-161-6330/+6264
|
* 6011Kartik Agaram2020-02-162-5/+3
|
* 6010 - starting to flesh out run-testsKartik Agaram2020-02-161-1/+1
|
* 6009 - significantly cleaner lexingKartik Agaram2020-02-163-135/+34
| | | | | | | | | This cleans up a bunch of little warts that had historically accumulated because of my bull-headedness in not designing a grammar up front. Let's see if the lack of a grammar comes up again. We now require that there be no space in variable declarations between the name and the colon separating it from its type.
* 6008Kartik Agaram2020-02-163-19/+20
| | | | | | | | Allow comments at the end of all kinds of statements. To do this I replaced all calls to next-word with next-mu-token.. except one. I'm not seeing any bugs yet, any places where comments break things. But this exception makes me nervous.
* 6007Kartik Agaram2020-02-141-2/+2
|
* 6006Kartik Agaram2020-02-142-4/+4
|
* 6005Kartik Agaram2020-02-143-4/+47
| | | | | | | | Support calling SubX code from Mu. I have _zero_ idea how to make this safe. Now we can start writing tests. We can't use commandline args yet. That requires support for kernel strings.
* 6004Kartik Agaram2020-02-141-0/+11
|
* 6003Kartik Agaram2020-02-092-7/+18
|
* 6002Kartik Agaram2020-02-091-3/+4
|
* 6001Kartik Agaram2020-02-0918-7154/+7393
|
* 6000 - clean up after no-local branchesKartik Agaram2020-02-0916-12/+215
|
* 5999Kartik Agaram2020-02-0911-1/+1
| | | | | Fix CI. apps/survey was running out of space in the trace segment when translating apps/mu.subx
* 5998 - redo code-generation for 'break'Kartik Agaram2020-02-092-77/+130
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | I've been saying that we can convert this: { var x: int break-if-= ... } ..into this: { 68/push 0/imm32 { 0f 84/jump-if-= break/disp32 ... } 81 0/subop/add %esp 4/imm32 } All subsequent instructions go into a nested block, so that they can be easily skipped without skipping the stack cleanup. However, I've been growing aware that this is a special case. Most of the time we can't use this trick: for loops for non-local breaks for non-local loops In most cases we need to figure out all the intervening variables on the stack and emit code to clean them up. And now it turns out even for local breaks like above, the trick doesn't work. Consider what happens when there's a loop later in the block: { var x: int break-if-= ... } If we emitted a nested block for the break, the local loop would become non-local. So we replace one kind of state with another. Easiest course of action is to just emit the exact same cleanup code for all conditional branches.
* 5997 - clean up after unconditional loopsKartik Agaram2020-02-092-34/+122
| | | | | | | Turns out we can't handle them like conditional loops. This function to emit cleanup code for jumps is getting quite terrible. I don't yet know what subsidiary abstractions it needs.
* 5996Kartik Agaram2020-02-091-0/+12
|
* 5995Kartik Agaram2020-02-081-7408/+7804
|
* 5994Kartik Agaram2020-02-081-3/+3
|
* 5993 - support for unlabeled loop instructionsKartik Agaram2020-02-082-3/+213
| | | | | Now that we have the infrastructure for emitting cleanup blocks, the labeled variants should be easy as well.
* 5992Kartik Agaram2020-02-072-12/+43
|
* 5991Kartik Agaram2020-02-072-1/+4
|
296'>^
9fdda88b ^
5f98a10c ^
8eff7919 ^
f6d47435 ^
f64f1ca5 ^










2a81a547 ^
f64f1ca5 ^

2a81a547 ^




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
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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246

                                                                      



































                                                       
 




                                                                             
                                
                         
                    


                                                        
                       
                               

                           


                          
  
                              



                             
                       
                            
                         
                                           

       
                                    


                                                                                                                   
                            
                            
 


                                 

                                       













                                                                                                   
 












































                                                                                







                                                                                                                                        

                                                                  
                                            
                                                                                                                  

        
                                                                        
          

                                                                                                       


                                                                                                        


                                                                                    


                                             
                                           
   


                                                                                                                

                          
 






















                                                             
 
                                                                        
 

                                              
                       
 
 

                                                                
                         
                                                         

 
                                  

                                                                           
                                                                
                                  


                                                                                                                                                               
                                     
                                                                        
                              
                                       
                         
 










                                                          
                               

        




                                                                                                                                   
//: So far the recipes we define can't run each other. Let's fix that.

void test_calling_recipe() {
  run(
      "def main [\n"
      "  f\n"
      "]\n"
      "def f [\n"
      "  3:num <- add 2, 2\n"
      "]\n"
  );
  CHECK_TRACE_CONTENTS(
      "mem: storing 4 in location 3\n"
  );
}

void test_return_on_fallthrough() {
  run(
      "def main [\n"
      "  f\n"
      "  1:num <- copy 0\n"
      "  2:num <- copy 0\n"
      "  3:num <- copy 0\n"
      "]\n"
      "def f [\n"
      "  4:num <- copy 0\n"
      "  5:num <- copy 0\n"
      "]\n"
  );
  CHECK_TRACE_CONTENTS(
      "run: f\n"
      "run: {4: \"number\"} <- copy {0: \"literal\"}\n"
      "run: {5: \"number\"} <- copy {0: \"literal\"}\n"
      "run: {1: \"number\"} <- copy {0: \"literal\"}\n"
      "run: {2: \"number\"} <- copy {0: \"literal\"}\n"
      "run: {3: \"number\"} <- copy {0: \"literal\"}\n"
  );
}

:(before "struct routine {")
// Everytime a recipe runs another, we interrupt it and start running the new
// recipe. When that finishes, we continue this one where we left off.
// This requires maintaining a 'stack' of interrupted recipes or 'calls'.
struct call {
  recipe_ordinal running_recipe;
  int running_step_index;
  // End call Fields
  call(recipe_ordinal r) { clear(r, 0); }
  call(recipe_ordinal r, int index) { clear(r, index); }
  void clear(recipe_ordinal r, int index) {
    running_recipe = r;
    running_step_index = index;
    // End call Constructor
  }
  ~call() {
    // End call Destructor
  }
};
typedef list<call> call_stack;

:(replace{} "struct routine")
struct routine {
  call_stack calls;
  // End routine Fields
  routine(recipe_ordinal r);
  bool completed() const;
  const vector<instruction>& steps() const;
};
:(code)
routine::routine(recipe_ordinal r) {
  ++Callstack_depth;
  trace(Callstack_depth+1, "trace") << "new routine; incrementing callstack depth to " << Callstack_depth << end();
  assert(Callstack_depth < Max_depth);
  calls.push_front(call(r));
  // End routine Constructor
}

//:: now update routine's helpers

//: macro versions for a slight speedup

:(delete{} "int& current_step_index()")
:(delete{} "recipe_ordinal currently_running_recipe()")
:(delete{} "const string& current_recipe_name()")
:(delete{} "const recipe& current_recipe()")
:(delete{} "const instruction& current_instruction()")

:(before "End Includes")
#define current_call() Current_routine->calls.front()
#define current_step_index() current_call().running_step_index
#define currently_running_recipe() current_call().running_recipe
#define current_recipe() get(Recipe, currently_running_recipe())
#define current_recipe_name() current_recipe().name
#define to_instruction(call) get(Recipe, (call).running_recipe).steps.at((call).running_step_index)
#define current_instruction() to_instruction(current_call())

//: function versions for debugging

:(code)
//? :(before "End Globals")
//? bool Foo2 = false;
//? :(code)
//? call& current_call() {
//?   if (Foo2) cerr << __FUNCTION__ << '\n';
//?   return Current_routine->calls.front();
//? }
//? :(replace{} "int& current_step_index()")
//? int& current_step_index() {
//?   assert(!Current_routine->calls.empty());
//?   if (Foo2) cerr << __FUNCTION__ << '\n';
//?   return current_call().running_step_index;
//? }
//? :(replace{} "recipe_ordinal currently_running_recipe()")
//? recipe_ordinal currently_running_recipe() {
//?   assert(!Current_routine->calls.empty());
//?   if (Foo2) cerr << __FUNCTION__ << '\n';
//?   return current_call().running_recipe;
//? }
//? :(replace{} "const string& current_recipe_name()")
//? const string& current_recipe_name() {
//?   assert(!Current_routine->calls.empty());
//?   if (Foo2) cerr << __FUNCTION__ << '\n';
//?   return get(Recipe, current_call().running_recipe).name;
//? }
//? :(replace{} "const recipe& current_recipe()")
//? const recipe& current_recipe() {
//?   assert(!Current_routine->calls.empty());
//?   if (Foo2) cerr << __FUNCTION__ << '\n';
//?   return get(Recipe, current_call().running_recipe);
//? }
//? :(replace{} "const instruction& current_instruction()")
//? const instruction& current_instruction() {
//?   assert(!Current_routine->calls.empty());
//?   if (Foo2) cerr << __FUNCTION__ << '\n';
//?   return to_instruction(current_call());
//? }
//? :(code)
//? const instruction& to_instruction(const call& call) {
//?   return get(Recipe, call.running_recipe).steps.at(call.running_step_index);
//? }

:(code)
void dump_callstack() {
  if (!Current_routine) return;
  if (Current_routine->calls.size() <= 1) return;
  for (call_stack::const_iterator p = ++Current_routine->calls.begin();  p != Current_routine->calls.end();  ++p)
    raise << "  called from " << get(Recipe, p->running_recipe).name << ": " << to_original_string(to_instruction(*p)) << '\n' << end();
}

:(after "Defined Recipe Checks")
// not a primitive; check that it's present in the book of recipes
if (!contains_key(Recipe, inst.operation)) {
  raise << maybe(get(Recipe, r).name) << "undefined operation in '" << to_original_string(inst) << "'\n" << end();
  break;
}
:(replace{} "default:" following "End Primitive Recipe Implementations")
default: {
  if (contains_key(Recipe, current_instruction().operation)) {  // error already raised in Checks above
    // not a primitive; look up the book of recipes
    ++Callstack_depth;
    trace(Callstack_depth+1, "trace") << "incrementing callstack depth to " << Callstack_depth << end();
    assert(Callstack_depth < Max_depth);
    const call& caller_frame = current_call();
    Current_routine->calls.push_front(call(to_instruction(caller_frame).operation));
    finish_call_housekeeping(to_instruction(caller_frame), ingredients);
    // not done with caller
    write_products = false;
    fall_through_to_next_instruction = false;
    // End Non-primitive Call(caller_frame)
  }
}
:(code)
void finish_call_housekeeping(const instruction& call_instruction, const vector<vector<double> >& ingredients) {
  // End Call Housekeeping
}

void test_calling_undefined_recipe_fails() {
  Hide_errors = true;
  run(
      "def main [\n"
      "  foo\n"
      "]\n"
  );
  CHECK_TRACE_CONTENTS(
      "error: main: undefined operation in 'foo'\n"
  );
}

void test_calling_undefined_recipe_handles_missing_result() {
  Hide_errors = true;
  run(
      "def main [\n"
      "  x:num <- foo\n"
      "]\n"
  );
  CHECK_TRACE_CONTENTS(
      "error: main: undefined operation in 'x:num <- foo'\n"
  );
}

//:: finally, we need to fix the termination conditions for the run loop

:(replace{} "bool routine::completed() const")
bool routine::completed() const {
  return calls.empty();
}

:(replace{} "const vector<instruction>& routine::steps() const")
const vector<instruction>& routine::steps() const {
  assert(!calls.empty());
  return get(Recipe, calls.front().running_recipe).steps;
}

:(after "Running One Instruction")
// when we reach the end of one call, we may reach the end of the one below
// it, and the one below that, and so on
while (current_step_index() >= SIZE(Current_routine->steps())) {
  // Falling Through End Of Recipe
  trace(Callstack_depth+1, "trace") << "fall-through: exiting " << current_recipe_name() << "; decrementing callstack depth from " << Callstack_depth << end();
  --Callstack_depth;
  assert(Callstack_depth >= 0);
  Current_routine->calls.pop_front();
  if (Current_routine->calls.empty()) goto stop_running_current_routine;
  // Complete Call Fallthrough
  // todo: fail if no products returned
  ++current_step_index();
}

:(before "End Primitive Recipe Declarations")
_DUMP_CALL_STACK,
:(before "End Primitive Recipe Numbers")
put(Recipe_ordinal, "$dump-call-stack", _DUMP_CALL_STACK);
:(before "End Primitive Recipe Checks")
case _DUMP_CALL_STACK: {
  break;
}
:(before "End Primitive Recipe Implementations")
case _DUMP_CALL_STACK: {
  dump(Current_routine->calls);
  break;
}
:(code)
void dump(const call_stack& calls) {
  for (call_stack::const_reverse_iterator p = calls.rbegin(); p != calls.rend(); ++p)
    cerr << get(Recipe, p->running_recipe).name << ":" << p->running_step_index << " -- " << to_string(to_instruction(*p)) << '\n';
}