mittens 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile +1 -0
  4. data/README.md +2 -2
  5. data/Rakefile +10 -3
  6. data/lib/mittens/version.rb +1 -1
  7. data/vendor/snowball/.github/workflows/ci.yml +144 -17
  8. data/vendor/snowball/.github/workflows/coverage.yml +117 -0
  9. data/vendor/snowball/.github/workflows/runtime-tests.yml +26 -0
  10. data/vendor/snowball/.gitignore +33 -7
  11. data/vendor/snowball/CONTRIBUTING.rst +7 -0
  12. data/vendor/snowball/COPYING +1 -1
  13. data/vendor/snowball/GNUmakefile +736 -298
  14. data/vendor/snowball/NEWS +1394 -7
  15. data/vendor/snowball/README.rst +8 -8
  16. data/vendor/snowball/ada/generate/generate.adb +5 -5
  17. data/vendor/snowball/ada/src/stemmer.adb +177 -188
  18. data/vendor/snowball/ada/src/stemmer.ads +86 -89
  19. data/vendor/snowball/ada/src/stemwords.adb +21 -5
  20. data/vendor/snowball/algorithms/czech.sbl +255 -0
  21. data/vendor/snowball/algorithms/danish.sbl +22 -10
  22. data/vendor/snowball/algorithms/english.sbl +7 -4
  23. data/vendor/snowball/algorithms/esperanto.sbl +6 -7
  24. data/vendor/snowball/algorithms/estonian.sbl +9 -4
  25. data/vendor/snowball/algorithms/finnish.sbl +33 -21
  26. data/vendor/snowball/algorithms/german.sbl +5 -0
  27. data/vendor/snowball/algorithms/indonesian.sbl +115 -96
  28. data/vendor/snowball/algorithms/italian.sbl +26 -1
  29. data/vendor/snowball/algorithms/lithuanian.sbl +13 -13
  30. data/vendor/snowball/algorithms/norwegian.sbl +17 -6
  31. data/vendor/snowball/algorithms/persian.sbl +387 -0
  32. data/vendor/snowball/algorithms/polish.sbl +177 -0
  33. data/vendor/snowball/algorithms/sesotho.sbl +115 -0
  34. data/vendor/snowball/algorithms/turkish.sbl +4 -4
  35. data/vendor/snowball/compiler/analyser.c +2002 -711
  36. data/vendor/snowball/compiler/driver.c +460 -298
  37. data/vendor/snowball/compiler/generator.c +439 -1965
  38. data/vendor/snowball/compiler/generator_ada.c +605 -430
  39. data/vendor/snowball/compiler/generator_c.c +2227 -0
  40. data/vendor/snowball/compiler/generator_csharp.c +365 -274
  41. data/vendor/snowball/compiler/generator_dart.c +1476 -0
  42. data/vendor/snowball/compiler/generator_go.c +348 -270
  43. data/vendor/snowball/compiler/generator_java.c +330 -233
  44. data/vendor/snowball/compiler/generator_js.c +534 -385
  45. data/vendor/snowball/compiler/generator_pascal.c +361 -320
  46. data/vendor/snowball/compiler/generator_php.c +1445 -0
  47. data/vendor/snowball/compiler/generator_python.c +399 -299
  48. data/vendor/snowball/compiler/generator_rust.c +370 -261
  49. data/vendor/snowball/compiler/generator_zig.c +1474 -0
  50. data/vendor/snowball/compiler/header.h +153 -86
  51. data/vendor/snowball/compiler/space.c +121 -63
  52. data/vendor/snowball/compiler/tokeniser.c +286 -182
  53. data/vendor/snowball/compiler/tokens.h +71 -0
  54. data/vendor/snowball/csharp/Snowball/Among.cs +14 -26
  55. data/vendor/snowball/csharp/Snowball/AssemblyInfo.cs +3 -3
  56. data/vendor/snowball/csharp/Snowball/Stemmer.cs +41 -45
  57. data/vendor/snowball/csharp/Stemwords/Program.cs +20 -14
  58. data/vendor/snowball/cxx/.gitignore +4 -0
  59. data/vendor/snowball/cxx/generate_algorithms.pl +87 -0
  60. data/vendor/snowball/cxx/stemmer.h +12 -0
  61. data/vendor/snowball/cxx/stemwords.cxx +176 -0
  62. data/vendor/snowball/cxx/utilities.cxx +2 -0
  63. data/vendor/snowball/dart/.gitignore +4 -0
  64. data/vendor/snowball/dart/analysis_options.yaml +1 -0
  65. data/vendor/snowball/dart/example/test_app.dart +65 -0
  66. data/vendor/snowball/dart/generate_algorithms.pl +21 -0
  67. data/vendor/snowball/dart/lib/snowball.dart +18 -0
  68. data/vendor/snowball/dart/lib/src/snowball.dart +339 -0
  69. data/vendor/snowball/dart/pubspec.yaml +17 -0
  70. data/vendor/snowball/doc/libstemmer_dart_README +37 -0
  71. data/vendor/snowball/doc/libstemmer_js_README +2 -2
  72. data/vendor/snowball/doc/libstemmer_php_README +38 -0
  73. data/vendor/snowball/doc/libstemmer_python_README +3 -3
  74. data/vendor/snowball/examples/stemwords.c +18 -3
  75. data/vendor/snowball/go/README.md +12 -4
  76. data/vendor/snowball/go/env.go +12 -14
  77. data/vendor/snowball/go/stemwords/main.go +2 -1
  78. data/vendor/snowball/java/org/tartarus/snowball/CharArraySequence.java +36 -0
  79. data/vendor/snowball/java/org/tartarus/snowball/SnowballProgram.java +17 -34
  80. data/vendor/snowball/java/org/tartarus/snowball/SnowballStemmer.java +0 -2
  81. data/vendor/snowball/javascript/base-stemmer.js +219 -252
  82. data/vendor/snowball/javascript/stemwords.js +86 -58
  83. data/vendor/snowball/libstemmer/mkmodules.pl +1 -1
  84. data/vendor/snowball/libstemmer/modules.txt +4 -0
  85. data/vendor/snowball/pascal/SnowballProgram.pas +18 -31
  86. data/vendor/snowball/php/base-stemmer.php +453 -0
  87. data/vendor/snowball/php/stemwords.php +25 -0
  88. data/vendor/snowball/python/create_init.py +16 -21
  89. data/vendor/snowball/python/pyproject.toml +3 -0
  90. data/vendor/snowball/python/setup.py +5 -7
  91. data/vendor/snowball/python/snowballstemmer/among.py +1 -2
  92. data/vendor/snowball/python/snowballstemmer/basestemmer.py +24 -33
  93. data/vendor/snowball/python/stemwords.py +72 -63
  94. data/vendor/snowball/runtime/api.c +11 -42
  95. data/vendor/snowball/runtime/api.h +11 -9
  96. data/vendor/snowball/runtime/snowball_runtime.h +110 -0
  97. data/vendor/snowball/runtime/utilities.c +282 -106
  98. data/vendor/snowball/rust/src/main.rs +2 -2
  99. data/vendor/snowball/rust/src/snowball/snowball_env.rs +7 -9
  100. data/vendor/snowball/tests/compilertest +62 -0
  101. data/vendor/snowball/tests/errors/ae-errors.sbl +53 -0
  102. data/vendor/snowball/tests/errors/ae-errors.stderr +8 -0
  103. data/vendor/snowball/tests/errors/bad-dollar.sbl +14 -0
  104. data/vendor/snowball/tests/errors/bad-dollar.stderr +4 -0
  105. data/vendor/snowball/tests/errors/bad-grouping-definition.sbl +9 -0
  106. data/vendor/snowball/tests/errors/bad-grouping-definition.stderr +6 -0
  107. data/vendor/snowball/tests/errors/missing-bra.sbl +6 -0
  108. data/vendor/snowball/tests/errors/missing-bra.stderr +3 -0
  109. data/vendor/snowball/tests/errors/missing-command.sbl +9 -0
  110. data/vendor/snowball/tests/errors/missing-command.stderr +1 -0
  111. data/vendor/snowball/tests/errors/missing-ket-backwardmode.sbl +3 -0
  112. data/vendor/snowball/tests/errors/missing-ket-backwardmode.stderr +1 -0
  113. data/vendor/snowball/tests/errors/missing-ket.sbl +7 -0
  114. data/vendor/snowball/tests/errors/missing-ket.stderr +6 -0
  115. data/vendor/snowball/tests/errors/notdefined.sbl +4 -0
  116. data/vendor/snowball/tests/errors/notdefined.stderr +2 -0
  117. data/vendor/snowball/tests/errors/string-omitted.sbl +5 -0
  118. data/vendor/snowball/tests/errors/string-omitted.stderr +1 -0
  119. data/vendor/snowball/tests/errors/undeclared.sbl +20 -0
  120. data/vendor/snowball/tests/errors/undeclared.stderr +9 -0
  121. data/vendor/snowball/tests/errors/unexpected-token.sbl +24 -0
  122. data/vendor/snowball/tests/errors/unexpected-token.stderr +17 -0
  123. data/vendor/snowball/tests/errors/wrongdirection.sbl +14 -0
  124. data/vendor/snowball/tests/errors/wrongdirection.stderr +1 -0
  125. data/vendor/snowball/tests/runtime/among.sbl +19 -0
  126. data/vendor/snowball/tests/runtime/arithmeticexpr.sbl +86 -0
  127. data/vendor/snowball/tests/runtime/attachinsert.sbl +47 -0
  128. data/vendor/snowball/tests/runtime/booleans.sbl +19 -0
  129. data/vendor/snowball/tests/runtime/externals.sbl +22 -0
  130. data/vendor/snowball/tests/runtime/hop.sbl +12 -0
  131. data/vendor/snowball/tests/runtime/integertests.sbl +60 -0
  132. data/vendor/snowball/tests/runtime/intlimits.sbl +25 -0
  133. data/vendor/snowball/tests/runtime/naming.sbl +20 -0
  134. data/vendor/snowball/tests/runtime/not.sbl +30 -0
  135. data/vendor/snowball/tests/runtime/or.sbl +17 -0
  136. data/vendor/snowball/tests/runtime/repeat.sbl +16 -0
  137. data/vendor/snowball/tests/runtime/setlimit.sbl +24 -0
  138. data/vendor/snowball/tests/runtime/sizelen.sbl +56 -0
  139. data/vendor/snowball/tests/runtime/slice.sbl +27 -0
  140. data/vendor/snowball/tests/runtime/stringdollar.sbl +39 -0
  141. data/vendor/snowball/tests/runtime/strings.sbl +66 -0
  142. data/vendor/snowball/tests/runtime/test.sbl +19 -0
  143. data/vendor/snowball/tests/stemtest.c +41 -1
  144. data/vendor/snowball/tests/syntax/canon.sbl +32 -0
  145. data/vendor/snowball/tests/syntax/canon.stderr +0 -0
  146. data/vendor/snowball/tests/syntax/canon.syntax +57 -0
  147. data/vendor/snowball/tests/syntax/emptyprogram.sbl +2 -0
  148. data/vendor/snowball/tests/syntax/emptyprogram.syntax +0 -0
  149. data/vendor/snowball/tests/syntax/groupings.sbl +11 -0
  150. data/vendor/snowball/tests/syntax/inline.sbl +144 -0
  151. data/vendor/snowball/tests/syntax/inline.stderr +0 -0
  152. data/vendor/snowball/tests/syntax/inline.syntax +121 -0
  153. data/vendor/snowball/tests/syntax/legacy.sbl +17 -0
  154. data/vendor/snowball/tests/syntax/legacy.stderr +5 -0
  155. data/vendor/snowball/tests/syntax/legacy.syntax +19 -0
  156. data/vendor/snowball/tests/syntax/loops.sbl +14 -0
  157. data/vendor/snowball/tests/syntax/loops.stderr +9 -0
  158. data/vendor/snowball/tests/syntax/loops.syntax +29 -0
  159. data/vendor/snowball/tests/syntax/noops.sbl +76 -0
  160. data/vendor/snowball/tests/syntax/noops.stderr +27 -0
  161. data/vendor/snowball/tests/syntax/noops.syntax +135 -0
  162. data/vendor/snowball/tests/syntax/simplifyae.sbl +21 -0
  163. data/vendor/snowball/tests/syntax/simplifyae.stderr +0 -0
  164. data/vendor/snowball/tests/syntax/simplifyae.syntax +39 -0
  165. data/vendor/snowball/tests/syntax/unused.sbl +18 -0
  166. data/vendor/snowball/tests/syntax/unused.stderr +7 -0
  167. data/vendor/snowball/tests/syntax/unused.syntax +3 -0
  168. data/vendor/snowball/zig/env.zig +599 -0
  169. data/vendor/snowball/zig/generate_algorithms.pl +19 -0
  170. data/vendor/snowball/zig/stemwords.zig +123 -0
  171. metadata +102 -4
  172. data/vendor/snowball/compiler/syswords.h +0 -86
  173. data/vendor/snowball/runtime/header.h +0 -62
