1 
2 #include <stdlib.h> /* for exit */
3 #include <string.h> /* for strlen */
4 #include <stdio.h> /* for fprintf etc */
5 #include "header.h"
6 
7 /* prototypes */
8 
9 static void generate(struct generator * g, struct node * p);
10 static void w(struct generator * g, const char * s);
11 static void writef(struct generator * g, const char * s, struct node * p);
12 
new_label(struct generator * g)13 static int new_label(struct generator * g) {
14     return g->next_label++;
15 }
16 
vars_newname(struct generator * g)17 static struct str * vars_newname(struct generator * g) {
18 
19     struct str * output;
20     g->var_number++;
21     output = str_new();
22     str_append_string(output, "v_");
23     str_append_int(output, g->var_number);
24     return output;
25 }
26 
27 
28 /* Write routines for items from the syntax tree */
29 
write_varname(struct generator * g,struct name * p)30 static void write_varname(struct generator * g, struct name * p) {
31 
32     switch (p->type) {
33         case t_external:
34             break;
35         default: {
36             int ch = "SbirxG"[p->type];
37             write_char(g, ch);
38             write_char(g, '_');
39             break;
40         }
41     }
42     write_b(g, p->b);
43 }
44 
write_varref(struct generator * g,struct name * p)45 static void write_varref(struct generator * g, struct name * p) {
46     write_string(g, "context.");
47     write_varname(g, p);
48 }
49 
write_hexdigit(struct generator * g,int n)50 static void write_hexdigit(struct generator * g, int n) {
51 
52     write_char(g, n < 10 ? n + '0' : n - 10 + 'A');
53 }
54 
write_hex(struct generator * g,int ch)55 static void write_hex(struct generator * g, int ch) {
56 
57     write_string(g, "\\u{");
58     {
59         int i;
60         for (i = 12; i >= 0; i -= 4) write_hexdigit(g, ch >> i & 0xf);
61     }
62     write_string(g, "}");
63 }
64 
write_literal_string(struct generator * g,symbol * p)65 static void write_literal_string(struct generator * g, symbol * p) {
66 
67     int i = 0;
68     write_string(g, "\"");
69     while (i < SIZE(p)) {
70         int ch;
71         i += get_utf8(p + i, &ch);
72         if (32 <= ch && ch < 127) {
73             if (ch == '\"' || ch == '\\') write_string(g, "\\");
74             write_char(g, ch);
75         } else {
76             write_hex(g, ch);
77         }
78     }
79     write_string(g, "\"");
80 }
81 
write_margin(struct generator * g)82 static void write_margin(struct generator * g) {
83 
84     int i;
85     for (i = 0; i < g->margin; i++) write_string(g, "    ");
86 }
87 
write_comment(struct generator * g,struct node * p)88 static void write_comment(struct generator * g, struct node * p) {
89     if (!g->options->comments) return;
90     write_margin(g);
91     write_string(g, "// ");
92     write_comment_content(g, p);
93     write_newline(g);
94 }
95 
write_block_start(struct generator * g)96 static void write_block_start(struct generator * g) {
97 
98     w(g, "~+{~N");
99 }
100 
write_block_end(struct generator * g)101 static void write_block_end(struct generator * g)    /* block end */ {
102 
103     w(g, "~-~M}~N");
104 }
105 
write_savecursor(struct generator * g,struct node * p,struct str * savevar)106 static void write_savecursor(struct generator * g, struct node * p,
107                              struct str * savevar) {
108 
109     g->B[0] = str_data(savevar);
110     g->S[1] = "";
111     if (p->mode != m_forward) g->S[1] = "env.limit - ";
112     writef(g, "~Mlet ~B0 = ~S1env.cursor;~N", p);
113 }
114 
restore_string(struct node * p,struct str * out,struct str * savevar)115 static void restore_string(struct node * p, struct str * out, struct str * savevar) {
116 
117     str_clear(out);
118     str_append_string(out, "env.cursor = ");
119     if (p->mode != m_forward) str_append_string(out, "env.limit - ");
120     str_append(out, savevar);
121     str_append_string(out, ";");
122 }
123 
write_restorecursor(struct generator * g,struct node * p,struct str * savevar)124 static void write_restorecursor(struct generator * g, struct node * p,
125                                 struct str * savevar) {
126 
127     struct str * temp = str_new();
128     write_margin(g);
129     restore_string(p, temp, savevar);
130     write_str(g, temp);
131     write_newline(g);
132     str_delete(temp);
133 }
134 
write_inc_cursor(struct generator * g,struct node * p)135 static void write_inc_cursor(struct generator * g, struct node * p) {
136 
137     write_margin(g);
138     write_string(g, p->mode == m_forward ? "env.next_char();" : "env.previous_char();");
139     write_newline(g);
140 }
141 
wsetlab_begin(struct generator * g,int n)142 static void wsetlab_begin(struct generator * g, int n) {
143 
144     g->I[0] = n;
145     w(g, "~M'lab~I0: loop {~N~+");
146 }
147 
wsetlab_end(struct generator * g,int n)148 static void wsetlab_end(struct generator * g, int n) {
149     if (!g->unreachable) {
150         g->I[0] = n;
151         w(g, "~Mbreak 'lab~I0;~N");
152     }
153     w(g, "~-~M}~N");
154 }
155 
wgotol(struct generator * g,int n)156 static void wgotol(struct generator * g, int n) {
157     g->I[0] = n;
158     w(g, "~Mbreak 'lab~I0;~N");
159 }
160 
write_failure(struct generator * g)161 static void write_failure(struct generator * g) {
162 
163     if (str_len(g->failure_str) != 0) {
164         write_margin(g);
165         write_str(g, g->failure_str);
166         write_newline(g);
167     }
168     switch (g->failure_label) {
169         case x_return:
170             w(g, "~Mreturn false;~N");
171             g->unreachable = true;
172             break;
173         default:
174             g->I[0] = g->failure_label;
175             w(g, "~Mbreak 'lab~I0;~N");
176             g->unreachable = true;
177     }
178 }
179 
write_failure_if(struct generator * g,char * s,struct node * p)180 static void write_failure_if(struct generator * g, char * s, struct node * p) {
181 
182     writef(g, "~Mif ", p);
183     writef(g, s, p);
184     writef(g, " ", p);
185     write_block_start(g);
186     write_failure(g);
187     write_block_end(g);
188     g->unreachable = false;
189 }
190 
191 /* if at limit fail */
write_check_limit(struct generator * g,struct node * p)192 static void write_check_limit(struct generator * g, struct node * p) {
193 
194     if (p->mode == m_forward) {
195         write_failure_if(g, "env.cursor >= env.limit", p);
196     } else {
197         write_failure_if(g, "env.cursor <= env.limit_backward", p);
198     }
199 }
200 
201 /* Formatted write. */
writef(struct generator * g,const char * input,struct node * p)202 static void writef(struct generator * g, const char * input, struct node * p) {
203     int i = 0;
204     int l = strlen(input);
205 
206     while (i < l) {
207         int ch = input[i++];
208         if (ch != '~') {
209             write_char(g, ch);
210             continue;
211         }
212         switch (input[i++]) {
213             default: write_char(g, input[i - 1]); continue;
214             case 'C': write_comment(g, p); continue;
215             case 'f': write_block_start(g);
216                       write_failure(g);
217                       g->unreachable = false;
218                       write_block_end(g);
219                       continue;
220             case 'M': write_margin(g); continue;
221             case 'N': write_newline(g); continue;
222             case '{': write_block_start(g); continue;
223             case '}': write_block_end(g); continue;
224             case 'S': write_string(g, g->S[input[i++] - '0']); continue;
225             case 'B': write_b(g, g->B[input[i++] - '0']); continue;
226             case 'I': write_int(g, g->I[input[i++] - '0']); continue;
227             case 'V': write_varref(g, g->V[input[i++] - '0']); continue;
228             case 'W': write_varname(g, g->V[input[i++] - '0']); continue;
229             case 'L': write_literal_string(g, g->L[input[i++] - '0']); continue;
230             case '+': g->margin++; continue;
231             case '-': g->margin--; continue;
232             case 'n': write_string(g, g->options->name); continue;
233         }
234     }
235 }
236 
w(struct generator * g,const char * s)237 static void w(struct generator * g, const char * s) {
238     writef(g, s, 0);
239 }
240 
generate_AE(struct generator * g,struct node * p)241 static void generate_AE(struct generator * g, struct node * p) {
242     const char * s;
243     switch (p->type) {
244         case c_name:
245             write_varref(g, p->name); break;
246         case c_number:
247             write_int(g, p->number); break;
248         case c_maxint:
249             write_string(g, "i32::MAX"); break;
250         case c_minint:
251             write_string(g, "i32::MIN"); break;
252         case c_neg:
253             write_char(g, '-'); generate_AE(g, p->right); break;
254         case c_multiply:
255             s = " * "; goto label0;
256         case c_plus:
257             s = " + "; goto label0;
258         case c_minus:
259             s = " - "; goto label0;
260         case c_divide:
261             s = " / ";
262         label0:
263             write_char(g, '('); generate_AE(g, p->left);
264             write_string(g, s); generate_AE(g, p->right); write_char(g, ')'); break;
265         case c_cursor:
266             w(g, "env.cursor"); break;
267         case c_limit:
268             w(g, p->mode == m_forward ? "env.limit" : "env.limit_backward"); break;
269         case c_lenof:
270             g->V[0] = p->name;
271             w(g, "(~V0.chars().count() as i32)");
272             break;
273         case c_sizeof:
274             g->V[0] = p->name;
275             w(g, "(~V0.len() as i32)");
276             break;
277         case c_len:
278             w(g, "(env.current.chars().count() as i32)");
279             break;
280         case c_size:
281             w(g, "(env.current.len() as i32)");
282             break;
283     }
284 }
285 
generate_bra(struct generator * g,struct node * p)286 static void generate_bra(struct generator * g, struct node * p) {
287 
288     write_comment(g, p);
289     p = p->left;
290     while (p) {
291         generate(g, p);
292         p = p->right;
293     }
294 }
295 
generate_and(struct generator * g,struct node * p)296 static void generate_and(struct generator * g, struct node * p) {
297 
298     struct str * savevar = vars_newname(g);
299     int keep_c = K_needed(g, p->left);
300 
301     write_comment(g, p);
302 
303     if (keep_c) write_savecursor(g, p, savevar);
304 
305     p = p->left;
306     while (p) {
307         generate(g, p);
308         if (g->unreachable) break;
309         if (keep_c && p->right != 0) write_restorecursor(g, p, savevar);
310         p = p->right;
311     }
312     str_delete(savevar);
313 }
314 
generate_or(struct generator * g,struct node * p)315 static void generate_or(struct generator * g, struct node * p) {
316 
317     struct str * savevar = vars_newname(g);
318     int keep_c = K_needed(g, p->left);
319 
320     int a0 = g->failure_label;
321     struct str * a1 = str_copy(g->failure_str);
322 
323     int out_lab = new_label(g);
324     int end_unreachable = true;
325 
326     write_comment(g, p);
327     wsetlab_begin(g, out_lab);
328 
329     if (keep_c) write_savecursor(g, p, savevar);
330 
331     p = p->left;
332     str_clear(g->failure_str);
333 
334     if (p == 0) {
335         /* p should never be 0 after an or: there should be at least two
336          * sub nodes. */
337         fprintf(stderr, "Error: \"or\" node without children nodes.");
338         exit(1);
339     }
340     while (p->right != 0) {
341         int label = new_label(g);
342         g->failure_label = label;
343         wsetlab_begin(g, label);
344         generate(g, p);
345         if (!g->unreachable) {
346             wgotol(g, out_lab);
347             end_unreachable = false;
348         }
349         w(g, "~-~M}~N");
350         g->unreachable = false;
351         if (keep_c) write_restorecursor(g, p, savevar);
352         p = p->right;
353     }
354 
355     g->failure_label = a0;
356     str_delete(g->failure_str);
357     g->failure_str = a1;
358 
359     generate(g, p);
360     wsetlab_end(g, out_lab);
361     if (!end_unreachable) {
362         g->unreachable = false;
363     }
364     str_delete(savevar);
365 }
366 
generate_backwards(struct generator * g,struct node * p)367 static void generate_backwards(struct generator * g, struct node * p) {
368 
369     write_comment(g, p);
370     writef(g,"~Menv.limit_backward = env.cursor;~N"
371              "~Menv.cursor = env.limit;~N", p);
372     generate(g, p->left);
373     w(g, "~Menv.cursor = env.limit_backward;~N");
374 }
375 
376 
generate_not(struct generator * g,struct node * p)377 static void generate_not(struct generator * g, struct node * p) {
378 
379     struct str * savevar = vars_newname(g);
380     int keep_c = K_needed(g, p->left);
381 
382     int a0 = g->failure_label;
383     struct str * a1 = str_copy(g->failure_str);
384     int label = new_label(g);
385     g->failure_label = label;
386 
387     write_comment(g, p);
388     if (keep_c) {
389         write_savecursor(g, p, savevar);
390     }
391 
392     str_clear(g->failure_str);
393 
394     wsetlab_begin(g, label);
395 
396     generate(g, p->left);
397 
398     g->failure_label = a0;
399     str_delete(g->failure_str);
400     g->failure_str = a1;
401 
402     if (!g->unreachable) write_failure(g);
403     w(g, "~-~M}~N");
404 
405     g->unreachable = false;
406 
407     if (keep_c) write_restorecursor(g, p, savevar);
408     str_delete(savevar);
409 }
410 
411 
generate_try(struct generator * g,struct node * p)412 static void generate_try(struct generator * g, struct node * p) {
413 
414     struct str * savevar = vars_newname(g);
415     int keep_c = K_needed(g, p->left);
416     int label = new_label(g);
417     g->failure_label = label;
418     str_clear(g->failure_str);
419 
420     write_comment(g, p);
421     if (keep_c) {
422         write_savecursor(g, p, savevar);
423         restore_string(p, g->failure_str, savevar);
424     }
425     wsetlab_begin(g, label);
426     generate(g, p->left);
427     wsetlab_end(g, label);
428     g->unreachable = false;
429 
430     str_delete(savevar);
431 }
432 
generate_set(struct generator * g,struct node * p)433 static void generate_set(struct generator * g, struct node * p) {
434 
435     write_comment(g, p);
436     g->V[0] = p->name;
437     writef(g, "~M~V0 = true;~N", p);
438 }
439 
generate_unset(struct generator * g,struct node * p)440 static void generate_unset(struct generator * g, struct node * p) {
441 
442     write_comment(g, p);
443     g->V[0] = p->name;
444     writef(g, "~M~V0 = false;~N", p);
445 }
446 
generate_fail(struct generator * g,struct node * p)447 static void generate_fail(struct generator * g, struct node * p) {
448 
449     write_comment(g, p);
450     generate(g, p->left);
451     if (!g->unreachable) write_failure(g);
452 }
453 
454 /* generate_test() also implements 'reverse' */
455 
generate_test(struct generator * g,struct node * p)456 static void generate_test(struct generator * g, struct node * p) {
457 
458     struct str * savevar = vars_newname(g);
459     int keep_c = K_needed(g, p->left);
460 
461     write_comment(g, p);
462 
463     if (keep_c) {
464         write_savecursor(g, p, savevar);
465     }
466 
467     generate(g, p->left);
468 
469     if (!g->unreachable) {
470         if (keep_c) {
471             write_restorecursor(g, p, savevar);
472         }
473     }
474     str_delete(savevar);
475 }
476 
generate_do(struct generator * g,struct node * p)477 static void generate_do(struct generator * g, struct node * p) {
478 
479     struct str * savevar = vars_newname(g);
480     int keep_c = K_needed(g, p->left);
481     write_comment(g, p);
482     if (keep_c) write_savecursor(g, p, savevar);
483 
484     if (p->left->type == c_call) {
485         /* Optimise do <call> */
486         write_comment(g, p->left);
487         g->V[0] = p->left->name;
488         w(g, "~M~W0(env, context);~N");
489     } else {
490         int label = new_label(g);
491         g->failure_label = label;
492         str_clear(g->failure_str);
493 
494         wsetlab_begin(g, label);
495         generate(g, p->left);
496         wsetlab_end(g, label);
497         g->unreachable = false;
498     }
499 
500     if (keep_c) write_restorecursor(g, p, savevar);
501     str_delete(savevar);
502 }
503 
generate_GO(struct generator * g,struct node * p,int style)504 static void generate_GO(struct generator * g, struct node * p, int style) {
505 
506     int end_unreachable = false;
507     struct str * savevar = vars_newname(g);
508     int keep_c = style == 1 || repeat_restore(g, p->left);
509 
510     int a0 = g->failure_label;
511     struct str * a1 = str_copy(g->failure_str);
512 
513     int golab = new_label(g);
514     g->I[0] = golab;
515     write_comment(g, p);
516     w(g, "~M'golab~I0: loop {~N~+");
517     if (keep_c) write_savecursor(g, p, savevar);
518 
519     g->failure_label = new_label(g);
520     str_clear(g->failure_str);
521     wsetlab_begin(g, g->failure_label);
522     generate(g, p->left);
523 
524     if (g->unreachable) {
525         /* Cannot break out of this loop: therefore the code after the
526          * end of the loop is unreachable.*/
527         end_unreachable = true;
528     } else {
529         /* include for goto; omit for gopast */
530         if (style == 1) write_restorecursor(g, p, savevar);
531         g->I[0] = golab;
532         w(g, "~Mbreak 'golab~I0;~N");
533     }
534     g->unreachable = false;
535     w(g, "~-~M}~N");
536     if (keep_c) write_restorecursor(g, p, savevar);
537 
538     g->failure_label = a0;
539     str_delete(g->failure_str);
540     g->failure_str = a1;
541 
542     write_check_limit(g, p);
543     write_inc_cursor(g, p);
544     write_block_end(g);
545 
546     str_delete(savevar);
547     g->unreachable = end_unreachable;
548 }
549 
generate_loop(struct generator * g,struct node * p)550 static void generate_loop(struct generator * g, struct node * p) {
551 
552     struct str * loopvar = vars_newname(g);
553     write_comment(g, p);
554     w(g, "~Mfor _ in 0..");
555     generate_AE(g, p->AE);
556     writef(g, " {~+~N", p);
557 
558     generate(g, p->left);
559 
560     w(g, "~-~M}~N");
561     str_delete(loopvar);
562     g->unreachable = false;
563 }
564 
generate_repeat_or_atleast(struct generator * g,struct node * p,struct str * loopvar)565 static void generate_repeat_or_atleast(struct generator * g, struct node * p, struct str * loopvar) {
566 
567     struct str * savevar = vars_newname(g);
568     int keep_c = repeat_restore(g, p->left);
569     int replab = new_label(g);
570     g->I[0] = replab;
571     writef(g, "~M'replab~I0: loop{~N~+", p);
572 
573     if (keep_c) write_savecursor(g, p, savevar);
574 
575     g->failure_label = new_label(g);
576     str_clear(g->failure_str);
577     g->I[0] = g->failure_label;
578     w(g, "~M'lab~I0: for _ in 0..1 {~N~+");
579     generate(g, p->left);
580 
581     if (!g->unreachable) {
582         if (loopvar != 0) {
583             g->B[0] = str_data(loopvar);
584             w(g, "~M~B0 -= 1;~N");
585         }
586 
587         g->I[0] = replab;
588         w(g, "~Mcontinue 'replab~I0;~N");
589     }
590     w(g, "~-~M}~N");
591     g->unreachable = false;
592 
593     if (keep_c) write_restorecursor(g, p, savevar);
594 
595     g->I[0] = replab;
596     w(g, "~Mbreak 'replab~I0;~N~-~M}~N");
597     str_delete(savevar);
598 }
599 
generate_repeat(struct generator * g,struct node * p)600 static void generate_repeat(struct generator * g, struct node * p) {
601     write_comment(g, p);
602     generate_repeat_or_atleast(g, p, NULL);
603 }
604 
generate_atleast(struct generator * g,struct node * p)605 static void generate_atleast(struct generator * g, struct node * p) {
606 
607     struct str * loopvar = vars_newname(g);
608     write_comment(g, p);
609     g->B[0] = str_data(loopvar);
610     w(g, "~Mlet mut ~B0 = ");
611     generate_AE(g, p->AE);
612     w(g, ";~N");
613     {
614         int a0 = g->failure_label;
615         struct str * a1 = str_copy(g->failure_str);
616 
617         generate_repeat_or_atleast(g, p, loopvar);
618 
619         g->failure_label = a0;
620         str_delete(g->failure_str);
621         g->failure_str = a1;
622     }
623     g->B[0] = str_data(loopvar);
624     write_failure_if(g, "~B0 > 0", p);
625     str_delete(loopvar);
626 }
627 
generate_setmark(struct generator * g,struct node * p)628 static void generate_setmark(struct generator * g, struct node * p) {
629 
630     write_comment(g, p);
631     g->V[0] = p->name;
632     writef(g, "~M~V0 = env.cursor;~N", p);
633 }
634 
generate_tomark(struct generator * g,struct node * p)635 static void generate_tomark(struct generator * g, struct node * p) {
636 
637     write_comment(g, p);
638     g->S[0] = p->mode == m_forward ? ">" : "<";
639 
640     w(g, "~Mif env.cursor ~S0 "); generate_AE(g, p->AE);
641     writef(g, " ", p);
642     write_block_start(g);
643     write_failure(g);
644     write_block_end(g);
645     g->unreachable = false;
646     w(g, "~Menv.cursor = "); generate_AE(g, p->AE); writef(g, ";~N", p);
647 }
648 
generate_atmark(struct generator * g,struct node * p)649 static void generate_atmark(struct generator * g, struct node * p) {
650 
651     write_comment(g, p);
652     w(g, "~Mif env.cursor != "); generate_AE(g, p->AE);
653     writef(g, " ", p);
654     write_block_start(g);
655     write_failure(g);
656     write_block_end(g);
657     g->unreachable = false;
658 }
659 
generate_hop(struct generator * g,struct node * p)660 static void generate_hop(struct generator * g, struct node * p) {
661     write_comment(g, p);
662     // Generate the AE to a temporary block so we can substitute it in
663     // write_failure_if().
664     struct str * ae = str_new();
665     struct str * s = g->outbuf;
666     g->outbuf = ae;
667     generate_AE(g, p->AE);
668     g->outbuf = s;
669     g->B[0] = str_data(ae);
670     g->S[0] = p->mode == m_forward ? "" : "_back";
671     g->S[1] = p->AE->type == c_number ? "" : "_checked";
672     write_failure_if(g, "!env.hop~S0~S1(~B0)", p);
673     str_delete(ae);
674 }
675 
generate_delete(struct generator * g,struct node * p)676 static void generate_delete(struct generator * g, struct node * p) {
677 
678     write_comment(g, p);
679     writef(g, "~Mif !env.slice_del() {~N"
680               "~+~Mreturn false;~N~-"
681               "~M}~N", p);
682 }
683 
684 
generate_next(struct generator * g,struct node * p)685 static void generate_next(struct generator * g, struct node * p) {
686 
687     write_comment(g, p);
688     write_check_limit(g, p);
689     write_inc_cursor(g, p);
690 }
691 
generate_tolimit(struct generator * g,struct node * p)692 static void generate_tolimit(struct generator * g, struct node * p) {
693 
694     write_comment(g, p);
695     g->S[0] = p->mode == m_forward ? "env.limit" : "env.limit_backward";
696     writef(g, "~Menv.cursor = ~S0;~N", p);
697 }
698 
generate_atlimit(struct generator * g,struct node * p)699 static void generate_atlimit(struct generator * g, struct node * p) {
700 
701     write_comment(g, p);
702     g->S[0] = p->mode == m_forward ? "env.limit" : "env.limit_backward";
703     g->S[1] = p->mode == m_forward ? "<" : ">";
704     write_failure_if(g, "env.cursor ~S1 ~S0", p);
705 }
706 
generate_leftslice(struct generator * g,struct node * p)707 static void generate_leftslice(struct generator * g, struct node * p) {
708 
709     write_comment(g, p);
710     g->S[0] = p->mode == m_forward ? "env.bra" : "env.ket";
711     writef(g, "~M~S0 = env.cursor;~N", p);
712 }
713 
generate_rightslice(struct generator * g,struct node * p)714 static void generate_rightslice(struct generator * g, struct node * p) {
715 
716     write_comment(g, p);
717     g->S[0] = p->mode == m_forward ? "env.ket" : "env.bra";
718     writef(g, "~M~S0 = env.cursor;~N", p);
719 }
720 
generate_assignto(struct generator * g,struct node * p)721 static void generate_assignto(struct generator * g, struct node * p) {
722 
723     write_comment(g, p);
724     g->V[0] = p->name;
725     writef(g, "~M~V0 = env.assign_to();~N", p);
726 }
727 
generate_sliceto(struct generator * g,struct node * p)728 static void generate_sliceto(struct generator * g, struct node * p) {
729 
730     write_comment(g, p);
731     g->V[0] = p->name;
732     writef(g, "~M~V0 = env.slice_to();~N"
733               "~Mif ~V0.is_empty() {~N"
734               "~+~Mreturn false;~N~-~M}~N", p);
735 }
736 
generate_address(struct generator * g,struct node * p)737 static void generate_address(struct generator * g, struct node * p) {
738 
739     /* If we deal with a string variable which is of type String we need to
740      * pass it by reference not by value.  Literalstrings on the other hand are
741      * of type &'static str so we can pass them by value.
742      */
743     symbol * b = p->literalstring;
744     if (b != 0) {
745         write_literal_string(g, b);
746     } else {
747         write_char(g, '&');
748         write_varref(g, p->name);
749     }
750 }
751 
generate_insert(struct generator * g,struct node * p,int style)752 static void generate_insert(struct generator * g, struct node * p, int style) {
753 
754     int keep_c = style == c_attach;
755     write_comment(g, p);
756     if (p->mode == m_backward) keep_c = !keep_c;
757     if (keep_c) w(g, "~Mlet c = env.cursor;~N");
758     w(g, "~Mlet (bra, ket) = (env.cursor, env.cursor);~N");
759     writef(g, "~Menv.insert(bra, ket, ", p);
760     generate_address(g, p);
761     writef(g, ");~N", p);
762     if (keep_c) w(g, "~Menv.cursor = c;~N");
763 }
764 
generate_assignfrom(struct generator * g,struct node * p)765 static void generate_assignfrom(struct generator * g, struct node * p) {
766 
767     int keep_c = p->mode == m_forward; /* like 'attach' */
768 
769     write_comment(g, p);
770     if (keep_c) writef(g, "~Mlet c = env.cursor;~N", p);
771     /* Copying limits and cursors is necessary here because the rust
772      * borrowchecker does not like taking something from someone you are about
773      * to mutate... */
774     if (p->mode == m_forward) {
775         writef(g, "~Mlet (bra, ket) = (env.cursor, env.limit);~N", p);
776     } else {
777         writef(g, "~Mlet (bra, ket) = (env.limit_backward, env.cursor);~N", p);
778     }
779     writef(g, "~Menv.insert(bra, ket, ", p);
780     generate_address(g, p);
781     writef(g, ");~N", p);
782     if (keep_c) w(g, "~Menv.cursor = c;~N");
783 }
784 
785 
generate_slicefrom(struct generator * g,struct node * p)786 static void generate_slicefrom(struct generator * g, struct node * p) {
787 
788     write_comment(g, p);
789     w(g, "~Mif !env.slice_from(");
790     generate_address(g, p);
791     writef(g, ") {~N"
792               "~+~Mreturn false;~N~-~M}~N", p);
793 }
794 
generate_setlimit(struct generator * g,struct node * p)795 static void generate_setlimit(struct generator * g, struct node * p) {
796     struct str * savevar = vars_newname(g);
797     struct str * varname = vars_newname(g);
798     write_comment(g, p);
799     if (p->left && p->left->type == c_tomark) {
800         /* Special case for:
801          *
802          *   setlimit tomark AE for C
803          *
804          * All uses of setlimit in the current stemmers we ship follow this
805          * pattern, and by special-casing we can avoid having to save and
806          * restore c.
807          */
808         struct node * q = p->left;
809         g->S[0] = q->mode == m_forward ? ">" : "<";
810         w(g, "~Mif env.cursor ~S0 "); generate_AE(g, q->AE); w(g, " ");
811         write_block_start(g);
812         write_failure(g);
813         write_block_end(g);
814         g->unreachable = false;
815 
816         g->B[0] = str_data(varname);
817         if (p->mode == m_forward) {
818             w(g, "~Mlet ~B0 = env.limit - env.cursor;~N");
819             w(g, "~Menv.limit = ");
820         } else {
821             w(g, "~Mlet ~B0 = env.limit_backward;~N");
822             w(g, "~Menv.limit_backward = ");
823         }
824         generate_AE(g, q->AE); writef(g, ";~N", q);
825 
826         if (p->mode == m_forward) {
827             str_assign(g->failure_str, "env.limit += ");
828             str_append(g->failure_str, varname);
829             str_append_string(g->failure_str, ";");
830         } else {
831             str_assign(g->failure_str, "env.limit_backward = ");
832             str_append(g->failure_str, varname);
833             str_append_string(g->failure_str, ";");
834         }
835     } else {
836         write_savecursor(g, p, savevar);
837         generate(g, p->left);
838 
839         if (!g->unreachable) {
840             g->B[0] = str_data(varname);
841             if (p->mode == m_forward) {
842                 w(g, "~Mlet ~B0 = env.limit - env.cursor;~N");
843                 w(g, "~Menv.limit = env.cursor;~N");
844             } else {
845                 w(g, "~Mlet ~B0 = env.limit_backward;~N");
846                 w(g, "~Menv.limit_backward = env.cursor;~N");
847             }
848             write_restorecursor(g, p, savevar);
849 
850             if (p->mode == m_forward) {
851                 str_assign(g->failure_str, "env.limit += ");
852                 str_append(g->failure_str, varname);
853                 str_append_string(g->failure_str, ";");
854             } else {
855                 str_assign(g->failure_str, "env.limit_backward = ");
856                 str_append(g->failure_str, varname);
857                 str_append_string(g->failure_str, ";");
858             }
859         }
860     }
861 
862     if (!g->unreachable) {
863         generate(g, p->aux);
864 
865         if (!g->unreachable) {
866             write_margin(g);
867             write_str(g, g->failure_str);
868             write_newline(g);
869         }
870     }
871     str_delete(varname);
872     str_delete(savevar);
873 }
874 
875 /* dollar sets snowball up to operate on a string variable as if it were the
876  * current string */
generate_dollar(struct generator * g,struct node * p)877 static void generate_dollar(struct generator * g, struct node * p) {
878 
879     struct str * savevar_env = vars_newname(g);
880     write_comment(g, p);
881     g->V[0] = p->name;
882     g->B[0] = str_data(savevar_env);
883     writef(g, "~Mlet ~B0 = env.clone();~N"
884               "~Menv.set_current_s(~V0.clone());~N"
885               "~Menv.cursor = 0;~N"
886               "~Menv.limit = env.current.len() as i32;~N", p);
887     generate(g, p->left);
888     if (!g->unreachable) {
889         g->V[0] = p->name;
890         g->B[0] = str_data(savevar_env);
891         /* Update string variable. */
892         w(g, "~M~V0 = env.current.clone().into_owned();~N");
893         /* Reset env */
894         w(g, "~M*env = ~B0;~N");
895     }
896     str_delete(savevar_env);
897 }
898 
generate_integer_assign(struct generator * g,struct node * p,char * s)899 static void generate_integer_assign(struct generator * g, struct node * p, char * s) {
900 
901     g->V[0] = p->name;
902     g->S[0] = s;
903     w(g, "~M~V0 ~S0 "); generate_AE(g, p->AE); w(g, ";~N");
904 }
905 
generate_integer_test(struct generator * g,struct node * p,char * s)906 static void generate_integer_test(struct generator * g, struct node * p, char * s) {
907 
908     w(g, "~Mif !(");
909     generate_AE(g, p->left);
910     write_char(g, ' ');
911     write_string(g, s);
912     write_char(g, ' ');
913     generate_AE(g, p->AE);
914     w(g, ")");
915     write_block_start(g);
916     write_failure(g);
917     write_block_end(g);
918     g->unreachable = false;
919 }
920 
generate_call(struct generator * g,struct node * p)921 static void generate_call(struct generator * g, struct node * p) {
922 
923     write_comment(g, p);
924     g->V[0] = p->name;
925     write_failure_if(g, "!~W0(env, context)", p);
926 }
927 
generate_grouping(struct generator * g,struct node * p,int complement)928 static void generate_grouping(struct generator * g, struct node * p, int complement) {
929 
930     struct grouping * q = p->name->grouping;
931     g->S[0] = p->mode == m_forward ? "" : "_b";
932     g->S[1] = complement ? "out" : "in";
933     g->V[0] = p->name;
934     g->I[0] = q->smallest_ch;
935     g->I[1] = q->largest_ch;
936     write_failure_if(g, "!env.~S1_grouping~S0(~W0, ~I0, ~I1)", p);
937 }
938 
generate_namedstring(struct generator * g,struct node * p)939 static void generate_namedstring(struct generator * g, struct node * p) {
940 
941     write_comment(g, p);
942     g->S[0] = p->mode == m_forward ? "" : "_b";
943     g->V[0] = p->name;
944     write_failure_if(g, "!env.eq_s~S0(&~V0)", p);
945 }
946 
generate_literalstring(struct generator * g,struct node * p)947 static void generate_literalstring(struct generator * g, struct node * p) {
948     symbol * b = p->literalstring;
949     write_comment(g, p);
950     g->S[0] = p->mode == m_forward ? "" : "_b";
951     g->L[0] = b;
952     write_failure_if(g, "!env.eq_s~S0(&~L0)", p);
953 }
954 
generate_setup_context(struct generator * g)955 static void generate_setup_context(struct generator * g) {
956 
957     struct name * q;
958     w(g, "~Mlet mut context = &mut Context {~+~N");
959     for (q = g->analyser->names; q; q = q->next) {
960         g->V[0] = q;
961         switch (q->type) {
962             case t_string:
963                 w(g, "~M~W0: String::new(),~N");
964                 break;
965             case t_integer:
966                 w(g, "~M~W0: 0,~N");
967                 break;
968             case t_boolean:
969                 w(g, "~M~W0: false,~N");
970                 break;
971         }
972     }
973     w(g, "~-~M};~N");
974 }
975 
generate_define(struct generator * g,struct node * p)976 static void generate_define(struct generator * g, struct node * p) {
977     struct name * q = p->name;
978 
979     struct str * saved_output = g->outbuf;
980 
981     g->V[0] = q;
982 
983     if (q->type == t_routine) {
984         w(g, "~N~Mfn ~W0(env: &mut SnowballEnv, context: &mut Context) -> bool {~+~N");
985     } else {
986         w(g, "~N~Mpub fn ~W0(env: &mut SnowballEnv) -> bool {~+~N");
987         generate_setup_context(g);
988     }
989     if (p->amongvar_needed) w(g, "~Mlet mut among_var;~N");
990     g->outbuf = str_new();
991 
992     g->next_label = 0;
993     g->var_number = 0;
994 
995     str_clear(g->failure_str);
996     g->failure_label = x_return;
997     g->unreachable = false;
998     generate(g, p->left);
999     if (!g->unreachable) w(g, "~Mreturn true;~N");
1000     w(g, "~-~M}~N");
1001 
1002     str_append(saved_output, g->outbuf);
1003     str_delete(g->outbuf);
1004     g->outbuf = saved_output;
1005 }
1006 
generate_substring(struct generator * g,struct node * p)1007 static void generate_substring(struct generator * g, struct node * p) {
1008 
1009     struct among * x = p->among;
1010 
1011     write_comment(g, p);
1012 
1013     g->S[0] = p->mode == m_forward ? "" : "_b";
1014     g->I[0] = x->number;
1015 
1016     if (!x->amongvar_needed) {
1017         write_failure_if(g, "env.find_among~S0(~A_~I0, context) == 0", p);
1018     } else {
1019         writef(g, "~Mamong_var = env.find_among~S0(~A_~I0, context);~N", p);
1020         write_failure_if(g, "among_var == 0", p);
1021     }
1022 }
1023 
generate_among(struct generator * g,struct node * p)1024 static void generate_among(struct generator * g, struct node * p) {
1025 
1026     struct among * x = p->among;
1027 
1028     if (x->substring == 0) generate_substring(g, p);
1029 
1030     if (x->starter != 0) generate(g, x->starter);
1031 
1032     if (x->command_count == 1 && x->nocommand_count == 0) {
1033         /* Only one outcome ("no match" already handled). */
1034         generate(g, x->commands[0]);
1035     } else if (x->command_count > 0) {
1036         int i;
1037         w(g, "~M");
1038         for (i = 1; i <= x->command_count; i++) {
1039             g->I[0] = i;
1040             if (i > 1) w(g, " else ");
1041             w(g, "if among_var == ~I0 {~N~+");
1042             generate(g, x->commands[i - 1]);
1043             w(g, "~-~M}");
1044             g->unreachable = false;
1045         }
1046         w(g, "~N");
1047     }
1048 }
1049 
generate_booltest(struct generator * g,struct node * p)1050 static void generate_booltest(struct generator * g, struct node * p) {
1051 
1052     write_comment(g, p);
1053     g->V[0] = p->name;
1054     write_failure_if(g, "!~V0", p);
1055 }
1056 
generate_false(struct generator * g,struct node * p)1057 static void generate_false(struct generator * g, struct node * p) {
1058 
1059     write_comment(g, p);
1060     write_failure(g);
1061 }
1062 
generate_debug(struct generator * g,struct node * p)1063 static void generate_debug(struct generator * g, struct node * p) {
1064 
1065     write_comment(g, p);
1066     g->I[0] = g->debug_count++;
1067     g->I[1] = p->line_number;
1068     writef(g, "~Menv.debug(~I0, ~I1);~N", p);
1069 }
1070 
generate(struct generator * g,struct node * p)1071 static void generate(struct generator * g, struct node * p) {
1072 
1073     int a0;
1074     struct str * a1;
1075 
1076     if (g->unreachable) return;
1077 
1078     a0 = g->failure_label;
1079     a1 = str_copy(g->failure_str);
1080 
1081     switch (p->type) {
1082         case c_define:        generate_define(g, p); break;
1083         case c_bra:           generate_bra(g, p); break;
1084         case c_and:           generate_and(g, p); break;
1085         case c_or:            generate_or(g, p); break;
1086         case c_backwards:     generate_backwards(g, p); break;
1087         case c_not:           generate_not(g, p); break;
1088         case c_set:           generate_set(g, p); break;
1089         case c_unset:         generate_unset(g, p); break;
1090         case c_try:           generate_try(g, p); break;
1091         case c_fail:          generate_fail(g, p); break;
1092         case c_reverse:
1093         case c_test:          generate_test(g, p); break;
1094         case c_do:            generate_do(g, p); break;
1095         case c_goto:          generate_GO(g, p, 1); break;
1096         case c_gopast:        generate_GO(g, p, 0); break;
1097         case c_repeat:        generate_repeat(g, p); break;
1098         case c_loop:          generate_loop(g, p); break;
1099         case c_atleast:       generate_atleast(g, p); break;
1100         case c_setmark:       generate_setmark(g, p); break;
1101         case c_tomark:        generate_tomark(g, p); break;
1102         case c_atmark:        generate_atmark(g, p); break;
1103         case c_hop:           generate_hop(g, p); break;
1104         case c_delete:        generate_delete(g, p); break;
1105         case c_next:          generate_next(g, p); break;
1106         case c_tolimit:       generate_tolimit(g, p); break;
1107         case c_atlimit:       generate_atlimit(g, p); break;
1108         case c_leftslice:     generate_leftslice(g, p); break;
1109         case c_rightslice:    generate_rightslice(g, p); break;
1110         case c_assignto:      generate_assignto(g, p); break;
1111         case c_sliceto:       generate_sliceto(g, p); break;
1112         case c_assign:        generate_assignfrom(g, p); break;
1113         case c_insert:
1114         case c_attach:        generate_insert(g, p, p->type); break;
1115         case c_slicefrom:     generate_slicefrom(g, p); break;
1116         case c_setlimit:      generate_setlimit(g, p); break;
1117         case c_dollar:        generate_dollar(g, p); break;
1118         case c_mathassign:    generate_integer_assign(g, p, "="); break;
1119         case c_plusassign:    generate_integer_assign(g, p, "+="); break;
1120         case c_minusassign:   generate_integer_assign(g, p, "-="); break;
1121         case c_multiplyassign:generate_integer_assign(g, p, "*="); break;
1122         case c_divideassign:  generate_integer_assign(g, p, "/="); break;
1123         case c_eq:            generate_integer_test(g, p, "=="); break;
1124         case c_ne:            generate_integer_test(g, p, "!="); break;
1125         case c_gr:            generate_integer_test(g, p, ">"); break;
1126         case c_ge:            generate_integer_test(g, p, ">="); break;
1127         case c_ls:            generate_integer_test(g, p, "<"); break;
1128         case c_le:            generate_integer_test(g, p, "<="); break;
1129         case c_call:          generate_call(g, p); break;
1130         case c_grouping:      generate_grouping(g, p, false); break;
1131         case c_non:           generate_grouping(g, p, true); break;
1132         case c_name:          generate_namedstring(g, p); break;
1133         case c_literalstring: generate_literalstring(g, p); break;
1134         case c_among:         generate_among(g, p); break;
1135         case c_substring:     generate_substring(g, p); break;
1136         case c_booltest:      generate_booltest(g, p); break;
1137         case c_false:         generate_false(g, p); break;
1138         case c_true:          break;
1139         case c_debug:         generate_debug(g, p); break;
1140         default: fprintf(stderr, "%d encountered\n", p->type);
1141                  exit(1);
1142     }
1143 
1144     g->failure_label = a0;
1145     str_delete(g->failure_str);
1146     g->failure_str = a1;
1147 }
1148 
1149 /* rustc emits warnings if variables don't match the style guide */
1150 /* (i.e. upper-case for globals, snake case for fields etc.) */
1151 /* To allow warning free compilation of generated code and */
1152 /* consistency with snowball variable namings we allow some kind of warnings here */
generate_allow_warnings(struct generator * g)1153 static void generate_allow_warnings(struct generator * g) {
1154 
1155     w(g, "#![allow(non_upper_case_globals)]~N");
1156     w(g, "#![allow(non_snake_case)]~N");
1157     w(g, "#![allow(unused_variables)]~N");
1158     w(g, "#![allow(unused_mut)]~N");
1159 }
1160 
generate_class_begin(struct generator * g)1161 static void generate_class_begin(struct generator * g) {
1162 
1163     w(g, "use snowball::SnowballEnv;~N");
1164     if (g->analyser->among_count > 0) {
1165         w(g, "use snowball::Among;~N~N");
1166     }
1167 }
1168 
generate_among_table(struct generator * g,struct among * x)1169 static void generate_among_table(struct generator * g, struct among * x) {
1170 
1171     struct amongvec * v = x->b;
1172 
1173     g->I[0] = x->number;
1174     g->I[1] = x->literalstring_count;
1175 
1176     w(g, "~Mstatic A_~I0: &'static [Among<Context>; ~I1] = &[~N~+");
1177     {
1178         int i;
1179         for (i = 0; i < x->literalstring_count; i++) {
1180             g->I[0] = v->i;
1181             g->I[1] = v->result;
1182             g->L[0] = v->b;
1183             g->S[0] = ",";
1184 
1185             w(g, "~MAmong(~L0, ~I0, ~I1, ");
1186             if (v->function != 0) {
1187                 w(g, "Some(&");
1188                 write_varname(g, v->function);
1189                 w(g, ")");
1190             } else {
1191               w(g, "None");
1192             }
1193             w(g, ")~S0~N");
1194             v++;
1195         }
1196     }
1197     w(g, "~-~M];~N~N");
1198 }
1199 
generate_amongs(struct generator * g)1200 static void generate_amongs(struct generator * g) {
1201     struct among * x;
1202     for (x = g->analyser->amongs; x; x = x->next) {
1203         generate_among_table(g, x);
1204     }
1205 }
1206 
set_bit(symbol * b,int i)1207 static void set_bit(symbol * b, int i) { b[i/8] |= 1 << i%8; }
1208 
generate_grouping_table(struct generator * g,struct grouping * q)1209 static void generate_grouping_table(struct generator * g, struct grouping * q) {
1210 
1211     int range = q->largest_ch - q->smallest_ch + 1;
1212     int size = (range + 7)/ 8;  /* assume 8 bits per symbol */
1213     symbol * b = q->b;
1214     symbol * map = create_b(size);
1215     int i;
1216     for (i = 0; i < size; i++) map[i] = 0;
1217 
1218     for (i = 0; i < SIZE(b); i++) set_bit(map, b[i] - q->smallest_ch);
1219 
1220     g->V[0] = q->name;
1221     g->I[0] = size;
1222     w(g, "~Mstatic ~W0: &'static [u8; ~I0] = &[");
1223     for (i = 0; i < size; i++) {
1224         write_int(g, map[i]);
1225         if (i < size - 1) w(g, ", ");
1226     }
1227     w(g, "];~N~N");
1228     lose_b(map);
1229 }
1230 
generate_groupings(struct generator * g)1231 static void generate_groupings(struct generator * g) {
1232     struct grouping * q;
1233     for (q = g->analyser->groupings; q; q = q->next) {
1234         if (q->name->used)
1235             generate_grouping_table(g, q);
1236     }
1237 }
1238 
1239 
generate_members(struct generator * g)1240 static void generate_members(struct generator * g) {
1241 
1242     struct name * q;
1243     w(g, "#[derive(Clone)]~N");
1244     w(g, "struct Context {~+~N");
1245     for (q = g->analyser->names; q; q = q->next) {
1246         g->V[0] = q;
1247         switch (q->type) {
1248             case t_string:
1249                 w(g, "~M~W0: String,~N");
1250                 break;
1251             case t_integer:
1252                 w(g, "~M~W0: i32,~N");
1253                 break;
1254             case t_boolean:
1255                 w(g, "~M~W0: bool,~N");
1256                 break;
1257         }
1258     }
1259     w(g, "~-}~N");
1260 }
1261 
generate_methods(struct generator * g)1262 static void generate_methods(struct generator * g) {
1263 
1264     struct node * p = g->analyser->program;
1265     while (p != 0) {
1266         generate(g, p);
1267         g->unreachable = false;
1268         p = p->right;
1269     }
1270 }
1271 
generate_program_rust(struct generator * g)1272 extern void generate_program_rust(struct generator * g) {
1273 
1274     g->outbuf = str_new();
1275     g->failure_str = str_new();
1276 
1277     write_start_comment(g, "//! ", NULL);
1278     generate_allow_warnings(g);
1279     if (g->analyser->int_limits_used) {
1280         /* std::i32 is used in the code generated for i32::MAX and i32::MIN */
1281         w(g, "use std::i32;~N~N");
1282     }
1283     generate_class_begin(g);
1284 
1285     generate_amongs(g);
1286     generate_groupings(g);
1287 
1288     generate_members(g);
1289     generate_methods(g);
1290 
1291     output_str(g->options->output_src, g->outbuf);
1292     str_delete(g->failure_str);
1293     str_delete(g->outbuf);
1294 }
1295