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,79 +1,64 @@
1
1
  #include <assert.h>
2
+ #include <stdio.h> /* for fprintf etc */
2
3
  #include <stdlib.h> /* for exit */
3
4
  #include <string.h> /* for strlen */
4
- #include <stdio.h> /* for fprintf etc */
5
5
  #include "header.h"
6
6
 
7
- /* prototypes */
7
+ /* prototype functions for recursive use: */
8
8
 
9
9
  static void generate(struct generator * g, struct node * p);
10
10
  static void w(struct generator * g, const char * s);
11
11
  static void writef(struct generator * g, const char * s, struct node * p);
12
12
 
13
- static int new_label(struct generator * g) {
14
- return g->next_label++;
15
- }
13
+ /* Write routines for items from the syntax tree */
16
14
 
17
- static struct str * vars_newname(struct generator * g) {
18
- struct str * output;
19
- g->var_number++;
20
- output = str_new();
21
- str_append_string(output, "v_");
22
- str_append_int(output, g->var_number);
23
- return output;
15
+ static void write_relop(struct generator * g, int relop) {
16
+ // Relational operators are the same as C.
17
+ write_c_relop(g, relop);
24
18
  }
25
19
 
26
- /* Write routines for items from the syntax tree */
27
-
28
20
  static void write_varname(struct generator * g, struct name * p) {
29
- switch (p->type) {
30
- case t_external:
31
- break;
32
- default: {
33
- int ch = "SbirxG"[p->type];
34
- write_char(g, ch);
35
- write_char(g, '_');
36
- break;
37
- }
38
- }
21
+ // We use the same naming scheme for both global and local variables.
22
+ write_char(g, "SbirrG"[p->type]);
23
+ write_char(g, '_');
39
24
  write_s(g, p->s);
40
25
  }
41
26
 
27
+ /* Reference to variable, e.g. when assigning to or using in an expression. */
42
28
  static void write_varref(struct generator * g, struct name * p) {
43
- write_string(g, "context.");
29
+ if (p->local_to == NULL) {
30
+ write_string(g, "context.");
31
+ }
44
32
  write_varname(g, p);
45
33
  }
46
34
 
47
35
  static void write_literal_string(struct generator * g, symbol * p) {
48
36
  int i = 0;
49
- write_string(g, "\"");
37
+ write_char(g, '"');
50
38
  while (i < SIZE(p)) {
51
39
  int ch;
52
40
  i += get_utf8(p + i, &ch);
53
- if (32 <= ch && ch < 0x590 && ch != 127) {
41
+ // Write out ASCII and lower Unicode printables as literal characters.
42
+ // Use escapes for anything over 0x590 as a crude way to avoid LTR
43
+ // characters affecting the rendering of source character order in
44
+ // confusing ways.
45
+ if ((32 <= ch && ch < 127) || (0xa0 < ch && ch < 0x590)) {
54
46
  if (ch == '"' || ch == '\\') write_char(g, '\\');
55
47
  write_wchar_as_utf8(g, ch);
56
48
  } else {
57
- // Use escapes for anything over 0x590 as a crude way to avoid
58
- // LTR characters affecting the rendering of source character
59
- // order in confusing ways.
60
49
  write_string(g, "\\u{");
61
50
  write_hex4(g, ch);
62
51
  write_string(g, "}");
63
52
  }
64
53
  }
65
- write_string(g, "\"");
66
- }
67
-
68
- static void write_margin(struct generator * g) {
69
- for (int i = 0; i < g->margin; i++) write_string(g, " ");
54
+ write_char(g, '"');
70
55
  }
71
56
 
72
57
  static void write_comment(struct generator * g, struct node * p) {
73
58
  if (!g->options->comments) return;
74
59
  write_margin(g);
75
60
  write_string(g, "// ");
76
- write_comment_content(g, p);
61
+ write_comment_content(g, p, NULL);
77
62
  write_newline(g);
78
63
  }
79
64
 
@@ -97,7 +82,7 @@ static void append_restore_string(struct node * p, struct str * out, struct str
97
82
  str_append_string(out, "env.cursor = ");
98
83
  if (p->mode != m_forward) str_append_string(out, "env.limit - ");
99
84
  str_append(out, savevar);
100
- str_append_string(out, ";");
85
+ str_append_ch(out, ';');
101
86
  }
102
87
 
103
88
  static void write_restorecursor(struct generator * g, struct node * p, struct str * savevar) {
@@ -128,6 +113,7 @@ static void wsetlab_end(struct generator * g, int n) {
128
113
  static void wgotol(struct generator * g, int n) {
129
114
  g->I[0] = n;
130
115
  w(g, "~Mbreak 'lab~I0;~N");
116
+ g->unreachable = true;
131
117
  }
132
118
 
133
119
  static void write_failure(struct generator * g) {
@@ -138,15 +124,15 @@ static void write_failure(struct generator * g) {
138
124
  }
139
125
  switch (g->failure_label) {
140
126
  case x_return:
141
- w(g, "~Mreturn false;~N");
142
- g->unreachable = true;
127
+ w(g, "~Mreturn false;");
143
128
  break;
144
129
  default:
145
130
  w(g, "~Mbreak 'lab");
146
131
  write_int(g, g->failure_label);
147
- w(g, ";~N");
148
- g->unreachable = true;
132
+ write_char(g, ';');
149
133
  }
134
+ write_newline(g);
135
+ g->unreachable = true;
150
136
  }
151
137
 
152
138
  static void write_failure_if(struct generator * g, const char * s, struct node * p) {
@@ -170,7 +156,6 @@ static void write_check_limit(struct generator * g, struct node * p) {
170
156
 
171
157
  /* Formatted write. */
172
158
  static void writef(struct generator * g, const char * input, struct node * p) {
173
- (void)p;
174
159
  int i = 0;
175
160
 
176
161
  while (input[i]) {
@@ -215,27 +200,26 @@ static void writef(struct generator * g, const char * input, struct node * p) {
215
200
  write_int(g, g->I[j]);
216
201
  continue;
217
202
  }
218
- case 'V':
219
- case 'W': {
220
- int j = input[i++] - '0';
221
- if (j < 0 || j > (int)(sizeof(g->V) / sizeof(g->V[0])))
222
- goto invalid_escape2;
223
- if (ch == 'V')
224
- write_varref(g, g->V[j]);
225
- else
226
- write_varname(g, g->V[j]);
203
+ case 'E': {
204
+ // Write an external name.
205
+ if (g->options->externals_prefix) {
206
+ write_string(g, g->options->externals_prefix);
207
+ }
208
+ write_s(g, p->name->s);
227
209
  continue;
228
210
  }
229
- case 'L': {
230
- int j = input[i++] - '0';
231
- if (j < 0 || j > (int)(sizeof(g->L) / sizeof(g->L[0])))
232
- goto invalid_escape2;
233
- write_literal_string(g, g->L[j]);
211
+ case 'V':
212
+ write_varref(g, p->name);
213
+ continue;
214
+ case 'W':
215
+ write_varname(g, p->name);
216
+ continue;
217
+ case 'L':
218
+ write_literal_string(g, p->literalstring);
234
219
  continue;
235
- }
236
220
  case '+': g->margin++; continue;
237
221
  case '-': g->margin--; continue;
238
- case 'n': write_string(g, g->options->name); continue;
222
+ case 'n': write_s(g, g->options->name); continue;
239
223
  default:
240
224
  printf("Invalid escape sequence ~%c in writef(g, \"%s\", p)\n",
241
225
  ch, input);
@@ -256,37 +240,44 @@ static void generate_AE(struct generator * g, struct node * p) {
256
240
  const char * s;
257
241
  switch (p->type) {
258
242
  case c_name:
259
- write_varref(g, p->name); break;
243
+ write_varref(g, p->name);
244
+ break;
260
245
  case c_number:
261
- write_int(g, p->number); break;
246
+ write_int(g, p->number);
247
+ break;
262
248
  case c_maxint:
263
- write_string(g, "i32::MAX"); break;
249
+ write_string(g, "i32::MAX");
250
+ break;
264
251
  case c_minint:
265
- write_string(g, "i32::MIN"); break;
252
+ write_string(g, "i32::MIN");
253
+ break;
266
254
  case c_neg:
267
- write_char(g, '-'); generate_AE(g, p->right); break;
255
+ write_char(g, '-');
256
+ generate_AE(g, p->right);
257
+ break;
268
258
  case c_multiply:
269
- s = " * "; goto label0;
270
- case c_plus:
271
- s = " + "; goto label0;
272
- case c_minus:
273
- s = " - "; goto label0;
259
+ s = " * ";
260
+ goto label0;
274
261
  case c_divide:
275
262
  s = " / ";
263
+ goto label0;
264
+ case c_plus:
265
+ s = " + ";
266
+ goto label0;
267
+ case c_minus:
268
+ s = " - ";
276
269
  label0:
277
- write_char(g, '('); generate_AE(g, p->left);
278
- write_string(g, s); generate_AE(g, p->right); write_char(g, ')'); break;
270
+ write_char(g, '(');
271
+ generate_AE(g, p->left);
272
+ write_string(g, s);
273
+ generate_AE(g, p->right);
274
+ write_char(g, ')');
275
+ break;
279
276
  case c_cursor:
280
- w(g, "env.cursor"); break;
281
- case c_limit:
282
- w(g, p->mode == m_forward ? "env.limit" : "env.limit_backward"); break;
283
- case c_lenof:
284
- g->V[0] = p->name;
285
- w(g, "(~V0.chars().count() as i32)");
277
+ w(g, "env.cursor");
286
278
  break;
287
- case c_sizeof:
288
- g->V[0] = p->name;
289
- w(g, "(~V0.len() as i32)");
279
+ case c_limit:
280
+ w(g, p->mode == m_forward ? "env.limit" : "env.limit_backward");
290
281
  break;
291
282
  case c_len:
292
283
  w(g, "(env.current.chars().count() as i32)");
@@ -294,6 +285,12 @@ static void generate_AE(struct generator * g, struct node * p) {
294
285
  case c_size:
295
286
  w(g, "(env.current.len() as i32)");
296
287
  break;
288
+ case c_lenof:
289
+ writef(g, "(~V.chars().count() as i32)", p);
290
+ break;
291
+ case c_sizeof:
292
+ writef(g, "(~V.len() as i32)", p);
293
+ break;
297
294
  }
298
295
  }
299
296
 
@@ -308,13 +305,15 @@ static void generate_bra(struct generator * g, struct node * p) {
308
305
 
309
306
  static void generate_and(struct generator * g, struct node * p) {
310
307
  struct str * savevar = NULL;
311
- if (K_needed(g, p->left)) {
308
+ if (K_needed_for_and(p->left)) {
312
309
  savevar = vars_newname(g);
313
310
  }
314
311
 
315
312
  write_comment(g, p);
316
313
 
317
- if (savevar) write_savecursor(g, p, savevar);
314
+ if (savevar) {
315
+ write_savecursor(g, p, savevar);
316
+ }
318
317
 
319
318
  p = p->left;
320
319
  while (p) {
@@ -331,7 +330,7 @@ static void generate_and(struct generator * g, struct node * p) {
331
330
 
332
331
  static void generate_or(struct generator * g, struct node * p) {
333
332
  struct str * savevar = NULL;
334
- if (K_needed(g, p->left)) {
333
+ if (K_needed_for_or(p->left)) {
335
334
  savevar = vars_newname(g);
336
335
  }
337
336
 
@@ -339,12 +338,14 @@ static void generate_or(struct generator * g, struct node * p) {
339
338
  struct str * a1 = str_copy(g->failure_str);
340
339
 
341
340
  int out_lab = new_label(g);
342
- int end_unreachable = true;
341
+ bool end_unreachable = true;
343
342
 
344
343
  write_comment(g, p);
345
344
  wsetlab_begin(g, out_lab);
346
345
 
347
- if (savevar) write_savecursor(g, p, savevar);
346
+ if (savevar && K_needed_node_on_f(p)) {
347
+ write_savecursor(g, p, savevar);
348
+ }
348
349
 
349
350
  p = p->left;
350
351
  str_clear(g->failure_str);
@@ -364,9 +365,11 @@ static void generate_or(struct generator * g, struct node * p) {
364
365
  wgotol(g, out_lab);
365
366
  end_unreachable = false;
366
367
  }
367
- w(g, "~-~M}~N");
368
+ wsetlab_end(g, label);
368
369
  g->unreachable = false;
369
- if (savevar) write_restorecursor(g, p, savevar);
370
+ if (savevar) {
371
+ write_restorecursor(g, p, savevar);
372
+ }
370
373
  p = p->right;
371
374
  }
372
375
 
@@ -375,6 +378,7 @@ static void generate_or(struct generator * g, struct node * p) {
375
378
  g->failure_str = a1;
376
379
 
377
380
  generate(g, p);
381
+
378
382
  wsetlab_end(g, out_lab);
379
383
  if (!end_unreachable) {
380
384
  g->unreachable = false;
@@ -393,10 +397,9 @@ static void generate_backwards(struct generator * g, struct node * p) {
393
397
  w(g, "~Menv.cursor = env.limit_backward;~N");
394
398
  }
395
399
 
396
-
397
400
  static void generate_not(struct generator * g, struct node * p) {
398
401
  struct str * savevar = NULL;
399
- if (K_needed(g, p->left)) {
402
+ if (K_needed_node_on_f(p->left)) {
400
403
  savevar = vars_newname(g);
401
404
  }
402
405
 
@@ -421,7 +424,7 @@ static void generate_not(struct generator * g, struct node * p) {
421
424
  g->failure_str = a1;
422
425
 
423
426
  if (!g->unreachable) write_failure(g);
424
- w(g, "~-~M}~N");
427
+ wsetlab_end(g, label);
425
428
 
426
429
  g->unreachable = false;
427
430
 
@@ -431,18 +434,16 @@ static void generate_not(struct generator * g, struct node * p) {
431
434
  }
432
435
  }
433
436
 
434
-
435
437
  static void generate_try(struct generator * g, struct node * p) {
436
438
  struct str * savevar = NULL;
437
- if (K_needed(g, p->left)) {
439
+ if (K_needed(p->left)) {
438
440
  savevar = vars_newname(g);
439
441
  }
440
442
 
443
+ write_comment(g, p);
441
444
  int label = new_label(g);
442
445
  g->failure_label = label;
443
446
  str_clear(g->failure_str);
444
-
445
- write_comment(g, p);
446
447
  if (savevar) {
447
448
  write_savecursor(g, p, savevar);
448
449
  append_restore_string(p, g->failure_str, savevar);
@@ -459,14 +460,12 @@ static void generate_try(struct generator * g, struct node * p) {
459
460
 
460
461
  static void generate_set(struct generator * g, struct node * p) {
461
462
  write_comment(g, p);
462
- g->V[0] = p->name;
463
- writef(g, "~M~V0 = true;~N", p);
463
+ writef(g, "~M~V = true;~N", p);
464
464
  }
465
465
 
466
466
  static void generate_unset(struct generator * g, struct node * p) {
467
467
  write_comment(g, p);
468
- g->V[0] = p->name;
469
- writef(g, "~M~V0 = false;~N", p);
468
+ writef(g, "~M~V = false;~N", p);
470
469
  }
471
470
 
472
471
  static void generate_fail(struct generator * g, struct node * p) {
@@ -476,10 +475,9 @@ static void generate_fail(struct generator * g, struct node * p) {
476
475
  }
477
476
 
478
477
  /* generate_test() also implements 'reverse' */
479
-
480
478
  static void generate_test(struct generator * g, struct node * p) {
481
479
  struct str * savevar = NULL;
482
- if (K_needed(g, p->left)) {
480
+ if (K_needed(p->left)) {
483
481
  savevar = vars_newname(g);
484
482
  }
485
483
 
@@ -501,18 +499,19 @@ static void generate_test(struct generator * g, struct node * p) {
501
499
 
502
500
  static void generate_do(struct generator * g, struct node * p) {
503
501
  struct str * savevar = NULL;
504
- if (K_needed(g, p->left)) {
502
+ if (K_needed(p->left)) {
505
503
  savevar = vars_newname(g);
506
504
  }
507
505
 
508
506
  write_comment(g, p);
509
- if (savevar) write_savecursor(g, p, savevar);
507
+ if (savevar) {
508
+ write_savecursor(g, p, savevar);
509
+ }
510
510
 
511
511
  if (p->left->type == c_call) {
512
512
  /* Optimise do <call> */
513
513
  write_comment(g, p->left);
514
- g->V[0] = p->left->name;
515
- w(g, "~M~W0(env, context);~N");
514
+ writef(g, "~M~W(env, context);~N", p->left);
516
515
  } else {
517
516
  int label = new_label(g);
518
517
  g->failure_label = label;
@@ -542,34 +541,36 @@ static void generate_GO_grouping(struct generator * g, struct node * p, int is_g
542
541
  struct grouping * q = p->name->grouping;
543
542
  g->S[0] = p->mode == m_forward ? "" : "_b";
544
543
  g->S[1] = complement ? "in" : "out";
545
- g->V[0] = p->name;
546
544
  g->I[0] = q->smallest_ch;
547
545
  g->I[1] = q->largest_ch;
548
- write_failure_if(g, "!env.go_~S1_grouping~S0(~W0, ~I0, ~I1)", p);
546
+ write_failure_if(g, "!env.go_~S1_grouping~S0(~W, ~I0, ~I1)", p);
549
547
  if (!is_goto) {
548
+ write_margin(g);
550
549
  write_string(g, p->mode == m_forward ? "env.next_char();" : "env.previous_char();");
550
+ write_newline(g);
551
551
  }
552
552
  }
553
553
 
554
- static void generate_GO(struct generator * g, struct node * p, int style) {
554
+ static void generate_GO(struct generator * g, struct node * p, int is_goto) {
555
555
  write_comment(g, p);
556
556
 
557
557
  int a0 = g->failure_label;
558
558
  struct str * a1 = str_copy(g->failure_str);
559
559
 
560
- int end_unreachable = false;
560
+ bool end_unreachable = false;
561
561
 
562
562
  int golab = new_label(g);
563
563
  g->I[0] = golab;
564
564
  w(g, "~M'golab~I0: loop {~N~+");
565
565
 
566
566
  struct str * savevar = NULL;
567
- if (style == 1 || repeat_restore(g, p->left)) {
567
+ if (is_goto || repeat_restore(p->left)) {
568
568
  savevar = vars_newname(g);
569
569
  write_savecursor(g, p, savevar);
570
570
  }
571
571
 
572
- g->failure_label = new_label(g);
572
+ int label = new_label(g);
573
+ g->failure_label = label;
573
574
  str_clear(g->failure_str);
574
575
  wsetlab_begin(g, g->failure_label);
575
576
  generate(g, p->left);
@@ -580,12 +581,13 @@ static void generate_GO(struct generator * g, struct node * p, int style) {
580
581
  end_unreachable = true;
581
582
  } else {
582
583
  /* include for goto; omit for gopast */
583
- if (style == 1) write_restorecursor(g, p, savevar);
584
+ if (is_goto) write_restorecursor(g, p, savevar);
584
585
  g->I[0] = golab;
585
586
  w(g, "~Mbreak 'golab~I0;~N");
587
+ g->unreachable = true;
586
588
  }
589
+ wsetlab_end(g, g->failure_label);
587
590
  g->unreachable = false;
588
- w(g, "~-~M}~N");
589
591
  if (savevar) {
590
592
  write_restorecursor(g, p, savevar);
591
593
  str_delete(savevar);
@@ -602,8 +604,8 @@ static void generate_GO(struct generator * g, struct node * p, int style) {
602
604
  }
603
605
 
604
606
  static void generate_loop(struct generator * g, struct node * p) {
605
- struct str * loopvar = vars_newname(g);
606
607
  write_comment(g, p);
608
+ struct str * loopvar = vars_newname(g);
607
609
  w(g, "~Mfor _ in 0..");
608
610
  generate_AE(g, p->AE);
609
611
  writef(g, " {~+~N", p);
@@ -621,12 +623,13 @@ static void generate_repeat_or_atleast(struct generator * g, struct node * p, st
621
623
  writef(g, "~M'replab~I0: loop{~N~+", p);
622
624
 
623
625
  struct str * savevar = NULL;
624
- if (repeat_restore(g, p->left)) {
626
+ if (repeat_restore(p->left)) {
625
627
  savevar = vars_newname(g);
626
628
  write_savecursor(g, p, savevar);
627
629
  }
628
630
 
629
- g->failure_label = new_label(g);
631
+ int label = new_label(g);
632
+ g->failure_label = label;
630
633
  str_clear(g->failure_str);
631
634
  g->I[0] = g->failure_label;
632
635
  w(g, "~M'lab~I0: for _ in 0..1 {~N~+");
@@ -659,9 +662,9 @@ static void generate_repeat(struct generator * g, struct node * p) {
659
662
  }
660
663
 
661
664
  static void generate_atleast(struct generator * g, struct node * p) {
662
- struct str * loopvar = vars_newname(g);
663
-
664
665
  write_comment(g, p);
666
+
667
+ struct str * loopvar = vars_newname(g);
665
668
  g->B[0] = str_data(loopvar);
666
669
  w(g, "~Mlet mut ~B0 = ");
667
670
  generate_AE(g, p->AE);
@@ -681,12 +684,6 @@ static void generate_atleast(struct generator * g, struct node * p) {
681
684
  str_delete(loopvar);
682
685
  }
683
686
 
684
- static void generate_setmark(struct generator * g, struct node * p) {
685
- write_comment(g, p);
686
- g->V[0] = p->name;
687
- writef(g, "~M~V0 = env.cursor;~N", p);
688
- }
689
-
690
687
  static void generate_tomark(struct generator * g, struct node * p) {
691
688
  write_comment(g, p);
692
689
  g->S[0] = p->mode == m_forward ? ">" : "<";
@@ -700,15 +697,6 @@ static void generate_tomark(struct generator * g, struct node * p) {
700
697
  w(g, "~Menv.cursor = "); generate_AE(g, p->AE); writef(g, ";~N", p);
701
698
  }
702
699
 
703
- static void generate_atmark(struct generator * g, struct node * p) {
704
- write_comment(g, p);
705
- w(g, "~Mif env.cursor != "); generate_AE(g, p->AE); writef(g, " ", p);
706
- write_block_start(g);
707
- write_failure(g);
708
- write_block_end(g);
709
- g->unreachable = false;
710
- }
711
-
712
700
  static void generate_hop(struct generator * g, struct node * p) {
713
701
  write_comment(g, p);
714
702
  // Generate the AE to a temporary block so we can substitute it in
@@ -725,26 +713,12 @@ static void generate_hop(struct generator * g, struct node * p) {
725
713
  str_delete(ae);
726
714
  }
727
715
 
728
- static void generate_delete(struct generator * g, struct node * p) {
729
- write_comment(g, p);
730
- writef(g, "~Mif !env.slice_del() {~N"
731
- "~+~Mreturn false;~N~-"
732
- "~M}~N", p);
733
- }
734
-
735
716
  static void generate_tolimit(struct generator * g, struct node * p) {
736
717
  write_comment(g, p);
737
718
  g->S[0] = p->mode == m_forward ? "env.limit" : "env.limit_backward";
738
719
  writef(g, "~Menv.cursor = ~S0;~N", p);
739
720
  }
740
721
 
741
- static void generate_atlimit(struct generator * g, struct node * p) {
742
- write_comment(g, p);
743
- g->S[0] = p->mode == m_forward ? "env.limit" : "env.limit_backward";
744
- g->S[1] = p->mode == m_forward ? "<" : ">";
745
- write_failure_if(g, "env.cursor ~S1 ~S0", p);
746
- }
747
-
748
722
  static void generate_leftslice(struct generator * g, struct node * p) {
749
723
  write_comment(g, p);
750
724
  g->S[0] = p->mode == m_forward ? "env.bra" : "env.ket";
@@ -759,16 +733,12 @@ static void generate_rightslice(struct generator * g, struct node * p) {
759
733
 
760
734
  static void generate_assignto(struct generator * g, struct node * p) {
761
735
  write_comment(g, p);
762
- g->V[0] = p->name;
763
- writef(g, "~M~V0 = env.assign_to();~N", p);
736
+ writef(g, "~M~V = env.assign_to();~N", p);
764
737
  }
765
738
 
766
739
  static void generate_sliceto(struct generator * g, struct node * p) {
767
740
  write_comment(g, p);
768
- g->V[0] = p->name;
769
- writef(g, "~M~V0 = env.slice_to();~N"
770
- "~Mif ~V0.is_empty() {~N"
771
- "~+~Mreturn false;~N~-~M}~N", p);
741
+ writef(g, "~M~V = env.slice_to();~N", p);
772
742
  }
773
743
 
774
744
  static void generate_address(struct generator * g, struct node * p) {
@@ -786,8 +756,8 @@ static void generate_address(struct generator * g, struct node * p) {
786
756
  }
787
757
 
788
758
  static void generate_insert(struct generator * g, struct node * p, int style) {
789
- int keep_c = style == c_attach;
790
759
  write_comment(g, p);
760
+ int keep_c = style == c_attach;
791
761
  if (p->mode == m_backward) keep_c = !keep_c;
792
762
  if (keep_c) w(g, "~Mlet c = env.cursor;~N");
793
763
  w(g, "~Mlet (bra, ket) = (env.cursor, env.cursor);~N");
@@ -797,11 +767,12 @@ static void generate_insert(struct generator * g, struct node * p, int style) {
797
767
  if (keep_c) w(g, "~Menv.cursor = c;~N");
798
768
  }
799
769
 
800
- static void generate_assignfrom(struct generator * g, struct node * p) {
801
- int keep_c = p->mode == m_forward; /* like 'attach' */
802
-
770
+ static void generate_stringassign(struct generator * g, struct node * p) {
803
771
  write_comment(g, p);
804
- if (keep_c) writef(g, "~Mlet c = env.cursor;~N", p);
772
+ int keep_c = p->mode == m_forward; /* like 'attach' */
773
+ if (keep_c) {
774
+ writef(g, "~Mlet c = env.cursor;~N", p);
775
+ }
805
776
  /* Copying limits and cursors is necessary here because the rust
806
777
  * borrowchecker does not like taking something from someone you are about
807
778
  * to mutate... */
@@ -813,20 +784,26 @@ static void generate_assignfrom(struct generator * g, struct node * p) {
813
784
  writef(g, "~Menv.insert(bra, ket, ", p);
814
785
  generate_address(g, p);
815
786
  writef(g, ");~N", p);
816
- if (keep_c) w(g, "~Menv.cursor = c;~N");
787
+ if (keep_c) {
788
+ w(g, "~Menv.cursor = c;~N");
789
+ }
817
790
  }
818
791
 
819
792
  static void generate_slicefrom(struct generator * g, struct node * p) {
820
793
  write_comment(g, p);
821
- w(g, "~Mif !env.slice_from(");
794
+ if (p->literalstring && SIZE(p->literalstring) == 0) {
795
+ w(g, "~Menv.slice_del();~N");
796
+ return;
797
+ }
798
+ w(g, "~Menv.slice_from(");
822
799
  generate_address(g, p);
823
- writef(g, ") {~N"
824
- "~+~Mreturn false;~N~-~M}~N", p);
800
+ w(g, ");~N");
825
801
  }
826
802
 
827
803
  static void generate_setlimit(struct generator * g, struct node * p) {
828
- struct str * varname = vars_newname(g);
829
804
  write_comment(g, p);
805
+ struct str * varname = vars_newname(g);
806
+
830
807
  if (p->left && p->left->type == c_tomark) {
831
808
  /* Special case for:
832
809
  *
@@ -838,6 +815,7 @@ static void generate_setlimit(struct generator * g, struct node * p) {
838
815
  */
839
816
  struct node * q = p->left;
840
817
  write_comment(g, q);
818
+
841
819
  g->S[0] = q->mode == m_forward ? ">" : "<";
842
820
  w(g, "~Mif env.cursor ~S0 "); generate_AE(g, q->AE); w(g, " ");
843
821
  write_block_start(g);
@@ -847,23 +825,26 @@ static void generate_setlimit(struct generator * g, struct node * p) {
847
825
 
848
826
  g->B[0] = str_data(varname);
849
827
  if (p->mode == m_forward) {
850
- w(g, "~Mlet ~B0 = env.limit - env.cursor;~N");
828
+ w(g, "~Mlet mut ~B0 = env.limit;~N");
851
829
  w(g, "~Menv.limit = ");
830
+ generate_AE(g, q->AE);
831
+ w(g, ";~N");
832
+ w(g, "~M~B0 -= env.limit;~N");
852
833
  } else {
853
834
  w(g, "~Mlet ~B0 = env.limit_backward;~N");
854
835
  w(g, "~Menv.limit_backward = ");
836
+ generate_AE(g, q->AE);
837
+ w(g, ";~N");
855
838
  }
856
- generate_AE(g, q->AE);
857
- writef(g, ";~N", q);
858
839
 
859
840
  if (p->mode == m_forward) {
860
841
  str_assign(g->failure_str, "env.limit += ");
861
842
  str_append(g->failure_str, varname);
862
- str_append_string(g->failure_str, ";");
843
+ str_append_ch(g->failure_str, ';');
863
844
  } else {
864
845
  str_assign(g->failure_str, "env.limit_backward = ");
865
846
  str_append(g->failure_str, varname);
866
- str_append_string(g->failure_str, ";");
847
+ str_append_ch(g->failure_str, ';');
867
848
  }
868
849
  } else {
869
850
  struct str * savevar = vars_newname(g);
@@ -885,11 +866,11 @@ static void generate_setlimit(struct generator * g, struct node * p) {
885
866
  if (p->mode == m_forward) {
886
867
  str_assign(g->failure_str, "env.limit += ");
887
868
  str_append(g->failure_str, varname);
888
- str_append_string(g->failure_str, ";");
869
+ str_append_ch(g->failure_str, ';');
889
870
  } else {
890
871
  str_assign(g->failure_str, "env.limit_backward = ");
891
872
  str_append(g->failure_str, varname);
892
- str_append_string(g->failure_str, ";");
873
+ str_append_ch(g->failure_str, ';');
893
874
  }
894
875
  }
895
876
  str_delete(savevar);
@@ -904,6 +885,7 @@ static void generate_setlimit(struct generator * g, struct node * p) {
904
885
  write_newline(g);
905
886
  }
906
887
  }
888
+
907
889
  str_delete(varname);
908
890
  }
909
891
 
@@ -912,36 +894,64 @@ static void generate_setlimit(struct generator * g, struct node * p) {
912
894
  static void generate_dollar(struct generator * g, struct node * p) {
913
895
  write_comment(g, p);
914
896
 
897
+ int a0 = g->failure_label;
898
+ struct str * a1 = str_copy(g->failure_str);
899
+ int label = new_label(g);
900
+ g->failure_label = label;
901
+ str_clear(g->failure_str);
902
+
915
903
  struct str * savevar = vars_newname(g);
916
- g->V[0] = p->name;
917
904
  g->B[0] = str_data(savevar);
918
905
  writef(g, "~Mlet ~B0 = env.clone();~N"
919
- "~Menv.set_current_s(~V0.clone());~N"
906
+ "~Menv.set_current_s(~V.clone());~N"
920
907
  "~Menv.cursor = 0;~N"
921
908
  "~Menv.limit = env.current.len() as i32;~N", p);
909
+ if (p->left->possible_signals == -1) {
910
+ /* Assume failure. */
911
+ w(g, "~Mlet mut ~B0_f = true;~N");
912
+ }
913
+
914
+ wsetlab_begin(g, g->failure_label);
915
+
922
916
  generate(g, p->left);
923
- if (!g->unreachable) {
924
- g->V[0] = p->name;
917
+
918
+ if (!g->unreachable && p->left->possible_signals == -1) {
919
+ /* Mark success. */
925
920
  g->B[0] = str_data(savevar);
926
- /* Update string variable. */
927
- w(g, "~M~V0 = env.current.clone().into_owned();~N");
928
- /* Reset env */
929
- w(g, "~M*env = ~B0;~N");
921
+ w(g, "~M~B0_f = false;~N");
922
+ }
923
+
924
+ wsetlab_end(g, g->failure_label);
925
+
926
+ g->failure_label = a0;
927
+ str_delete(g->failure_str);
928
+ g->failure_str = a1;
929
+
930
+ g->B[0] = str_data(savevar);
931
+ /* Update string variable; restore env. */
932
+ writef(g, "~M~V = env.current.clone().into_owned();~N"
933
+ "~M*env = ~B0;~N", p);
934
+
935
+ if (p->left->possible_signals == 0) {
936
+ // p->left always signals f.
937
+ write_failure(g);
938
+ } else if (p->left->possible_signals == -1) {
939
+ write_failure_if(g, "~B0_f", p);
930
940
  }
941
+
931
942
  str_delete(savevar);
932
943
  }
933
944
 
934
945
  static void generate_integer_assign(struct generator * g, struct node * p, const char * s) {
935
946
  write_comment(g, p);
936
- g->V[0] = p->name;
937
947
  g->S[0] = s;
938
- w(g, "~M~V0 ~S0 "); generate_AE(g, p->AE); w(g, ";~N");
948
+ writef(g, "~M~V ~S0 ", p); generate_AE(g, p->AE); w(g, ";~N");
939
949
  }
940
950
 
941
951
  static void generate_integer_test(struct generator * g, struct node * p) {
942
952
  write_comment(g, p);
943
953
  int relop = p->type;
944
- int optimise_to_return = (g->failure_label == x_return && p->right && p->right->type == c_functionend);
954
+ int optimise_to_return = tailcallable(g, p);
945
955
  if (optimise_to_return) {
946
956
  w(g, "~Mreturn ");
947
957
  p->right = NULL;
@@ -951,12 +961,12 @@ static void generate_integer_test(struct generator * g, struct node * p) {
951
961
  relop ^= 1;
952
962
  }
953
963
  generate_AE(g, p->left);
954
- // Relational operators are the same as C.
955
- write_c_relop(g, relop);
964
+ write_relop(g, relop);
956
965
  generate_AE(g, p->AE);
957
966
  if (optimise_to_return) {
958
967
  w(g, "~N");
959
968
  } else {
969
+ write_char(g, ' ');
960
970
  write_block_start(g);
961
971
  write_failure(g);
962
972
  write_block_end(g);
@@ -965,24 +975,30 @@ static void generate_integer_test(struct generator * g, struct node * p) {
965
975
  }
966
976
 
967
977
  static void generate_call(struct generator * g, struct node * p) {
968
- int signals = check_possible_signals_list(g, p->name->definition, c_define, 0);
978
+ int signals = p->name->definition->possible_signals;
969
979
  write_comment(g, p);
970
- g->V[0] = p->name;
971
- if (g->failure_label == x_return &&
972
- (signals == 0 || (p->right && p->right->type == c_functionend))) {
973
- /* Always fails or tail call. */
974
- writef(g, "~Mreturn ~W0(env, context);~N", p);
980
+ if (tailcallable(g, p)) {
981
+ /* Tail call. */
982
+ writef(g, "~Mreturn ~W(env, context);~N", p);
983
+ p->right = NULL;
984
+ g->unreachable = true;
985
+ return;
986
+ }
987
+ if (just_return_on_fail(g) && signals == 0) {
988
+ /* Always fails. */
989
+ writef(g, "~Mreturn ~W(env, context);~N", p);
990
+ g->unreachable = true;
975
991
  return;
976
992
  }
977
993
  if (signals == 1) {
978
994
  /* Always succeeds. */
979
- writef(g, "~M~W0(env, context);~N", p);
995
+ writef(g, "~M~W(env, context);~N", p);
980
996
  } else if (signals == 0) {
981
997
  /* Always fails. */
982
- writef(g, "~M~W0(env, context);~N", p);
998
+ writef(g, "~M~W(env, context);~N", p);
983
999
  write_failure(g);
984
1000
  } else {
985
- write_failure_if(g, "!~W0(env, context)", p);
1001
+ write_failure_if(g, "!~W(env, context)", p);
986
1002
  }
987
1003
  }
988
1004
 
@@ -992,40 +1008,57 @@ static void generate_grouping(struct generator * g, struct node * p, int complem
992
1008
  struct grouping * q = p->name->grouping;
993
1009
  g->S[0] = p->mode == m_forward ? "" : "_b";
994
1010
  g->S[1] = complement ? "out" : "in";
995
- g->V[0] = p->name;
996
1011
  g->I[0] = q->smallest_ch;
997
1012
  g->I[1] = q->largest_ch;
998
- write_failure_if(g, "!env.~S1_grouping~S0(~W0, ~I0, ~I1)", p);
1013
+ if (tailcallable(g, p)) {
1014
+ writef(g, "~Mreturn env.~S1_grouping~S0(~W, ~I0, ~I1);~N", p);
1015
+ p->right = NULL;
1016
+ } else {
1017
+ write_failure_if(g, "!env.~S1_grouping~S0(~W, ~I0, ~I1)", p);
1018
+ }
999
1019
  }
1000
1020
 
1001
1021
  static void generate_namedstring(struct generator * g, struct node * p) {
1002
1022
  write_comment(g, p);
1003
1023
  g->S[0] = p->mode == m_forward ? "" : "_b";
1004
- g->V[0] = p->name;
1005
- write_failure_if(g, "!env.eq_s~S0(&~V0)", p);
1024
+ if (tailcallable(g, p)) {
1025
+ writef(g, "~Mreturn env.eq_s~S0(&~V);~N", p);
1026
+ p->right = NULL;
1027
+ } else {
1028
+ write_failure_if(g, "!env.eq_s~S0(&~V)", p);
1029
+ }
1006
1030
  }
1007
1031
 
1008
1032
  static void generate_literalstring(struct generator * g, struct node * p) {
1009
- symbol * b = p->literalstring;
1010
1033
  write_comment(g, p);
1011
1034
  g->S[0] = p->mode == m_forward ? "" : "_b";
1012
- g->L[0] = b;
1013
- write_failure_if(g, "!env.eq_s~S0(&~L0)", p);
1035
+ if (tailcallable(g, p)) {
1036
+ writef(g, "~Mreturn env.eq_s~S0(&~L);~N", p);
1037
+ p->right = NULL;
1038
+ } else {
1039
+ write_failure_if(g, "!env.eq_s~S0(&~L)", p);
1040
+ }
1014
1041
  }
1015
1042
 
1016
1043
  static void generate_setup_context(struct generator * g) {
1017
1044
  w(g, "~Mlet mut context = &mut Context {~+~N");
1018
1045
  for (struct name * q = g->analyser->names; q; q = q->next) {
1019
- g->V[0] = q;
1046
+ if (q->local_to) continue;
1020
1047
  switch (q->type) {
1021
1048
  case t_string:
1022
- w(g, "~M~W0: String::new(),~N");
1049
+ write_margin(g);
1050
+ write_varname(g, q);
1051
+ w(g, ": String::new(),~N");
1023
1052
  break;
1024
1053
  case t_integer:
1025
- w(g, "~M~W0: 0,~N");
1054
+ write_margin(g);
1055
+ write_varname(g, q);
1056
+ w(g, ": 0,~N");
1026
1057
  break;
1027
1058
  case t_boolean:
1028
- w(g, "~M~W0: false,~N");
1059
+ write_margin(g);
1060
+ write_varname(g, q);
1061
+ w(g, ": false,~N");
1029
1062
  break;
1030
1063
  }
1031
1064
  }
@@ -1034,23 +1067,52 @@ static void generate_setup_context(struct generator * g) {
1034
1067
 
1035
1068
  static void generate_define(struct generator * g, struct node * p) {
1036
1069
  struct name * q = p->name;
1037
- if (q->type == t_routine && !q->used) return;
1038
1070
 
1039
1071
  write_newline(g);
1040
1072
  write_comment(g, p);
1041
1073
 
1042
- g->V[0] = q;
1043
1074
  if (q->type == t_routine) {
1044
- w(g, "~Mfn ~W0(env: &mut SnowballEnv, context: &mut Context) -> bool {~+~N");
1075
+ writef(g, "~Mfn ~W(env: &mut SnowballEnv, context: &mut Context) -> bool {~+~N", p);
1045
1076
  } else {
1046
- w(g, "~Mpub fn ~W0(env: &mut SnowballEnv) -> bool {~+~N");
1077
+ writef(g, "~Mpub fn ~E(env: &mut SnowballEnv) -> bool {~+~N", p);
1047
1078
  generate_setup_context(g);
1079
+ if (q->used != q->definition) {
1080
+ // This external needs to be callable as a routine, so generate
1081
+ // the actual code like a routine with an external which just
1082
+ // forwards to that.
1083
+ writef(g, "~Mreturn ~W(env, context);~N", p);
1084
+ w(g, "~-~M}~N");
1085
+ writef(g, "~Mfn ~W(env: &mut SnowballEnv, context: &mut Context) -> bool {~+~N", p);
1086
+ }
1048
1087
  }
1049
- if (p->amongvar_needed) w(g, "~Mlet mut among_var;~N");
1050
1088
 
1051
- /* Save output. */
1052
- struct str * saved_output = g->outbuf;
1053
- g->outbuf = str_new();
1089
+ if (q->amongvar_needed) {
1090
+ w(g, "~Mlet mut among_var;~N");
1091
+ }
1092
+
1093
+ /* Declare localised variables. */
1094
+ for (struct name * name = g->analyser->names; name; name = name->next) {
1095
+ if (name->local_to == q) {
1096
+ switch (name->type) {
1097
+ case t_string:
1098
+ // String variables not localised for Rust currently.
1099
+ w(g, "~Mlet mut ");
1100
+ write_varname(g, name);
1101
+ w(g, " : String;~N");
1102
+ break;
1103
+ case t_integer:
1104
+ w(g, "~Mlet mut ");
1105
+ write_varname(g, name);
1106
+ w(g, " : i32;~N");
1107
+ break;
1108
+ case t_boolean:
1109
+ w(g, "~Mlet mut ");
1110
+ write_varname(g, name);
1111
+ w(g, " : bool;~N");
1112
+ break;
1113
+ }
1114
+ }
1115
+ }
1054
1116
 
1055
1117
  g->next_label = 0;
1056
1118
  g->var_number = 0;
@@ -1058,21 +1120,16 @@ static void generate_define(struct generator * g, struct node * p) {
1058
1120
  str_clear(g->failure_str);
1059
1121
  g->failure_label = x_return;
1060
1122
  g->unreachable = false;
1061
- int signals = check_possible_signals_list(g, p->left, c_define, 0);
1062
1123
 
1063
1124
  /* Generate function body. */
1064
1125
  generate(g, p->left);
1065
1126
  if (p->left->right) {
1066
1127
  assert(p->left->right->type == c_functionend);
1067
- if (signals) {
1128
+ if (p->left->possible_signals) {
1068
1129
  generate(g, p->left->right);
1069
1130
  }
1070
1131
  }
1071
1132
  w(g, "~-~M}~N");
1072
-
1073
- str_append(saved_output, g->outbuf);
1074
- str_delete(g->outbuf);
1075
- g->outbuf = saved_output;
1076
1133
  }
1077
1134
 
1078
1135
  static void generate_functionend(struct generator * g, struct node * p) {
@@ -1139,13 +1196,16 @@ static void generate_substring(struct generator * g, struct node * p) {
1139
1196
  }
1140
1197
  }
1141
1198
 
1142
- if (block != -1 || n_cases <= 2) {
1199
+ int pre_check = (block != -1 || n_cases <= 2);
1200
+ if (pre_check) {
1143
1201
  char buf[64];
1144
1202
  g->I[2] = block;
1145
1203
  g->I[3] = bitmap;
1146
1204
  g->I[4] = shortest_size - 1;
1147
1205
  if (p->mode == m_forward) {
1148
- sprintf(buf, "env.current.as_bytes()[(env.cursor + %d) as usize]", shortest_size - 1);
1206
+ checked_snprintf(buf, sizeof(buf),
1207
+ "env.current.as_bytes()[(env.cursor + %d) as usize]",
1208
+ shortest_size - 1);
1149
1209
  g->S[1] = buf;
1150
1210
  if (shortest_size == 1) {
1151
1211
  writef(g, "~Mif (env.cursor >= env.limit", p);
@@ -1160,12 +1220,8 @@ static void generate_substring(struct generator * g, struct node * p) {
1160
1220
  writef(g, "~Mif (env.cursor - ~I4 <= env.limit_backward", p);
1161
1221
  }
1162
1222
  }
1163
- if (n_cases == 0) {
1164
- /* We get this for the degenerate case: among ( '' )
1165
- * This doesn't seem to be a useful construct, but it is
1166
- * syntactically valid.
1167
- */
1168
- } else if (n_cases == 1) {
1223
+ assert(n_cases > 0);
1224
+ if (n_cases == 1) {
1169
1225
  g->I[4] = cases[0];
1170
1226
  writef(g, " || ~S1 as u8 != ~I4 as u8", p);
1171
1227
  } else if (n_cases == 2) {
@@ -1176,7 +1232,7 @@ static void generate_substring(struct generator * g, struct node * p) {
1176
1232
  writef(g, " || ~S1 as u8 >> 5 != ~I2 as u8 || ((~I3 as i32 >> (~S1 as u8 & 0x1f)) & 1) == 0", p);
1177
1233
  }
1178
1234
  write_string(g, ") ");
1179
- if (empty_case != -1) {
1235
+ if (empty_case != -1 && !among_cases[empty_case].function) {
1180
1236
  /* If the among includes the empty string, it can never fail
1181
1237
  * so not matching the bitmap means we match the empty string.
1182
1238
  */
@@ -1198,12 +1254,35 @@ static void generate_substring(struct generator * g, struct node * p) {
1198
1254
  if (!x->always_matches) {
1199
1255
  write_failure_if(g, "among_var == 0", p);
1200
1256
  }
1201
- } else if (x->always_matches) {
1257
+ if (block_opened) write_block_end(g);
1258
+ return;
1259
+ }
1260
+
1261
+ if (pre_check && !x->function_count) {
1262
+ // If all cases are one symbol long (so one byte of UTF-8, one
1263
+ // character long in fixed-width encodings) then we don't need to call
1264
+ // the helper and can just inc/dec the cursor by 1.
1265
+ if (x->longest_size == 1 && !x->always_matches) {
1266
+ if (p->mode == m_forward) {
1267
+ w(g, "~Menv.cursor += 1;~N");
1268
+ } else {
1269
+ w(g, "~Menv.cursor -= 1;~N");
1270
+ }
1271
+ // Suppress generating table for this among.
1272
+ x->used = false;
1273
+ return;
1274
+ }
1275
+ }
1276
+
1277
+ if (x->always_matches) {
1202
1278
  writef(g, "~Menv.find_among~S0(A_~I0, context);~N", p);
1279
+ } else if (x->command_count == 0 && tailcallable(g, p)) {
1280
+ writef(g, "~Mreturn env.find_among~S0(A_~I0, context) != 0;~N", p);
1281
+ x->node->right = NULL;
1282
+ g->unreachable = true;
1203
1283
  } else {
1204
1284
  write_failure_if(g, "env.find_among~S0(A_~I0, context) == 0", p);
1205
1285
  }
1206
- if (block_opened) write_block_end(g);
1207
1286
  }
1208
1287
 
1209
1288
  static void generate_among(struct generator * g, struct node * p) {
@@ -1232,10 +1311,24 @@ static void generate_among(struct generator * g, struct node * p) {
1232
1311
  }
1233
1312
  }
1234
1313
 
1235
- static void generate_booltest(struct generator * g, struct node * p) {
1314
+ static void generate_booltest(struct generator * g, struct node * p, int inverted) {
1236
1315
  write_comment(g, p);
1237
- g->V[0] = p->name;
1238
- write_failure_if(g, "!~V0", p);
1316
+ if (tailcallable(g, p)) {
1317
+ // Optimise at end of function.
1318
+ if (inverted) {
1319
+ writef(g, "~Mreturn !~V;~N", p);
1320
+ } else {
1321
+ writef(g, "~Mreturn ~V;~N", p);
1322
+ }
1323
+ p->right = NULL;
1324
+ g->unreachable = true;
1325
+ return;
1326
+ }
1327
+ if (inverted) {
1328
+ write_failure_if(g, "~V", p);
1329
+ } else {
1330
+ write_failure_if(g, "!~V", p);
1331
+ }
1239
1332
  }
1240
1333
 
1241
1334
  static void generate_false(struct generator * g, struct node * p) {
@@ -1280,25 +1373,21 @@ static void generate(struct generator * g, struct node * p) {
1280
1373
  case c_repeat: generate_repeat(g, p); break;
1281
1374
  case c_loop: generate_loop(g, p); break;
1282
1375
  case c_atleast: generate_atleast(g, p); break;
1283
- case c_setmark: generate_setmark(g, p); break;
1284
1376
  case c_tomark: generate_tomark(g, p); break;
1285
- case c_atmark: generate_atmark(g, p); break;
1286
1377
  case c_hop: generate_hop(g, p); break;
1287
- case c_delete: generate_delete(g, p); break;
1288
1378
  case c_next: generate_next(g, p); break;
1289
1379
  case c_tolimit: generate_tolimit(g, p); break;
1290
- case c_atlimit: generate_atlimit(g, p); break;
1291
1380
  case c_leftslice: generate_leftslice(g, p); break;
1292
1381
  case c_rightslice: generate_rightslice(g, p); break;
1293
1382
  case c_assignto: generate_assignto(g, p); break;
1294
1383
  case c_sliceto: generate_sliceto(g, p); break;
1295
- case c_assign: generate_assignfrom(g, p); break;
1384
+ case c_stringassign: generate_stringassign(g, p); break;
1296
1385
  case c_insert:
1297
1386
  case c_attach: generate_insert(g, p, p->type); break;
1298
1387
  case c_slicefrom: generate_slicefrom(g, p); break;
1299
1388
  case c_setlimit: generate_setlimit(g, p); break;
1300
1389
  case c_dollar: generate_dollar(g, p); break;
1301
- case c_mathassign: generate_integer_assign(g, p, "="); break;
1390
+ case c_assign: generate_integer_assign(g, p, "="); break;
1302
1391
  case c_plusassign: generate_integer_assign(g, p, "+="); break;
1303
1392
  case c_minusassign: generate_integer_assign(g, p, "-="); break;
1304
1393
  case c_multiplyassign:generate_integer_assign(g, p, "*="); break;
@@ -1318,7 +1407,8 @@ static void generate(struct generator * g, struct node * p) {
1318
1407
  case c_literalstring: generate_literalstring(g, p); break;
1319
1408
  case c_among: generate_among(g, p); break;
1320
1409
  case c_substring: generate_substring(g, p); break;
1321
- case c_booltest: generate_booltest(g, p); break;
1410
+ case c_booltest: generate_booltest(g, p, false); break;
1411
+ case c_not_booltest: generate_booltest(g, p, true); break;
1322
1412
  case c_false: generate_false(g, p); break;
1323
1413
  case c_true: break;
1324
1414
  case c_debug: generate_debug(g, p); break;
@@ -1346,7 +1436,7 @@ static void generate_allow_warnings(struct generator * g) {
1346
1436
 
1347
1437
  static void generate_class_begin(struct generator * g) {
1348
1438
  w(g, "use snowball::SnowballEnv;~N");
1349
- if (g->analyser->among_count > 0) {
1439
+ if (g->analyser->amongs) {
1350
1440
  w(g, "use snowball::Among;~N~N");
1351
1441
  }
1352
1442
  }
@@ -1359,37 +1449,40 @@ static void generate_among_table(struct generator * g, struct among * x) {
1359
1449
  g->I[0] = x->number;
1360
1450
  g->I[1] = x->literalstring_count;
1361
1451
 
1362
- w(g, "~Mstatic A_~I0: &'static [Among<Context>; ~I1] = &[~N~+");
1452
+ w(g, "~N~Mstatic A_~I0: &'static [Among<Context>; ~I1] = &[~N~+");
1363
1453
  for (int i = 0; i < x->literalstring_count; i++) {
1364
1454
  g->I[0] = v[i].i;
1365
1455
  g->I[1] = v[i].result;
1366
- g->L[0] = v[i].b;
1367
- g->S[0] = ",";
1368
1456
 
1369
- w(g, "~MAmong(~L0, ~I0, ~I1, ");
1457
+ w(g, "~MAmong(");
1458
+ write_literal_string(g, v[i].b);
1459
+ w(g, ", ~I0, ~I1, ");
1370
1460
  if (v[i].function != NULL) {
1371
1461
  w(g, "Some(&");
1372
1462
  write_varname(g, v[i].function);
1373
1463
  w(g, ")");
1374
1464
  } else {
1375
- w(g, "None");
1465
+ w(g, "None");
1376
1466
  }
1377
- w(g, ")~S0~N");
1467
+ w(g, "),~N");
1378
1468
  }
1379
- w(g, "~-~M];~N~N");
1469
+ w(g, "~-~M];~N");
1380
1470
  }
1381
1471
 
1382
1472
  static void generate_amongs(struct generator * g) {
1473
+ struct str * s = g->outbuf;
1474
+ g->outbuf = g->declarations;
1383
1475
  for (struct among * x = g->analyser->amongs; x; x = x->next) {
1384
- generate_among_table(g, x);
1476
+ if (x->used) generate_among_table(g, x);
1385
1477
  }
1478
+ g->outbuf = s;
1386
1479
  }
1387
1480
 
1388
- static void set_bit(symbol * b, int i) { b[i/8] |= 1 << i%8; }
1481
+ static void set_bit(symbol * b, int i) { b[i >> 3] |= 1 << (i & 7); }
1389
1482
 
1390
1483
  static void generate_grouping_table(struct generator * g, struct grouping * q) {
1391
1484
  int range = q->largest_ch - q->smallest_ch + 1;
1392
- int size = (range + 7)/ 8; /* assume 8 bits per symbol */
1485
+ int size = (range + 7) / 8; /* assume 8 bits per symbol */
1393
1486
  symbol * b = q->b;
1394
1487
  symbol * map = create_b(size);
1395
1488
 
@@ -1397,39 +1490,48 @@ static void generate_grouping_table(struct generator * g, struct grouping * q) {
1397
1490
 
1398
1491
  for (int i = 0; i < SIZE(b); i++) set_bit(map, b[i] - q->smallest_ch);
1399
1492
 
1400
- g->V[0] = q->name;
1401
1493
  g->I[0] = size;
1402
- w(g, "~Mstatic ~W0: &'static [u8; ~I0] = &[");
1494
+ w(g, "~N~Mstatic ");
1495
+ write_varname(g, q->name);
1496
+ w(g, ": &'static [u8; ~I0] = &[");
1403
1497
  for (int i = 0; i < size; i++) {
1498
+ if (i) w(g, ", ");
1404
1499
  write_int(g, map[i]);
1405
- if (i < size - 1) w(g, ", ");
1406
1500
  }
1407
- w(g, "];~N~N");
1501
+ w(g, "];~N");
1408
1502
 
1409
1503
  lose_b(map);
1410
1504
  }
1411
1505
 
1412
1506
  static void generate_groupings(struct generator * g) {
1507
+ struct str * s = g->outbuf;
1508
+ g->outbuf = g->declarations;
1413
1509
  for (struct grouping * q = g->analyser->groupings; q; q = q->next) {
1414
- if (q->name->used)
1415
- generate_grouping_table(g, q);
1510
+ generate_grouping_table(g, q);
1416
1511
  }
1512
+ g->outbuf = s;
1417
1513
  }
1418
1514
 
1419
1515
  static void generate_members(struct generator * g) {
1420
1516
  w(g, "#[derive(Clone)]~N");
1421
1517
  w(g, "struct Context {~+~N");
1422
1518
  for (struct name * q = g->analyser->names; q; q = q->next) {
1423
- g->V[0] = q;
1519
+ if (q->local_to) continue;
1424
1520
  switch (q->type) {
1425
1521
  case t_string:
1426
- w(g, "~M~W0: String,~N");
1522
+ write_margin(g);
1523
+ write_varname(g, q);
1524
+ w(g, ": String,~N");
1427
1525
  break;
1428
1526
  case t_integer:
1429
- w(g, "~M~W0: i32,~N");
1527
+ write_margin(g);
1528
+ write_varname(g, q);
1529
+ w(g, ": i32,~N");
1430
1530
  break;
1431
1531
  case t_boolean:
1432
- w(g, "~M~W0: bool,~N");
1532
+ write_margin(g);
1533
+ write_varname(g, q);
1534
+ w(g, ": bool,~N");
1433
1535
  break;
1434
1536
  }
1435
1537
  }
@@ -1455,13 +1557,20 @@ extern void generate_program_rust(struct generator * g) {
1455
1557
  }
1456
1558
  generate_class_begin(g);
1457
1559
 
1458
- generate_amongs(g);
1459
- generate_groupings(g);
1460
-
1461
1560
  generate_members(g);
1561
+
1562
+ g->declarations = g->outbuf;
1563
+ g->outbuf = str_new();
1564
+
1462
1565
  generate_methods(g);
1463
1566
 
1567
+ generate_amongs(g);
1568
+ generate_groupings(g);
1569
+
1570
+ output_str(g->options->output_src, g->declarations);
1571
+ str_delete(g->declarations);
1464
1572
  output_str(g->options->output_src, g->outbuf);
1465
- str_delete(g->failure_str);
1466
1573
  str_delete(g->outbuf);
1574
+
1575
+ str_delete(g->failure_str);
1467
1576
  }