@@ -1,77 +1,57 @@
1
1
  #include <assert.h>
2
+ #include <ctype.h> /* for toupper */
3
+ #include <stdio.h> /* for fprintf etc */
2
4
  #include <stdlib.h> /* for exit */
3
5
  #include <string.h> /* for strlen */
4
- #include <stdio.h> /* for fprintf etc */
5
- #include <ctype.h> /* for toupper */
6
6
  #include "header.h"
7
7
 
8
- /* prototypes */
8
+ /* prototype functions for recursive use: */
9
9
 
10
10
  static void generate(struct generator * g, struct node * p);
11
11
  static void w(struct generator * g, const char * s);
12
12
  static void writef(struct generator * g, const char * s, struct node * p);
13
13
 
14
- static int new_label(struct generator * g) {
15
- return g->next_label++;
16
- }
14
+ /* Write routines for items from the syntax tree */
17
15
 
18
- static struct str * vars_newname(struct generator * g) {
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;
16
+ static void write_relop(struct generator * g, int relop) {
17
+ // Relational operators are the same as C.
18
+ write_c_relop(g, relop);
25
19
  }
26
20
 
27
- /* Write routines for items from the syntax tree */
28
-
29
21
  static void write_varname(struct generator * g, struct name * p) {
30
- switch (p->type) {
31
- case t_external: {
32
- char save_initial = p->s[0];
33
- p->s[0] = toupper(save_initial);
34
- str_append_s(g->outbuf, p->s);
35
- p->s[0] = save_initial;
36
- return;
37
- }
38
- default: {
39
- int ch = "SbirxG"[p->type];
40
- write_char(g, ch);
41
- write_char(g, '_');
42
- break;
43
- }
44
- }
22
+ // We use the same naming scheme for both global and local variables.
23
+ write_char(g, "SbirrG"[p->type]);
24
+ write_char(g, '_');
45
25
  write_s(g, p->s);
46
26
  }
47
27
 
28
+ /* Reference to variable, e.g. when assigning to or using in an expression. */
48
29
  static void write_varref(struct generator * g, struct name * p) {
49
- write_string(g, "context.");
30
+ if (p->type >= t_routine || p->local_to == NULL) {
31
+ write_string(g, "context.");
32
+ }
50
33
  write_varname(g, p);
51
34
  }
52
35
 
53
36
  static void write_literal_string(struct generator * g, symbol * p) {
54
37
  int i = 0;
55
- write_string(g, "\"");
38
+ write_char(g, '"');
56
39
  while (i < SIZE(p)) {
57
40
  int ch;
58
41
  i += get_utf8(p + i, &ch);
59
- if (32 <= ch && ch < 0x590 && ch != 127) {
42
+ // Write out ASCII and lower Unicode printables as literal characters.
43
+ // Use escapes for anything over 0x590 as a crude way to avoid LTR
44
+ // characters affecting the rendering of source character order in
45
+ // confusing ways.
46
+ if ((32 <= ch && ch < 127) || (0xa0 < ch && ch < 0x590)) {
60
47
  if (ch == '"' || ch == '\\') write_char(g, '\\');
61
48
  write_wchar_as_utf8(g, ch);
62
49
  } else {
63
- // Use escapes for anything over 0x590 as a crude way to avoid
64
- // LTR characters affecting the rendering of source character
65
- // order in confusing ways.
66
50
  write_string(g, "\\u");
67
51
  write_hex4(g, ch);
68
52
  }
69
53
  }
70
- write_string(g, "\"");
71
- }
72
-
73
- static void write_margin(struct generator * g) {
74
- for (int i = 0; i < g->margin; i++) write_string(g, " ");
54
+ write_char(g, '"');
75
55
  }
76
56
 
77
57
  static void write_comment(struct generator * g, struct node * p) {
@@ -79,7 +59,7 @@ static void write_comment(struct generator * g, struct node * p) {
79
59
  /* FIXME could use Go //line syntax if we had original filename */
80
60
  write_margin(g);
81
61
  write_string(g, "// ");
82
- write_comment_content(g, p);
62
+ write_comment_content(g, p, NULL);
83
63
  write_newline(g);
84
64
  }
85
65
 
@@ -113,24 +93,27 @@ static void write_restorecursor(struct generator * g, struct node * p, struct st
113
93
 
114
94
  static void write_inc_cursor(struct generator * g, struct node * p) {
115
95
  write_margin(g);
116
- write_string(g, p->mode == m_forward ? "env.NextChar();" : "env.PrevChar();");
96
+ write_string(g, p->mode == m_forward ? "env.NextChar()" : "env.PrevChar()");
117
97
  write_newline(g);
118
98
  }
119
99
 
120
100
  static void wsetlab_begin(struct generator * g, int n) {
121
101
  g->I[0] = n;
122
- w(g, "~Mlab~I0: for {~N~+");
102
+ w(g, "~-~Mlab~I0:~N~+~Mfor {~N~+");
123
103
  }
124
104
 
125
105
  static void wsetlab_end(struct generator * g, int n) {
126
- g->I[0] = n;
127
- w(g, "~Mbreak lab~I0~N");
106
+ if (!g->unreachable) {
107
+ g->I[0] = n;
108
+ w(g, "~Mbreak lab~I0~N");
109
+ }
128
110
  w(g, "~-~M}~N");
129
111
  }
130
112
 
131
113
  static void wgotol(struct generator * g, int n) {
132
114
  g->I[0] = n;
133
115
  w(g, "~Mbreak lab~I0~N");
116
+ g->unreachable = true;
134
117
  }
135
118
 
136
119
  static void write_failure(struct generator * g) {
@@ -141,14 +124,14 @@ static void write_failure(struct generator * g) {
141
124
  }
142
125
  switch (g->failure_label) {
143
126
  case x_return:
144
- w(g, "~Mreturn false~N");
145
- g->unreachable = true;
127
+ w(g, "~Mreturn false");
146
128
  break;
147
129
  default:
148
- g->I[0] = g->failure_label;
149
- w(g, "~Mbreak lab~I0~N");
150
- g->unreachable = true;
130
+ w(g, "~Mbreak lab");
131
+ write_int(g, g->failure_label);
151
132
  }
133
+ write_newline(g);
134
+ g->unreachable = true;
152
135
  }
153
136
 
154
137
  static void write_failure_if(struct generator * g, const char * s, struct node * p) {
@@ -172,7 +155,6 @@ static void write_check_limit(struct generator * g, struct node * p) {
172
155
 
173
156
  /* Formatted write. */
174
157
  static void writef(struct generator * g, const char * input, struct node * p) {
175
- (void)p;
176
158
  int i = 0;
177
159
 
178
160
  while (input[i]) {
@@ -217,27 +199,29 @@ static void writef(struct generator * g, const char * input, struct node * p) {
217
199
  write_int(g, g->I[j]);
218
200
  continue;
219
201
  }
220
- case 'V':
221
- case 'W': {
222
- int j = input[i++] - '0';
223
- if (j < 0 || j > (int)(sizeof(g->V) / sizeof(g->V[0])))
224
- goto invalid_escape2;
225
- if (ch == 'V')
226
- write_varref(g, g->V[j]);
227
- else
228
- write_varname(g, g->V[j]);
202
+ case 'E': {
203
+ // Write an external name.
204
+ if (g->options->externals_prefix) {
205
+ write_string(g, g->options->externals_prefix);
206
+ }
207
+ char save_initial = p->name->s[0];
208
+ p->name->s[0] = toupper(save_initial);
209
+ write_s(g, p->name->s);
210
+ p->name->s[0] = save_initial;
229
211
  continue;
230
212
  }
231
- case 'L': {
232
- int j = input[i++] - '0';
233
- if (j < 0 || j > (int)(sizeof(g->L) / sizeof(g->L[0])))
234
- goto invalid_escape2;
235
- write_literal_string(g, g->L[j]);
213
+ case 'V':
214
+ write_varref(g, p->name);
215
+ continue;
216
+ case 'W':
217
+ write_varname(g, p->name);
218
+ continue;
219
+ case 'L':
220
+ write_literal_string(g, p->literalstring);
236
221
  continue;
237
- }
238
222
  case '+': g->margin++; continue;
239
223
  case '-': g->margin--; continue;
240
- case 'n': write_string(g, g->options->name); continue;
224
+ case 'n': write_s(g, g->options->name); continue;
241
225
  default:
242
226
  printf("Invalid escape sequence ~%c in writef(g, \"%s\", p)\n",
243
227
  ch, input);
@@ -258,37 +242,44 @@ static void generate_AE(struct generator * g, struct node * p) {
258
242
  const char * s;
259
243
  switch (p->type) {
260
244
  case c_name:
261
- write_varref(g, p->name); break;
245
+ write_varref(g, p->name);
246
+ break;
262
247
  case c_number:
263
- write_int(g, p->number); break;
248
+ write_int(g, p->number);
249
+ break;
264
250
  case c_maxint:
265
- write_string(g, "snowballRuntime.MaxInt"); break;
251
+ write_string(g, "snowballRuntime.MaxInt");
252
+ break;
266
253
  case c_minint:
267
- write_string(g, "snowballRuntime.MinInt"); break;
254
+ write_string(g, "snowballRuntime.MinInt");
255
+ break;
268
256
  case c_neg:
269
- write_char(g, '-'); generate_AE(g, p->right); break;
257
+ write_char(g, '-');
258
+ generate_AE(g, p->right);
259
+ break;
270
260
  case c_multiply:
271
- s = " * "; goto label0;
272
- case c_plus:
273
- s = " + "; goto label0;
274
- case c_minus:
275
- s = " - "; goto label0;
261
+ s = " * ";
262
+ goto label0;
276
263
  case c_divide:
277
264
  s = " / ";
265
+ goto label0;
266
+ case c_plus:
267
+ s = " + ";
268
+ goto label0;
269
+ case c_minus:
270
+ s = " - ";
278
271
  label0:
279
- write_char(g, '('); generate_AE(g, p->left);
280
- write_string(g, s); generate_AE(g, p->right); write_char(g, ')'); break;
272
+ write_char(g, '(');
273
+ generate_AE(g, p->left);
274
+ write_string(g, s);
275
+ generate_AE(g, p->right);
276
+ write_char(g, ')');
277
+ break;
281
278
  case c_cursor:
282
- w(g, "env.Cursor"); break;
283
- case c_limit:
284
- w(g, p->mode == m_forward ? "env.Limit" : "env.LimitBackward"); break;
285
- case c_lenof:
286
- g->V[0] = p->name;
287
- w(g, "snowballRuntime.RuneCountInString(~V0)");
279
+ w(g, "env.Cursor");
288
280
  break;
289
- case c_sizeof:
290
- g->V[0] = p->name;
291
- w(g, "len(~V0)");
281
+ case c_limit:
282
+ w(g, p->mode == m_forward ? "env.Limit" : "env.LimitBackward");
292
283
  break;
293
284
  case c_len:
294
285
  w(g, "snowballRuntime.RuneCountInString(env.Current())");
@@ -296,6 +287,12 @@ static void generate_AE(struct generator * g, struct node * p) {
296
287
  case c_size:
297
288
  w(g, "len(env.Current())");
298
289
  break;
290
+ case c_lenof:
291
+ writef(g, "snowballRuntime.RuneCountInString(~V)", p);
292
+ break;
293
+ case c_sizeof:
294
+ writef(g, "len(~V)", p);
295
+ break;
299
296
  }
300
297
  }
301
298
 
@@ -310,13 +307,15 @@ static void generate_bra(struct generator * g, struct node * p) {
310
307
 
311
308
  static void generate_and(struct generator * g, struct node * p) {
312
309
  struct str * savevar = NULL;
313
- if (K_needed(g, p->left)) {
310
+ if (K_needed_for_and(p->left)) {
314
311
  savevar = vars_newname(g);
315
312
  }
316
313
 
317
314
  write_comment(g, p);
318
315
 
319
- if (savevar) write_savecursor(g, p, savevar);
316
+ if (savevar) {
317
+ write_savecursor(g, p, savevar);
318
+ }
320
319
 
321
320
  p = p->left;
322
321
  while (p) {
@@ -333,7 +332,7 @@ static void generate_and(struct generator * g, struct node * p) {
333
332
 
334
333
  static void generate_or(struct generator * g, struct node * p) {
335
334
  struct str * savevar = NULL;
336
- if (K_needed(g, p->left)) {
335
+ if (K_needed_for_or(p->left)) {
337
336
  savevar = vars_newname(g);
338
337
  }
339
338
 
@@ -341,12 +340,14 @@ static void generate_or(struct generator * g, struct node * p) {
341
340
  struct str * a1 = str_copy(g->failure_str);
342
341
 
343
342
  int out_lab = new_label(g);
344
- int end_unreachable = true;
343
+ bool end_unreachable = true;
345
344
 
346
345
  write_comment(g, p);
347
346
  wsetlab_begin(g, out_lab);
348
347
 
349
- if (savevar) write_savecursor(g, p, savevar);
348
+ if (savevar && K_needed_node_on_f(p)) {
349
+ write_savecursor(g, p, savevar);
350
+ }
350
351
 
351
352
  p = p->left;
352
353
  str_clear(g->failure_str);
@@ -366,9 +367,12 @@ static void generate_or(struct generator * g, struct node * p) {
366
367
  wgotol(g, out_lab);
367
368
  end_unreachable = false;
368
369
  }
369
- w(g, "~-~M}~N");
370
+
371
+ wsetlab_end(g, label);
370
372
  g->unreachable = false;
371
- if (savevar) write_restorecursor(g, p, savevar);
373
+ if (savevar) {
374
+ write_restorecursor(g, p, savevar);
375
+ }
372
376
  p = p->right;
373
377
  }
374
378
 
@@ -377,6 +381,7 @@ static void generate_or(struct generator * g, struct node * p) {
377
381
  g->failure_str = a1;
378
382
 
379
383
  generate(g, p);
384
+
380
385
  wsetlab_end(g, out_lab);
381
386
  if (!end_unreachable) {
382
387
  g->unreachable = false;
@@ -395,10 +400,9 @@ static void generate_backwards(struct generator * g, struct node * p) {
395
400
  w(g, "~Menv.Cursor = env.LimitBackward~N");
396
401
  }
397
402
 
398
-
399
403
  static void generate_not(struct generator * g, struct node * p) {
400
404
  struct str * savevar = NULL;
401
- if (K_needed(g, p->left)) {
405
+ if (K_needed_node_on_f(p->left)) {
402
406
  savevar = vars_newname(g);
403
407
  }
404
408
 
@@ -423,7 +427,8 @@ static void generate_not(struct generator * g, struct node * p) {
423
427
  g->failure_str = a1;
424
428
 
425
429
  if (!g->unreachable) write_failure(g);
426
- w(g, "~-~M}~N");
430
+
431
+ wsetlab_end(g, label);
427
432
 
428
433
  g->unreachable = false;
429
434
 
@@ -433,10 +438,9 @@ static void generate_not(struct generator * g, struct node * p) {
433
438
  }
434
439
  }
435
440
 
436
-
437
441
  static void generate_try(struct generator * g, struct node * p) {
438
442
  struct str * savevar = NULL;
439
- if (K_needed(g, p->left)) {
443
+ if (K_needed(p->left)) {
440
444
  savevar = vars_newname(g);
441
445
  }
442
446
 
@@ -449,6 +453,7 @@ static void generate_try(struct generator * g, struct node * p) {
449
453
  write_savecursor(g, p, savevar);
450
454
  append_restore_string(p, g->failure_str, savevar);
451
455
  }
456
+
452
457
  wsetlab_begin(g, label);
453
458
  generate(g, p->left);
454
459
  wsetlab_end(g, label);
@@ -461,14 +466,12 @@ static void generate_try(struct generator * g, struct node * p) {
461
466
 
462
467
  static void generate_set(struct generator * g, struct node * p) {
463
468
  write_comment(g, p);
464
- g->V[0] = p->name;
465
- writef(g, "~M~V0 = true~N", p);
469
+ writef(g, "~M~V = true~N", p);
466
470
  }
467
471
 
468
472
  static void generate_unset(struct generator * g, struct node * p) {
469
473
  write_comment(g, p);
470
- g->V[0] = p->name;
471
- writef(g, "~M~V0 = false~N", p);
474
+ writef(g, "~M~V = false~N", p);
472
475
  }
473
476
 
474
477
  static void generate_fail(struct generator * g, struct node * p) {
@@ -478,10 +481,9 @@ static void generate_fail(struct generator * g, struct node * p) {
478
481
  }
479
482
 
480
483
  /* generate_test() also implements 'reverse' */
481
-
482
484
  static void generate_test(struct generator * g, struct node * p) {
483
485
  struct str * savevar = NULL;
484
- if (K_needed(g, p->left)) {
486
+ if (K_needed(p->left)) {
485
487
  savevar = vars_newname(g);
486
488
  }
487
489
 
@@ -503,18 +505,19 @@ static void generate_test(struct generator * g, struct node * p) {
503
505
 
504
506
  static void generate_do(struct generator * g, struct node * p) {
505
507
  struct str * savevar = NULL;
506
- if (K_needed(g, p->left)) {
508
+ if (K_needed(p->left)) {
507
509
  savevar = vars_newname(g);
508
510
  }
509
511
 
510
512
  write_comment(g, p);
511
- if (savevar) write_savecursor(g, p, savevar);
513
+ if (savevar) {
514
+ write_savecursor(g, p, savevar);
515
+ }
512
516
 
513
517
  if (p->left->type == c_call) {
514
518
  /* Optimise do <call> */
515
519
  write_comment(g, p->left);
516
- g->V[0] = p->left->name;
517
- w(g, "~M~W0(env, context)~N");
520
+ writef(g, "~M~W(env, context)~N", p->left);
518
521
  } else {
519
522
  int label = new_label(g);
520
523
  g->failure_label = label;
@@ -522,6 +525,7 @@ static void generate_do(struct generator * g, struct node * p) {
522
525
 
523
526
  wsetlab_begin(g, label);
524
527
  generate(g, p->left);
528
+
525
529
  wsetlab_end(g, label);
526
530
  g->unreachable = false;
527
531
  }
@@ -544,34 +548,34 @@ static void generate_GO_grouping(struct generator * g, struct node * p, int is_g
544
548
  struct grouping * q = p->name->grouping;
545
549
  g->S[0] = p->mode == m_forward ? "" : "B";
546
550
  g->S[1] = complement ? "In" : "Out";
547
- g->V[0] = p->name;
548
551
  g->I[0] = q->smallest_ch;
549
552
  g->I[1] = q->largest_ch;
550
- write_failure_if(g, "!env.Go~S1Grouping~S0(~W0, ~I0, ~I1)", p);
553
+ write_failure_if(g, "!env.Go~S1Grouping~S0(~W, ~I0, ~I1)", p);
551
554
  if (!is_goto) {
552
- write_string(g, p->mode == m_forward ? "env.NextChar();" : "env.PrevChar();");
555
+ w(g, p->mode == m_forward ? "~Menv.NextChar()~N" : "~Menv.PrevChar()~N");
553
556
  }
554
557
  }
555
558
 
556
- static void generate_GO(struct generator * g, struct node * p, int style) {
559
+ static void generate_GO(struct generator * g, struct node * p, int is_goto) {
557
560
  write_comment(g, p);
558
561
 
559
562
  int a0 = g->failure_label;
560
563
  struct str * a1 = str_copy(g->failure_str);
561
564
 
562
- int end_unreachable = false;
565
+ bool end_unreachable = false;
563
566
 
564
567
  int golab = new_label(g);
565
568
  g->I[0] = golab;
566
- w(g, "~Mgolab~I0: for {~N~+");
569
+ w(g, "~-~Mgolab~I0:~N~+~Mfor {~N~+");
567
570
 
568
571
  struct str * savevar = NULL;
569
- if (style == 1 || repeat_restore(g, p->left)) {
572
+ if (is_goto || repeat_restore(p->left)) {
570
573
  savevar = vars_newname(g);
571
574
  write_savecursor(g, p, savevar);
572
575
  }
573
576
 
574
- g->failure_label = new_label(g);
577
+ int label = new_label(g);
578
+ g->failure_label = label;
575
579
  str_clear(g->failure_str);
576
580
  wsetlab_begin(g, g->failure_label);
577
581
  generate(g, p->left);
@@ -582,12 +586,13 @@ static void generate_GO(struct generator * g, struct node * p, int style) {
582
586
  end_unreachable = true;
583
587
  } else {
584
588
  /* include for goto; omit for gopast */
585
- if (style == 1) write_restorecursor(g, p, savevar);
589
+ if (is_goto) write_restorecursor(g, p, savevar);
586
590
  g->I[0] = golab;
587
591
  w(g, "~Mbreak golab~I0~N");
592
+ g->unreachable = true;
588
593
  }
594
+ wsetlab_end(g, g->failure_label);
589
595
  g->unreachable = false;
590
- w(g, "~-~M}~N");
591
596
  if (savevar) {
592
597
  write_restorecursor(g, p, savevar);
593
598
  str_delete(savevar);
@@ -604,11 +609,11 @@ static void generate_GO(struct generator * g, struct node * p, int style) {
604
609
  }
605
610
 
606
611
  static void generate_loop(struct generator * g, struct node * p) {
607
- struct str * loopvar = vars_newname(g);
608
612
  write_comment(g, p);
609
- w(g, "~Mfor _ = range make([]struct{},");
613
+ struct str * loopvar = vars_newname(g);
614
+ w(g, "~Mfor _ = range make([]struct{}, ");
610
615
  generate_AE(g, p->AE);
611
- writef(g, ") {~+", p);
616
+ writef(g, ") {~N~+", p);
612
617
 
613
618
  generate(g, p->left);
614
619
 
@@ -620,18 +625,19 @@ static void generate_loop(struct generator * g, struct node * p) {
620
625
  static void generate_repeat_or_atleast(struct generator * g, struct node * p, struct str * loopvar) {
621
626
  int replab = new_label(g);
622
627
  g->I[0] = replab;
623
- writef(g, "~Mreplab~I0: for{~N~+", p);
628
+ writef(g, "~-~Mreplab~I0:~N~+~Mfor {~N~+", p);
624
629
 
625
630
  struct str * savevar = NULL;
626
- if (repeat_restore(g, p->left)) {
631
+ if (repeat_restore(p->left)) {
627
632
  savevar = vars_newname(g);
628
633
  write_savecursor(g, p, savevar);
629
634
  }
630
635
 
631
- g->failure_label = new_label(g);
636
+ int label = new_label(g);
637
+ g->failure_label = label;
632
638
  str_clear(g->failure_str);
633
639
  g->I[0] = g->failure_label;
634
- w(g, "~Mlab~I0: for _ = range [2]struct{}{} {~N~+");
640
+ w(g, "~-~Mlab~I0:~N~+~Mfor range [2]struct{}{} {~N~+");
635
641
  generate(g, p->left);
636
642
 
637
643
  if (!g->unreachable) {
@@ -661,9 +667,9 @@ static void generate_repeat(struct generator * g, struct node * p) {
661
667
  }
662
668
 
663
669
  static void generate_atleast(struct generator * g, struct node * p) {
664
- struct str * loopvar = vars_newname(g);
665
-
666
670
  write_comment(g, p);
671
+
672
+ struct str * loopvar = vars_newname(g);
667
673
  g->B[0] = str_data(loopvar);
668
674
  w(g, "~Mvar ~B0 = ");
669
675
  generate_AE(g, p->AE);
@@ -683,12 +689,6 @@ static void generate_atleast(struct generator * g, struct node * p) {
683
689
  str_delete(loopvar);
684
690
  }
685
691
 
686
- static void generate_setmark(struct generator * g, struct node * p) {
687
- write_comment(g, p);
688
- g->V[0] = p->name;
689
- writef(g, "~M~V0 = env.Cursor~N", p);
690
- }
691
-
692
692
  static void generate_tomark(struct generator * g, struct node * p) {
693
693
  write_comment(g, p);
694
694
  g->S[0] = p->mode == m_forward ? ">" : "<";
@@ -701,15 +701,6 @@ static void generate_tomark(struct generator * g, struct node * p) {
701
701
  w(g, "~Menv.Cursor = "); generate_AE(g, p->AE); writef(g, "~N", p);
702
702
  }
703
703
 
704
- static void generate_atmark(struct generator * g, struct node * p) {
705
- write_comment(g, p);
706
- w(g, "~Mif env.Cursor != "); generate_AE(g, p->AE); writef(g, " ", p);
707
- write_block_start(g);
708
- write_failure(g);
709
- write_block_end(g);
710
- g->unreachable = false;
711
- }
712
-
713
704
  static void generate_hop(struct generator * g, struct node * p) {
714
705
  write_comment(g, p);
715
706
  // Generate the AE to a temporary block so we can substitute it in
@@ -726,26 +717,12 @@ static void generate_hop(struct generator * g, struct node * p) {
726
717
  str_delete(ae);
727
718
  }
728
719
 
729
- static void generate_delete(struct generator * g, struct node * p) {
730
- write_comment(g, p);
731
- writef(g, "~Mif !env.SliceDel() {~N"
732
- "~+~Mreturn false~N~-"
733
- "~M}~N", p);
734
- }
735
-
736
720
  static void generate_tolimit(struct generator * g, struct node * p) {
737
721
  write_comment(g, p);
738
722
  g->S[0] = p->mode == m_forward ? "env.Limit" : "env.LimitBackward";
739
723
  writef(g, "~Menv.Cursor = ~S0~N", p);
740
724
  }
741
725
 
742
- static void generate_atlimit(struct generator * g, struct node * p) {
743
- write_comment(g, p);
744
- g->S[0] = p->mode == m_forward ? "env.Limit" : "env.LimitBackward";
745
- g->S[1] = p->mode == m_forward ? "<" : ">";
746
- write_failure_if(g, "env.Cursor ~S1 ~S0", p);
747
- }
748
-
749
726
  static void generate_leftslice(struct generator * g, struct node * p) {
750
727
  write_comment(g, p);
751
728
  g->S[0] = p->mode == m_forward ? "env.Bra" : "env.Ket";
@@ -760,16 +737,12 @@ static void generate_rightslice(struct generator * g, struct node * p) {
760
737
 
761
738
  static void generate_assignto(struct generator * g, struct node * p) {
762
739
  write_comment(g, p);
763
- g->V[0] = p->name;
764
- writef(g, "~M~V0 = env.AssignTo()~N", p);
740
+ writef(g, "~M~V = env.AssignTo()~N", p);
765
741
  }
766
742
 
767
743
  static void generate_sliceto(struct generator * g, struct node * p) {
768
744
  write_comment(g, p);
769
- g->V[0] = p->name;
770
- writef(g, "~M~V0 = env.SliceTo()~N"
771
- "~Mif ~V0 == \"\" {~N"
772
- "~+~Mreturn false~N~-~M}~N", p);
745
+ writef(g, "~M~V = env.SliceTo()~N", p);
773
746
  }
774
747
 
775
748
  static void generate_address(struct generator * g, struct node * p) {
@@ -782,26 +755,28 @@ static void generate_address(struct generator * g, struct node * p) {
782
755
  }
783
756
 
784
757
  static void generate_insert(struct generator * g, struct node * p, int style) {
785
- int keep_c = style == c_attach;
786
-
758
+ write_margin(g);
787
759
  write_block_start(g);
788
760
  write_comment(g, p);
761
+ int keep_c = style == c_attach;
789
762
  if (p->mode == m_backward) keep_c = !keep_c;
790
763
  if (keep_c) w(g, "~Mvar c = env.Cursor~N");
791
764
  w(g, "~Mbra, ket := env.Cursor, env.Cursor~N");
792
765
  writef(g, "~Menv.Insert(bra, ket, ", p);
793
766
  generate_address(g, p);
794
- writef(g, ");~N", p);
767
+ writef(g, ")~N", p);
795
768
  if (keep_c) w(g, "~Menv.Cursor = c~N");
796
769
  write_block_end(g);
797
770
  }
798
771
 
799
- static void generate_assignfrom(struct generator * g, struct node * p) {
800
- int keep_c = p->mode == m_forward; /* like 'attach' */
801
-
772
+ static void generate_stringassign(struct generator * g, struct node * p) {
773
+ write_margin(g);
802
774
  write_block_start(g);
803
775
  write_comment(g, p);
804
- if (keep_c) writef(g, "~Mvar c = env.Cursor~N", p);
776
+ int keep_c = p->mode == m_forward; /* like 'attach' */
777
+ if (keep_c) {
778
+ writef(g, "~Mvar c = env.Cursor~N", p);
779
+ }
805
780
  if (p->mode == m_forward) {
806
781
  writef(g, "~Menv.Insert(env.Cursor, env.Limit, ", p);
807
782
  } else {
@@ -809,21 +784,27 @@ static void generate_assignfrom(struct generator * g, struct node * p) {
809
784
  }
810
785
  generate_address(g, p);
811
786
  writef(g, ")~N", p);
812
- if (keep_c) w(g, "~Menv.Cursor = c~N");
787
+ if (keep_c) {
788
+ w(g, "~Menv.Cursor = c~N");
789
+ }
813
790
  write_block_end(g);
814
791
  }
815
792
 
816
793
  static void generate_slicefrom(struct generator * g, struct node * p) {
817
794
  write_comment(g, p);
818
- w(g, "~Mif !env.SliceFrom(");
795
+ if (p->literalstring && SIZE(p->literalstring) == 0) {
796
+ w(g, "~Menv.SliceDel()~N");
797
+ return;
798
+ }
799
+ w(g, "~Menv.SliceFrom(");
819
800
  generate_address(g, p);
820
- writef(g, ") {~N"
821
- "~+~Mreturn false~N~-~M}~N", p);
801
+ w(g, ")~N");
822
802
  }
823
803
 
824
804
  static void generate_setlimit(struct generator * g, struct node * p) {
825
- struct str * varname = vars_newname(g);
826
805
  write_comment(g, p);
806
+ struct str * varname = vars_newname(g);
807
+
827
808
  if (p->left && p->left->type == c_tomark) {
828
809
  /* Special case for:
829
810
  *
@@ -835,6 +816,7 @@ static void generate_setlimit(struct generator * g, struct node * p) {
835
816
  */
836
817
  struct node * q = p->left;
837
818
  write_comment(g, q);
819
+
838
820
  g->S[0] = q->mode == m_forward ? ">" : "<";
839
821
  w(g, "~Mif env.Cursor ~S0 "); generate_AE(g, q->AE); w(g, " ");
840
822
  write_block_start(g);
@@ -844,22 +826,24 @@ static void generate_setlimit(struct generator * g, struct node * p) {
844
826
 
845
827
  g->B[0] = str_data(varname);
846
828
  if (p->mode == m_forward) {
847
- w(g, "~Mvar ~B0 = env.Limit - env.Cursor~N");
829
+ w(g, "~Mvar ~B0 = env.Limit~N");
848
830
  w(g, "~Menv.Limit = ");
831
+ generate_AE(g, q->AE);
832
+ w(g, "~N");
833
+ w(g, "~M~B0 -= env.Limit~N");
849
834
  } else {
850
835
  w(g, "~Mvar ~B0 = env.LimitBackward~N");
851
836
  w(g, "~Menv.LimitBackward = ");
837
+ generate_AE(g, q->AE);
838
+ w(g, "~N");
852
839
  }
853
- generate_AE(g, q->AE); writef(g, ";~N", q);
854
840
 
855
841
  if (p->mode == m_forward) {
856
842
  str_assign(g->failure_str, "env.Limit += ");
857
843
  str_append(g->failure_str, varname);
858
- str_append_string(g->failure_str, ";");
859
844
  } else {
860
845
  str_assign(g->failure_str, "env.LimitBackward = ");
861
846
  str_append(g->failure_str, varname);
862
- str_append_string(g->failure_str, ";");
863
847
  }
864
848
  } else {
865
849
  struct str * savevar = vars_newname(g);
@@ -881,11 +865,9 @@ static void generate_setlimit(struct generator * g, struct node * p) {
881
865
  if (p->mode == m_forward) {
882
866
  str_assign(g->failure_str, "env.Limit += ");
883
867
  str_append(g->failure_str, varname);
884
- str_append_string(g->failure_str, ";");
885
868
  } else {
886
869
  str_assign(g->failure_str, "env.LimitBackward = ");
887
870
  str_append(g->failure_str, varname);
888
- str_append_string(g->failure_str, ";");
889
871
  }
890
872
  }
891
873
  str_delete(savevar);
@@ -908,28 +890,56 @@ static void generate_setlimit(struct generator * g, struct node * p) {
908
890
  static void generate_dollar(struct generator * g, struct node * p) {
909
891
  write_comment(g, p);
910
892
 
893
+ int a0 = g->failure_label;
894
+ struct str * a1 = str_copy(g->failure_str);
895
+ int label = new_label(g);
896
+ g->failure_label = label;
897
+ str_clear(g->failure_str);
898
+
911
899
  struct str * savevar = vars_newname(g);
912
- g->V[0] = p->name;
913
900
  g->B[0] = str_data(savevar);
914
901
  writef(g, "~Mvar ~B0 = env.Clone()~N"
915
- "~Menv.SetCurrent(~V0)~N", p);
902
+ "~Menv.SetCurrent(~V)~N", p);
903
+ if (p->left->possible_signals == -1) {
904
+ /* Assume failure. */
905
+ w(g, "~Mvar ~B0_f = true~N");
906
+ }
907
+
908
+ wsetlab_begin(g, g->failure_label);
909
+
916
910
  generate(g, p->left);
917
- if (!g->unreachable) {
918
- g->V[0] = p->name;
911
+
912
+ if (!g->unreachable && p->left->possible_signals == -1) {
913
+ /* Mark success. */
919
914
  g->B[0] = str_data(savevar);
920
- /* Update string variable. */
921
- w(g, "~M~V0 = env.Current()~N");
922
- /* Reset env */
923
- w(g, "~M*env = *~B0~N");
915
+ w(g, "~M~B0_f = false~N");
924
916
  }
917
+
918
+ wsetlab_end(g, g->failure_label);
919
+
920
+ g->failure_label = a0;
921
+ str_delete(g->failure_str);
922
+ g->failure_str = a1;
923
+
924
+ g->B[0] = str_data(savevar);
925
+ /* Update string variable; restore env. */
926
+ writef(g, "~M~V = env.Current()~N"
927
+ "~M*env = *~B0~N", p);
928
+
929
+ if (p->left->possible_signals == 0) {
930
+ // p->left always signals f.
931
+ write_failure(g);
932
+ } else if (p->left->possible_signals == -1) {
933
+ write_failure_if(g, "~B0_f", p);
934
+ }
935
+
925
936
  str_delete(savevar);
926
937
  }
927
938
 
928
939
  static void generate_integer_assign(struct generator * g, struct node * p, const char * s) {
929
940
  write_comment(g, p);
930
- g->V[0] = p->name;
931
941
  g->S[0] = s;
932
- w(g, "~M~V0 ~S0 ");
942
+ writef(g, "~M~V ~S0 ", p);
933
943
  generate_AE(g, p->AE);
934
944
  w(g, "~N");
935
945
  }
@@ -937,7 +947,7 @@ static void generate_integer_assign(struct generator * g, struct node * p, const
937
947
  static void generate_integer_test(struct generator * g, struct node * p) {
938
948
  write_comment(g, p);
939
949
  int relop = p->type;
940
- int optimise_to_return = (g->failure_label == x_return && p->right && p->right->type == c_functionend);
950
+ int optimise_to_return = tailcallable(g, p);
941
951
  if (optimise_to_return) {
942
952
  w(g, "~Mreturn ");
943
953
  p->right = NULL;
@@ -947,12 +957,12 @@ static void generate_integer_test(struct generator * g, struct node * p) {
947
957
  relop ^= 1;
948
958
  }
949
959
  generate_AE(g, p->left);
950
- // Relational operators are the same as C.
951
- write_c_relop(g, relop);
960
+ write_relop(g, relop);
952
961
  generate_AE(g, p->AE);
953
962
  if (optimise_to_return) {
954
963
  w(g, "~N");
955
964
  } else {
965
+ write_char(g, ' ');
956
966
  write_block_start(g);
957
967
  write_failure(g);
958
968
  write_block_end(g);
@@ -961,24 +971,28 @@ static void generate_integer_test(struct generator * g, struct node * p) {
961
971
  }
962
972
 
963
973
  static void generate_call(struct generator * g, struct node * p) {
964
- int signals = check_possible_signals_list(g, p->name->definition, c_define, 0);
974
+ int signals = p->name->definition->possible_signals;
965
975
  write_comment(g, p);
966
- g->V[0] = p->name;
967
- if (g->failure_label == x_return &&
968
- (signals == 0 || (p->right && p->right->type == c_functionend))) {
969
- /* Always fails or tail call. */
970
- writef(g, "~Mreturn ~W0(env, context)~N", p);
976
+ if (tailcallable(g, p)) {
977
+ /* Tail call. */
978
+ writef(g, "~Mreturn ~W(env, context)~N", p);
979
+ p->right = NULL;
980
+ return;
981
+ }
982
+ if (just_return_on_fail(g) && signals == 0) {
983
+ /* Always fails. */
984
+ writef(g, "~Mreturn ~W(env, context)~N", p);
971
985
  return;
972
986
  }
973
987
  if (signals == 1) {
974
988
  /* Always succeeds. */
975
- writef(g, "~M~W0(env, context)~N", p);
989
+ writef(g, "~M~W(env, context)~N", p);
976
990
  } else if (signals == 0) {
977
991
  /* Always fails. */
978
- writef(g, "~M~W0(env, context)~N", p);
992
+ writef(g, "~M~W(env, context)~N", p);
979
993
  write_failure(g);
980
994
  } else {
981
- write_failure_if(g, "!~W0(env, context)", p);
995
+ write_failure_if(g, "!~W(env, context)", p);
982
996
  }
983
997
  }
984
998
 
@@ -988,40 +1002,63 @@ static void generate_grouping(struct generator * g, struct node * p, int complem
988
1002
  struct grouping * q = p->name->grouping;
989
1003
  g->S[0] = p->mode == m_forward ? "" : "B";
990
1004
  g->S[1] = complement ? "Out" : "In";
991
- g->V[0] = p->name;
992
1005
  g->I[0] = q->smallest_ch;
993
1006
  g->I[1] = q->largest_ch;
994
- write_failure_if(g, "!env.~S1Grouping~S0(~W0, ~I0, ~I1)", p);
1007
+ if (tailcallable(g, p)) {
1008
+ writef(g, "~Mreturn env.~S1Grouping~S0(~W, ~I0, ~I1);~N", p);
1009
+ p->right = NULL;
1010
+ } else {
1011
+ write_failure_if(g, "!env.~S1Grouping~S0(~W, ~I0, ~I1)", p);
1012
+ }
995
1013
  }
996
1014
 
997
1015
  static void generate_namedstring(struct generator * g, struct node * p) {
998
1016
  write_comment(g, p);
999
1017
  g->S[0] = p->mode == m_forward ? "" : "B";
1000
- g->V[0] = p->name;
1001
- write_failure_if(g, "!env.EqS~S0(~V0)", p);
1018
+ if (tailcallable(g, p)) {
1019
+ writef(g, "~Mreturn env.EqS~S0(~V)~N", p);
1020
+ p->right = NULL;
1021
+ } else {
1022
+ write_failure_if(g, "!env.EqS~S0(~V)", p);
1023
+ }
1002
1024
  }
1003
1025
 
1004
1026
  static void generate_literalstring(struct generator * g, struct node * p) {
1005
- symbol * b = p->literalstring;
1006
1027
  write_comment(g, p);
1007
1028
  g->S[0] = p->mode == m_forward ? "" : "B";
1008
- g->L[0] = b;
1009
- write_failure_if(g, "!env.EqS~S0(~L0)", p);
1029
+ if (tailcallable(g, p)) {
1030
+ writef(g, "~Mreturn env.EqS~S0(~L)~N", p);
1031
+ p->right = NULL;
1032
+ } else {
1033
+ write_failure_if(g, "!env.EqS~S0(~L)", p);
1034
+ }
1010
1035
  }
1011
1036
 
1012
1037
  static void generate_setup_context(struct generator * g) {
1013
- w(g, "~Mvar context = &Context {~+~N");
1038
+ if (g->analyser->variable_count == 0) {
1039
+ w(g, "~Mvar context = &Context{}~N");
1040
+ w(g, "~M_ = context~N");
1041
+ return;
1042
+ }
1043
+
1044
+ w(g, "~Mvar context = &Context{~+~N");
1014
1045
  for (struct name * q = g->analyser->names; q; q = q->next) {
1015
- g->V[0] = q;
1046
+ if (q->local_to) continue;
1016
1047
  switch (q->type) {
1017
1048
  case t_string:
1018
- w(g, "~M~W0: \"\",~N");
1049
+ write_margin(g);
1050
+ write_varname(g, q);
1051
+ w(g, ": \"\",~N");
1019
1052
  break;
1020
1053
  case t_integer:
1021
- w(g, "~M~W0: 0,~N");
1054
+ write_margin(g);
1055
+ write_varname(g, q);
1056
+ w(g, ": 0,~N");
1022
1057
  break;
1023
1058
  case t_boolean:
1024
- w(g, "~M~W0: false,~N");
1059
+ write_margin(g);
1060
+ write_varname(g, q);
1061
+ w(g, ": false,~N");
1025
1062
  break;
1026
1063
  }
1027
1064
  }
@@ -1030,27 +1067,55 @@ static void generate_setup_context(struct generator * g) {
1030
1067
  }
1031
1068
 
1032
1069
  static void generate_define(struct generator * g, struct node * p) {
1033
- struct name * q = p->name;
1034
- if (q->type == t_routine && !q->used) return;
1035
-
1036
1070
  write_newline(g);
1037
1071
  write_comment(g, p);
1038
1072
 
1039
- g->V[0] = q;
1040
-
1073
+ struct name * q = p->name;
1041
1074
  if (q->type == t_routine) {
1042
- w(g, "~Mfunc ~W0(env *snowballRuntime.Env, ctx interface{}) bool {~+~N");
1075
+ writef(g, "~Mfunc ~W(env *snowballRuntime.Env, ctx interface{}) bool {~+~N", p);
1043
1076
  w(g, "~Mcontext := ctx.(*Context)~N");
1044
1077
  w(g, "~M_ = context~N");
1045
1078
  } else {
1046
- w(g, "~Mfunc ~W0(env *snowballRuntime.Env) bool {~+~N");
1079
+ writef(g, "~Mfunc ~E(env *snowballRuntime.Env) bool {~+~N", p);
1047
1080
  generate_setup_context(g);
1081
+ if (q->used != q->definition) {
1082
+ // This external needs to be callable as a routine, so generate
1083
+ // the actual code like a routine with an external which just
1084
+ // forwards to that.
1085
+ writef(g, "~Mreturn ~W(env, context)~N", p);
1086
+ w(g, "~-~M}~N");
1087
+ writef(g, "~Mfunc ~W(env *snowballRuntime.Env, ctx interface{}) bool {~+~N", p);
1088
+ w(g, "~Mcontext := ctx.(*Context)~N");
1089
+ w(g, "~M_ = context~N");
1090
+ }
1048
1091
  }
1049
- if (p->amongvar_needed) w(g, "~Mvar among_var int32~N");
1050
1092
 
1051
- /* Save output. */
1052
- struct str * saved_output = g->outbuf;
1053
- g->outbuf = str_new();
1093
+ if (q->amongvar_needed) {
1094
+ w(g, "~Mvar among_var int32~N");
1095
+ }
1096
+
1097
+ /* Declare localised variables. */
1098
+ for (struct name * name = g->analyser->names; name; name = name->next) {
1099
+ if (name->local_to == q) {
1100
+ switch (name->type) {
1101
+ case t_string:
1102
+ w(g, "~Mvar ");
1103
+ write_varname(g, name);
1104
+ w(g, " string~N");
1105
+ break;
1106
+ case t_integer:
1107
+ w(g, "~Mvar ");
1108
+ write_varname(g, name);
1109
+ w(g, " int~N");
1110
+ break;
1111
+ case t_boolean:
1112
+ w(g, "~Mvar ");
1113
+ write_varname(g, name);
1114
+ w(g, " bool~N");
1115
+ break;
1116
+ }
1117
+ }
1118
+ }
1054
1119
 
1055
1120
  g->next_label = 0;
1056
1121
  g->var_number = 0;
@@ -1058,21 +1123,16 @@ static void generate_define(struct generator * g, struct node * p) {
1058
1123
  str_clear(g->failure_str);
1059
1124
  g->failure_label = x_return;
1060
1125
  g->unreachable = false;
1061
- int signals = check_possible_signals_list(g, p->left, c_define, 0);
1062
1126
 
1063
1127
  /* Generate function body. */
1064
1128
  generate(g, p->left);
1065
1129
  if (p->left->right) {
1066
1130
  assert(p->left->right->type == c_functionend);
1067
- if (signals) {
1131
+ if (p->left->possible_signals) {
1068
1132
  generate(g, p->left->right);
1069
1133
  }
1070
1134
  }
1071
1135
  w(g, "~-~M}~N");
1072
-
1073
- str_append(saved_output, g->outbuf);
1074
- str_delete(g->outbuf);
1075
- g->outbuf = saved_output;
1076
1136
  }
1077
1137
 
1078
1138
  static void generate_functionend(struct generator * g, struct node * p) {
@@ -1095,6 +1155,10 @@ static void generate_substring(struct generator * g, struct node * p) {
1095
1155
  }
1096
1156
  } else if (x->always_matches) {
1097
1157
  writef(g, "~Menv.FindAmong~S0(A_~I0, context)~N", p);
1158
+ } else if (x->command_count == 0 && tailcallable(g, p)) {
1159
+ writef(g, "~Mreturn env.FindAmong~S0(A_~I0, context) != 0~N", p);
1160
+ x->node->right = NULL;
1161
+ g->unreachable = true;
1098
1162
  } else {
1099
1163
  write_failure_if(g, "env.FindAmong~S0(A_~I0, context) == 0", p);
1100
1164
  }
@@ -1125,10 +1189,23 @@ static void generate_among(struct generator * g, struct node * p) {
1125
1189
  }
1126
1190
  }
1127
1191
 
1128
- static void generate_booltest(struct generator * g, struct node * p) {
1192
+ static void generate_booltest(struct generator * g, struct node * p, int inverted) {
1129
1193
  write_comment(g, p);
1130
- g->V[0] = p->name;
1131
- write_failure_if(g, "!~V0", p);
1194
+ if (tailcallable(g, p)) {
1195
+ // Optimise at end of function.
1196
+ if (inverted) {
1197
+ writef(g, "~Mreturn !~V~N", p);
1198
+ } else {
1199
+ writef(g, "~Mreturn ~V~N", p);
1200
+ }
1201
+ p->right = NULL;
1202
+ return;
1203
+ }
1204
+ if (inverted) {
1205
+ write_failure_if(g, "~V", p);
1206
+ } else {
1207
+ write_failure_if(g, "!~V", p);
1208
+ }
1132
1209
  }
1133
1210
 
1134
1211
  static void generate_false(struct generator * g, struct node * p) {
@@ -1173,25 +1250,21 @@ static void generate(struct generator * g, struct node * p) {
1173
1250
  case c_repeat: generate_repeat(g, p); break;
1174
1251
  case c_loop: generate_loop(g, p); break;
1175
1252
  case c_atleast: generate_atleast(g, p); break;
1176
- case c_setmark: generate_setmark(g, p); break;
1177
1253
  case c_tomark: generate_tomark(g, p); break;
1178
- case c_atmark: generate_atmark(g, p); break;
1179
1254
  case c_hop: generate_hop(g, p); break;
1180
- case c_delete: generate_delete(g, p); break;
1181
1255
  case c_next: generate_next(g, p); break;
1182
1256
  case c_tolimit: generate_tolimit(g, p); break;
1183
- case c_atlimit: generate_atlimit(g, p); break;
1184
1257
  case c_leftslice: generate_leftslice(g, p); break;
1185
1258
  case c_rightslice: generate_rightslice(g, p); break;
1186
1259
  case c_assignto: generate_assignto(g, p); break;
1187
1260
  case c_sliceto: generate_sliceto(g, p); break;
1188
- case c_assign: generate_assignfrom(g, p); break;
1261
+ case c_stringassign: generate_stringassign(g, p); break;
1189
1262
  case c_insert:
1190
1263
  case c_attach: generate_insert(g, p, p->type); break;
1191
1264
  case c_slicefrom: generate_slicefrom(g, p); break;
1192
1265
  case c_setlimit: generate_setlimit(g, p); break;
1193
1266
  case c_dollar: generate_dollar(g, p); break;
1194
- case c_mathassign: generate_integer_assign(g, p, "="); break;
1267
+ case c_assign: generate_integer_assign(g, p, "="); break;
1195
1268
  case c_plusassign: generate_integer_assign(g, p, "+="); break;
1196
1269
  case c_minusassign: generate_integer_assign(g, p, "-="); break;
1197
1270
  case c_multiplyassign:generate_integer_assign(g, p, "*="); break;
@@ -1211,7 +1284,8 @@ static void generate(struct generator * g, struct node * p) {
1211
1284
  case c_literalstring: generate_literalstring(g, p); break;
1212
1285
  case c_among: generate_among(g, p); break;
1213
1286
  case c_substring: generate_substring(g, p); break;
1214
- case c_booltest: generate_booltest(g, p); break;
1287
+ case c_booltest: generate_booltest(g, p, false); break;
1288
+ case c_not_booltest: generate_booltest(g, p, true); break;
1215
1289
  case c_false: generate_false(g, p); break;
1216
1290
  case c_true: break;
1217
1291
  case c_debug: generate_debug(g, p); break;
@@ -1227,13 +1301,13 @@ static void generate(struct generator * g, struct node * p) {
1227
1301
 
1228
1302
  static void generate_class_begin(struct generator * g) {
1229
1303
  w(g, "package ");
1230
- w(g, g->options->package);
1304
+ write_string(g, g->options->package);
1231
1305
  w(g, "~N~N");
1232
1306
 
1233
- w(g, "import(~N");
1234
- w(g, " snowballRuntime \"");
1235
- w(g, g->options->go_snowball_runtime);
1236
- w(g, "\"~N)~N~N");
1307
+ w(g, "import (~N");
1308
+ w(g, "~+~MsnowballRuntime \"");
1309
+ write_string(g, g->options->go_snowball_runtime);
1310
+ w(g, "\"~N~-)~N~N");
1237
1311
  }
1238
1312
 
1239
1313
  static void generate_among_table(struct generator * g, struct among * x) {
@@ -1247,17 +1321,17 @@ static void generate_among_table(struct generator * g, struct among * x) {
1247
1321
  for (int i = 0; i < x->literalstring_count; i++) {
1248
1322
  g->I[0] = v[i].i;
1249
1323
  g->I[1] = v[i].result;
1250
- g->L[0] = v[i].b;
1251
- g->S[0] = ",";
1252
1324
 
1253
- w(g, "~M&snowballRuntime.Among{Str:~L0, A:~I0, B:~I1, ");
1325
+ w(g, "~M&snowballRuntime.Among{Str: ");
1326
+ write_literal_string(g, v[i].b);
1327
+ w(g, ", A: ~I0, B: ~I1, F: ");
1328
+
1254
1329
  if (v[i].function != NULL) {
1255
- w(g, "F:");
1256
1330
  write_varname(g, v[i].function);
1257
1331
  } else {
1258
- w(g, "F:nil");
1332
+ w(g, "nil");
1259
1333
  }
1260
- w(g, "}~S0~N");
1334
+ w(g, "},~N");
1261
1335
  }
1262
1336
  w(g, "~-~M}~N~N");
1263
1337
  }
@@ -1268,11 +1342,11 @@ static void generate_amongs(struct generator * g) {
1268
1342
  }
1269
1343
  }
1270
1344
 
1271
- static void set_bit(symbol * b, int i) { b[i/8] |= 1 << i%8; }
1345
+ static void set_bit(symbol * b, int i) { b[i >> 3] |= 1 << (i & 7); }
1272
1346
 
1273
1347
  static void generate_grouping_table(struct generator * g, struct grouping * q) {
1274
1348
  int range = q->largest_ch - q->smallest_ch + 1;
1275
- int size = (range + 7)/ 8; /* assume 8 bits per symbol */
1349
+ int size = (range + 7) / 8; /* assume 8 bits per symbol */
1276
1350
  symbol * b = q->b;
1277
1351
  symbol * map = create_b(size);
1278
1352
 
@@ -1280,11 +1354,12 @@ static void generate_grouping_table(struct generator * g, struct grouping * q) {
1280
1354
 
1281
1355
  for (int i = 0; i < SIZE(b); i++) set_bit(map, b[i] - q->smallest_ch);
1282
1356
 
1283
- g->V[0] = q->name;
1284
- w(g, "~Mvar ~W0 = []byte{");
1357
+ w(g, "~Mvar ");
1358
+ write_varname(g, q->name);
1359
+ w(g, " = []byte{");
1285
1360
  for (int i = 0; i < size; i++) {
1361
+ if (i) w(g, ", ");
1286
1362
  write_int(g, map[i]);
1287
- if (i < size - 1) w(g, ", ");
1288
1363
  }
1289
1364
  w(g, "}~N~N");
1290
1365
 
@@ -1293,24 +1368,29 @@ static void generate_grouping_table(struct generator * g, struct grouping * q) {
1293
1368
 
1294
1369
  static void generate_groupings(struct generator * g) {
1295
1370
  for (struct grouping * q = g->analyser->groupings; q; q = q->next) {
1296
- if (q->name->used)
1297
- generate_grouping_table(g, q);
1371
+ generate_grouping_table(g, q);
1298
1372
  }
1299
1373
  }
1300
1374
 
1301
1375
  static void generate_members(struct generator * g) {
1302
1376
  w(g, "type Context struct {~+~N");
1303
1377
  for (struct name * q = g->analyser->names; q; q = q->next) {
1304
- g->V[0] = q;
1378
+ if (q->local_to) continue;
1305
1379
  switch (q->type) {
1306
1380
  case t_string:
1307
- w(g, "~M~W0 string~N");
1381
+ write_margin(g);
1382
+ write_varname(g, q);
1383
+ w(g, " string~N");
1308
1384
  break;
1309
1385
  case t_integer:
1310
- w(g, "~M~W0 int~N");
1386
+ write_margin(g);
1387
+ write_varname(g, q);
1388
+ w(g, " int~N");
1311
1389
  break;
1312
1390
  case t_boolean:
1313
- w(g, "~M~W0 bool~N");
1391
+ write_margin(g);
1392
+ write_varname(g, q);
1393
+ w(g, " bool~N");
1314
1394
  break;
1315
1395
  }
1316
1396
  }
@@ -1325,14 +1405,12 @@ static void generate_methods(struct generator * g) {
1325
1405
  }
1326
1406
 
1327
1407
  extern void generate_program_go(struct generator * g) {
1408
+ g->margin_indent = "\t";
1409
+
1328
1410
  g->outbuf = str_new();
1329
1411
  g->failure_str = str_new();
1330
1412
 
1331
1413
  write_start_comment(g, "//! ", NULL);
1332
- if (g->analyser->int_limits_used) {
1333
- /* std::usize is used in the code generated for usize::MAX and usize::MIN */
1334
- w(g, "use std::usize;~N~N");
1335
- }
1336
1414
  generate_class_begin(g);
1337
1415
 
1338
1416
  generate_amongs(g);