mittens 0.3.0 → 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 (174) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/Gemfile +2 -1
  4. data/README.md +2 -2
  5. data/Rakefile +12 -5
  6. data/ext/mittens/extconf.rb +3 -1
  7. data/lib/mittens/version.rb +1 -1
  8. data/vendor/snowball/.github/workflows/ci.yml +144 -17
  9. data/vendor/snowball/.github/workflows/coverage.yml +117 -0
  10. data/vendor/snowball/.github/workflows/runtime-tests.yml +26 -0
  11. data/vendor/snowball/.gitignore +33 -7
  12. data/vendor/snowball/CONTRIBUTING.rst +7 -0
  13. data/vendor/snowball/COPYING +1 -1
  14. data/vendor/snowball/GNUmakefile +736 -298
  15. data/vendor/snowball/NEWS +1394 -7
  16. data/vendor/snowball/README.rst +8 -8
  17. data/vendor/snowball/ada/generate/generate.adb +5 -5
  18. data/vendor/snowball/ada/src/stemmer.adb +177 -188
  19. data/vendor/snowball/ada/src/stemmer.ads +86 -89
  20. data/vendor/snowball/ada/src/stemwords.adb +21 -5
  21. data/vendor/snowball/algorithms/czech.sbl +255 -0
  22. data/vendor/snowball/algorithms/danish.sbl +22 -10
  23. data/vendor/snowball/algorithms/english.sbl +7 -4
  24. data/vendor/snowball/algorithms/esperanto.sbl +6 -7
  25. data/vendor/snowball/algorithms/estonian.sbl +9 -4
  26. data/vendor/snowball/algorithms/finnish.sbl +33 -21
  27. data/vendor/snowball/algorithms/german.sbl +5 -0
  28. data/vendor/snowball/algorithms/indonesian.sbl +115 -96
  29. data/vendor/snowball/algorithms/italian.sbl +26 -1
  30. data/vendor/snowball/algorithms/lithuanian.sbl +13 -13
  31. data/vendor/snowball/algorithms/norwegian.sbl +17 -6
  32. data/vendor/snowball/algorithms/persian.sbl +387 -0
  33. data/vendor/snowball/algorithms/polish.sbl +177 -0
  34. data/vendor/snowball/algorithms/sesotho.sbl +115 -0
  35. data/vendor/snowball/algorithms/turkish.sbl +4 -4
  36. data/vendor/snowball/compiler/analyser.c +2002 -711
  37. data/vendor/snowball/compiler/driver.c +460 -298
  38. data/vendor/snowball/compiler/generator.c +439 -1965
  39. data/vendor/snowball/compiler/generator_ada.c +605 -430
  40. data/vendor/snowball/compiler/generator_c.c +2227 -0
  41. data/vendor/snowball/compiler/generator_csharp.c +365 -274
  42. data/vendor/snowball/compiler/generator_dart.c +1476 -0
  43. data/vendor/snowball/compiler/generator_go.c +348 -270
  44. data/vendor/snowball/compiler/generator_java.c +330 -233
  45. data/vendor/snowball/compiler/generator_js.c +534 -385
  46. data/vendor/snowball/compiler/generator_pascal.c +361 -320
  47. data/vendor/snowball/compiler/generator_php.c +1445 -0
  48. data/vendor/snowball/compiler/generator_python.c +399 -299
  49. data/vendor/snowball/compiler/generator_rust.c +370 -261
  50. data/vendor/snowball/compiler/generator_zig.c +1474 -0
  51. data/vendor/snowball/compiler/header.h +153 -86
  52. data/vendor/snowball/compiler/space.c +121 -63
  53. data/vendor/snowball/compiler/tokeniser.c +286 -182
  54. data/vendor/snowball/compiler/tokens.h +71 -0
  55. data/vendor/snowball/csharp/Snowball/Among.cs +14 -26
  56. data/vendor/snowball/csharp/Snowball/AssemblyInfo.cs +3 -3
  57. data/vendor/snowball/csharp/Snowball/Stemmer.cs +41 -45
  58. data/vendor/snowball/csharp/Stemwords/Program.cs +20 -14
  59. data/vendor/snowball/cxx/.gitignore +4 -0
  60. data/vendor/snowball/cxx/generate_algorithms.pl +87 -0
  61. data/vendor/snowball/cxx/stemmer.h +12 -0
  62. data/vendor/snowball/cxx/stemwords.cxx +176 -0
  63. data/vendor/snowball/cxx/utilities.cxx +2 -0
  64. data/vendor/snowball/dart/.gitignore +4 -0
  65. data/vendor/snowball/dart/analysis_options.yaml +1 -0
  66. data/vendor/snowball/dart/example/test_app.dart +65 -0
  67. data/vendor/snowball/dart/generate_algorithms.pl +21 -0
  68. data/vendor/snowball/dart/lib/snowball.dart +18 -0
  69. data/vendor/snowball/dart/lib/src/snowball.dart +339 -0
  70. data/vendor/snowball/dart/pubspec.yaml +17 -0
  71. data/vendor/snowball/doc/libstemmer_dart_README +37 -0
  72. data/vendor/snowball/doc/libstemmer_js_README +2 -2
  73. data/vendor/snowball/doc/libstemmer_php_README +38 -0
  74. data/vendor/snowball/doc/libstemmer_python_README +3 -3
  75. data/vendor/snowball/examples/stemwords.c +18 -3
  76. data/vendor/snowball/go/README.md +12 -4
  77. data/vendor/snowball/go/env.go +12 -14
  78. data/vendor/snowball/go/stemwords/main.go +2 -1
  79. data/vendor/snowball/java/org/tartarus/snowball/CharArraySequence.java +36 -0
  80. data/vendor/snowball/java/org/tartarus/snowball/SnowballProgram.java +17 -34
  81. data/vendor/snowball/java/org/tartarus/snowball/SnowballStemmer.java +0 -2
  82. data/vendor/snowball/javascript/base-stemmer.js +219 -252
  83. data/vendor/snowball/javascript/stemwords.js +86 -58
  84. data/vendor/snowball/libstemmer/mkmodules.pl +1 -1
  85. data/vendor/snowball/libstemmer/modules.txt +4 -0
  86. data/vendor/snowball/pascal/SnowballProgram.pas +18 -31
  87. data/vendor/snowball/php/base-stemmer.php +453 -0
  88. data/vendor/snowball/php/stemwords.php +25 -0
  89. data/vendor/snowball/python/create_init.py +16 -21
  90. data/vendor/snowball/python/pyproject.toml +3 -0
  91. data/vendor/snowball/python/setup.py +5 -7
  92. data/vendor/snowball/python/snowballstemmer/among.py +1 -2
  93. data/vendor/snowball/python/snowballstemmer/basestemmer.py +24 -33
  94. data/vendor/snowball/python/stemwords.py +72 -63
  95. data/vendor/snowball/runtime/api.c +11 -42
  96. data/vendor/snowball/runtime/api.h +11 -9
  97. data/vendor/snowball/runtime/snowball_runtime.h +110 -0
  98. data/vendor/snowball/runtime/utilities.c +282 -106
  99. data/vendor/snowball/rust/src/main.rs +2 -2
  100. data/vendor/snowball/rust/src/snowball/snowball_env.rs +7 -9
  101. data/vendor/snowball/tests/compilertest +62 -0
  102. data/vendor/snowball/tests/errors/ae-errors.sbl +53 -0
  103. data/vendor/snowball/tests/errors/ae-errors.stderr +8 -0
  104. data/vendor/snowball/tests/errors/bad-dollar.sbl +14 -0
  105. data/vendor/snowball/tests/errors/bad-dollar.stderr +4 -0
  106. data/vendor/snowball/tests/errors/bad-grouping-definition.sbl +9 -0
  107. data/vendor/snowball/tests/errors/bad-grouping-definition.stderr +6 -0
  108. data/vendor/snowball/tests/errors/missing-bra.sbl +6 -0
  109. data/vendor/snowball/tests/errors/missing-bra.stderr +3 -0
  110. data/vendor/snowball/tests/errors/missing-command.sbl +9 -0
  111. data/vendor/snowball/tests/errors/missing-command.stderr +1 -0
  112. data/vendor/snowball/tests/errors/missing-ket-backwardmode.sbl +3 -0
  113. data/vendor/snowball/tests/errors/missing-ket-backwardmode.stderr +1 -0
  114. data/vendor/snowball/tests/errors/missing-ket.sbl +7 -0
  115. data/vendor/snowball/tests/errors/missing-ket.stderr +6 -0
  116. data/vendor/snowball/tests/errors/notdefined.sbl +4 -0
  117. data/vendor/snowball/tests/errors/notdefined.stderr +2 -0
  118. data/vendor/snowball/tests/errors/string-omitted.sbl +5 -0
  119. data/vendor/snowball/tests/errors/string-omitted.stderr +1 -0
  120. data/vendor/snowball/tests/errors/undeclared.sbl +20 -0
  121. data/vendor/snowball/tests/errors/undeclared.stderr +9 -0
  122. data/vendor/snowball/tests/errors/unexpected-token.sbl +24 -0
  123. data/vendor/snowball/tests/errors/unexpected-token.stderr +17 -0
  124. data/vendor/snowball/tests/errors/wrongdirection.sbl +14 -0
  125. data/vendor/snowball/tests/errors/wrongdirection.stderr +1 -0
  126. data/vendor/snowball/tests/runtime/among.sbl +19 -0
  127. data/vendor/snowball/tests/runtime/arithmeticexpr.sbl +86 -0
  128. data/vendor/snowball/tests/runtime/attachinsert.sbl +47 -0
  129. data/vendor/snowball/tests/runtime/booleans.sbl +19 -0
  130. data/vendor/snowball/tests/runtime/externals.sbl +22 -0
  131. data/vendor/snowball/tests/runtime/hop.sbl +12 -0
  132. data/vendor/snowball/tests/runtime/integertests.sbl +60 -0
  133. data/vendor/snowball/tests/runtime/intlimits.sbl +25 -0
  134. data/vendor/snowball/tests/runtime/naming.sbl +20 -0
  135. data/vendor/snowball/tests/runtime/not.sbl +30 -0
  136. data/vendor/snowball/tests/runtime/or.sbl +17 -0
  137. data/vendor/snowball/tests/runtime/repeat.sbl +16 -0
  138. data/vendor/snowball/tests/runtime/setlimit.sbl +24 -0
  139. data/vendor/snowball/tests/runtime/sizelen.sbl +56 -0
  140. data/vendor/snowball/tests/runtime/slice.sbl +27 -0
  141. data/vendor/snowball/tests/runtime/stringdollar.sbl +39 -0
  142. data/vendor/snowball/tests/runtime/strings.sbl +66 -0
  143. data/vendor/snowball/tests/runtime/test.sbl +19 -0
  144. data/vendor/snowball/tests/stemtest.c +41 -1
  145. data/vendor/snowball/tests/syntax/canon.sbl +32 -0
  146. data/vendor/snowball/tests/syntax/canon.stderr +0 -0
  147. data/vendor/snowball/tests/syntax/canon.syntax +57 -0
  148. data/vendor/snowball/tests/syntax/emptyprogram.sbl +2 -0
  149. data/vendor/snowball/tests/syntax/emptyprogram.syntax +0 -0
  150. data/vendor/snowball/tests/syntax/groupings.sbl +11 -0
  151. data/vendor/snowball/tests/syntax/inline.sbl +144 -0
  152. data/vendor/snowball/tests/syntax/inline.stderr +0 -0
  153. data/vendor/snowball/tests/syntax/inline.syntax +121 -0
  154. data/vendor/snowball/tests/syntax/legacy.sbl +17 -0
  155. data/vendor/snowball/tests/syntax/legacy.stderr +5 -0
  156. data/vendor/snowball/tests/syntax/legacy.syntax +19 -0
  157. data/vendor/snowball/tests/syntax/loops.sbl +14 -0
  158. data/vendor/snowball/tests/syntax/loops.stderr +9 -0
  159. data/vendor/snowball/tests/syntax/loops.syntax +29 -0
  160. data/vendor/snowball/tests/syntax/noops.sbl +76 -0
  161. data/vendor/snowball/tests/syntax/noops.stderr +27 -0
  162. data/vendor/snowball/tests/syntax/noops.syntax +135 -0
  163. data/vendor/snowball/tests/syntax/simplifyae.sbl +21 -0
  164. data/vendor/snowball/tests/syntax/simplifyae.stderr +0 -0
  165. data/vendor/snowball/tests/syntax/simplifyae.syntax +39 -0
  166. data/vendor/snowball/tests/syntax/unused.sbl +18 -0
  167. data/vendor/snowball/tests/syntax/unused.stderr +7 -0
  168. data/vendor/snowball/tests/syntax/unused.syntax +3 -0
  169. data/vendor/snowball/zig/env.zig +599 -0
  170. data/vendor/snowball/zig/generate_algorithms.pl +19 -0
  171. data/vendor/snowball/zig/stemwords.zig +123 -0
  172. metadata +102 -4
  173. data/vendor/snowball/compiler/syswords.h +0 -86
  174. data/vendor/snowball/runtime/header.h +0 -62
@@ -1,43 +1,44 @@
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
- int next_label = g->next_label++;
15
- g->max_label = (next_label > g->max_label) ? next_label : g->max_label;
13
+ static int new_label_python(struct generator * g) {
14
+ int next_label = new_label(g);
15
+ if (next_label > g->max_label) g->max_label = next_label;
16
16
  return next_label;
17
17
  }
18
18
 
19
- static struct str * vars_newname(struct generator * g) {
20
- struct str * output;
21
- g->var_number++;
22
- output = str_new();
23
- str_append_string(output, "v_");
24
- str_append_int(output, g->var_number);
25
- return output;
26
- }
19
+ #define new_label(G) new_label_python(G)
27
20
 
28
21
  /* Write routines for items from the syntax tree */
29
22
 
23
+ static void write_relop(struct generator * g, int relop) {
24
+ // Relational operators are the same as C.
25
+ write_c_relop(g, relop);
26
+ }
27
+
30
28
  static void write_varname(struct generator * g, struct name * p) {
31
29
  switch (p->type) {
32
30
  case t_external:
33
- write_char(g, '_');
31
+ if (g->options->externals_prefix) {
32
+ write_string(g, g->options->externals_prefix);
33
+ }
34
34
  break;
35
35
  case t_routine:
36
36
  write_string(g, "__");
37
37
  /* FALLTHRU */
38
38
  default: {
39
- int ch = "SBIrxg"[p->type];
40
- write_char(g, ch);
39
+ // We use the same naming scheme for both global and local
40
+ // variables.
41
+ write_char(g, "SBIrxg"[p->type]);
41
42
  write_char(g, '_');
42
43
  break;
43
44
  }
@@ -45,16 +46,19 @@ static void write_varname(struct generator * g, struct name * p) {
45
46
  write_s(g, p->s);
46
47
  }
47
48
 
49
+ /* Reference to variable, e.g. when assigning to or using in an expression. */
48
50
  static void write_varref(struct generator * g, struct name * p) {
49
- write_string(g, "self.");
51
+ if (p->type >= t_routine || p->local_to == NULL) {
52
+ write_string(g, "self.");
53
+ }
50
54
  write_varname(g, p);
51
55
  }
52
56
 
53
57
  static void write_literal_string(struct generator * g, symbol * p) {
54
- write_string(g, "u\"");
58
+ write_char(g, '"');
55
59
  for (int i = 0; i < SIZE(p); i++) {
56
60
  int ch = p[i];
57
- if (32 <= ch && ch < 0x590 && ch != 127) {
61
+ if ((32 <= ch && ch < 127) || (0xa0 < ch && ch < 0x590)) {
58
62
  if (ch == '"' || ch == '\\') write_char(g, '\\');
59
63
  // Our Python generator uses ENC_WIDECHARS so we need to convert.
60
64
  write_wchar_as_utf8(g, ch);
@@ -66,11 +70,11 @@ static void write_literal_string(struct generator * g, symbol * p) {
66
70
  write_hex4(g, ch);
67
71
  }
68
72
  }
69
- write_string(g, "\"");
73
+ write_char(g, '"');
70
74
  }
71
75
 
72
76
  static void write_literal_char(struct generator * g, symbol ch) {
73
- write_string(g, "u\"");
77
+ write_char(g, '"');
74
78
  if (32 <= ch && ch < 0x590 && ch != 127) {
75
79
  if (ch == '"' || ch == '\\') write_char(g, '\\');
76
80
  // Python uses ENC_WIDECHARS so we need to convert.
@@ -82,18 +86,14 @@ static void write_literal_char(struct generator * g, symbol ch) {
82
86
  write_string(g, "\\u");
83
87
  write_hex4(g, ch);
84
88
  }
85
- write_string(g, "\"");
86
- }
87
-
88
- static void write_margin(struct generator * g) {
89
- for (int i = 0; i < g->margin; i++) write_string(g, " ");
89
+ write_char(g, '"');
90
90
  }
91
91
 
92
92
  static void write_comment(struct generator * g, struct node * p) {
93
93
  if (!g->options->comments) return;
94
94
  write_margin(g);
95
95
  write_string(g, "# ");
96
- write_comment_content(g, p);
96
+ write_comment_content(g, p, NULL);
97
97
  write_newline(g);
98
98
  }
99
99
 
@@ -143,11 +143,8 @@ static void wsetlab_begin(struct generator * g) {
143
143
  static void wsetlab_end(struct generator * g, int n) {
144
144
  g->I[0] = n;
145
145
  w(g, "~-~Mexcept lab~I0: pass~N");
146
- }
147
-
148
- static void wgotol(struct generator * g, int n) {
149
- g->I[0] = n;
150
- w(g, "~Mraise lab~I0()~N");
146
+ // We can safely reuse this later in this function.
147
+ g->next_label = n;
151
148
  }
152
149
 
153
150
  static void write_failure(struct generator * g) {
@@ -158,14 +155,15 @@ static void write_failure(struct generator * g) {
158
155
  }
159
156
  switch (g->failure_label) {
160
157
  case x_return:
161
- w(g, "~Mreturn False~N");
162
- g->unreachable = true;
158
+ w(g, "~Mreturn False");
163
159
  break;
164
160
  default:
165
- g->I[0] = g->failure_label;
166
- w(g, "~Mraise lab~I0()~N");
167
- g->unreachable = true;
161
+ w(g, "~Mraise lab");
162
+ write_int(g, g->failure_label);
163
+ w(g, "()");
168
164
  }
165
+ write_newline(g);
166
+ g->unreachable = true;
169
167
  }
170
168
 
171
169
  static void write_failure_if(struct generator * g, const char * s, struct node * p) {
@@ -189,7 +187,6 @@ static void write_check_limit(struct generator * g, struct node * p) {
189
187
 
190
188
  /* Formatted write. */
191
189
  static void writef(struct generator * g, const char * input, struct node * p) {
192
- (void)p;
193
190
  int i = 0;
194
191
 
195
192
  while (input[i]) {
@@ -235,26 +232,17 @@ static void writef(struct generator * g, const char * input, struct node * p) {
235
232
  continue;
236
233
  }
237
234
  case 'V':
238
- case 'W': {
239
- int j = input[i++] - '0';
240
- if (j < 0 || j > (int)(sizeof(g->V) / sizeof(g->V[0])))
241
- goto invalid_escape2;
242
- if (ch == 'V')
243
- write_varref(g, g->V[j]);
244
- else
245
- write_varname(g, g->V[j]);
235
+ write_varref(g, p->name);
246
236
  continue;
247
- }
248
- case 'L': {
249
- int j = input[i++] - '0';
250
- if (j < 0 || j > (int)(sizeof(g->L) / sizeof(g->L[0])))
251
- goto invalid_escape2;
252
- write_literal_string(g, g->L[j]);
237
+ case 'W':
238
+ write_varname(g, p->name);
239
+ continue;
240
+ case 'L':
241
+ write_literal_string(g, p->literalstring);
253
242
  continue;
254
- }
255
243
  case '+': g->margin++; continue;
256
244
  case '-': g->margin--; continue;
257
- case 'n': write_string(g, g->options->name); continue;
245
+ case 'n': write_s(g, g->options->name); continue;
258
246
  default:
259
247
  printf("Invalid escape sequence ~%c in writef(g, \"%s\", p)\n",
260
248
  ch, input);
@@ -275,50 +263,58 @@ static void generate_AE(struct generator * g, struct node * p) {
275
263
  const char * s;
276
264
  switch (p->type) {
277
265
  case c_name:
278
- write_varref(g, p->name); break;
266
+ write_varref(g, p->name);
267
+ break;
279
268
  case c_number:
280
- write_int(g, p->number); break;
269
+ write_int(g, p->number);
270
+ break;
281
271
  case c_maxint:
282
- write_string(g, "sys.maxsize"); break;
272
+ write_string(g, "sys.maxsize");
273
+ break;
283
274
  case c_minint:
284
- write_string(g, "(~sys.maxsize)"); break;
275
+ write_string(g, "(~sys.maxsize)");
276
+ break;
285
277
  case c_neg:
286
- write_char(g, '-'); generate_AE(g, p->right); break;
278
+ write_char(g, '-');
279
+ generate_AE(g, p->right);
280
+ break;
287
281
  case c_multiply:
288
- s = " * "; goto label0;
289
- case c_plus:
290
- s = " + "; goto label0;
291
- case c_minus:
292
- s = " - ";
293
- label0:
294
- write_char(g, '('); generate_AE(g, p->left);
295
- write_string(g, s); generate_AE(g, p->right); write_char(g, ')'); break;
282
+ s = " * ";
283
+ goto label0;
296
284
  case c_divide:
297
285
  /* Snowball specifies integer division with semantics matching C,
298
286
  * so Python's `/` or `//` isn't suitable (`//` would be in cases
299
287
  * where we knew that the arguments had the same sign).
300
- *
301
- * The `float(`...`)` is needed for Python2.
302
288
  */
303
- write_string(g, "int(float(");
289
+ write_string(g, "int");
290
+ s = " / ";
291
+ goto label0;
292
+ case c_plus:
293
+ s = " + ";
294
+ goto label0;
295
+ case c_minus:
296
+ s = " - ";
297
+ label0:
298
+ write_char(g, '(');
304
299
  generate_AE(g, p->left);
305
- write_string(g, ") / ");
300
+ write_string(g, s);
306
301
  generate_AE(g, p->right);
307
302
  write_char(g, ')');
308
303
  break;
309
304
  case c_cursor:
310
- w(g, "self.cursor"); break;
305
+ w(g, "self.cursor");
306
+ break;
311
307
  case c_limit:
312
- w(g, p->mode == m_forward ? "self.limit" : "self.limit_backward"); break;
313
- case c_lenof: /* Same as sizeof() for Python. */
314
- case c_sizeof:
315
- g->V[0] = p->name;
316
- w(g, "len(~V0)");
308
+ w(g, p->mode == m_forward ? "self.limit" : "self.limit_backward");
317
309
  break;
318
310
  case c_len: /* Same as size() for Python. */
319
311
  case c_size:
320
312
  w(g, "len(self.current)");
321
313
  break;
314
+ case c_lenof: /* Same as sizeof() for Python. */
315
+ case c_sizeof:
316
+ writef(g, "len(~V)", p);
317
+ break;
322
318
  }
323
319
  }
324
320
 
@@ -332,37 +328,47 @@ static void generate_bra(struct generator * g, struct node * p) {
332
328
  }
333
329
 
334
330
  static void generate_and(struct generator * g, struct node * p) {
335
- struct str * savevar = vars_newname(g);
336
- int keep_c = K_needed(g, p->left);
331
+ struct str * savevar = NULL;
332
+ if (K_needed_for_and(p->left)) {
333
+ savevar = vars_newname(g);
334
+ }
337
335
 
338
336
  write_comment(g, p);
339
337
 
340
- if (keep_c) write_savecursor(g, p, savevar);
338
+ if (savevar) {
339
+ write_savecursor(g, p, savevar);
340
+ }
341
341
 
342
342
  p = p->left;
343
343
  while (p) {
344
344
  generate(g, p);
345
345
  if (g->unreachable) break;
346
- if (keep_c && p->right != NULL) write_restorecursor(g, p, savevar);
346
+ if (savevar && p->right != NULL) write_restorecursor(g, p, savevar);
347
347
  p = p->right;
348
348
  }
349
- str_delete(savevar);
349
+
350
+ if (savevar) {
351
+ str_delete(savevar);
352
+ }
350
353
  }
351
354
 
352
355
  static void generate_or(struct generator * g, struct node * p) {
353
- struct str * savevar = vars_newname(g);
354
- int keep_c = K_needed(g, p->left);
356
+ struct str * savevar = NULL;
357
+ if (K_needed_for_or(p->left)) {
358
+ savevar = vars_newname(g);
359
+ }
355
360
 
356
361
  int a0 = g->failure_label;
357
362
  struct str * a1 = str_copy(g->failure_str);
358
363
 
359
- int out_lab = new_label(g);
360
- int end_unreachable = true;
364
+ bool end_unreachable = true;
361
365
 
362
366
  write_comment(g, p);
363
- wsetlab_begin(g);
367
+ w(g, "~Mwhile True:~N~+");
364
368
 
365
- if (keep_c) write_savecursor(g, p, savevar);
369
+ if (savevar && K_needed_node_on_f(p)) {
370
+ write_savecursor(g, p, savevar);
371
+ }
366
372
 
367
373
  p = p->left;
368
374
  str_clear(g->failure_str);
@@ -379,12 +385,14 @@ static void generate_or(struct generator * g, struct node * p) {
379
385
  wsetlab_begin(g);
380
386
  generate(g, p);
381
387
  if (!g->unreachable) {
382
- wgotol(g, out_lab);
388
+ w(g, "~Mbreak~N");
383
389
  end_unreachable = false;
384
390
  }
385
391
  wsetlab_end(g, label);
386
392
  g->unreachable = false;
387
- if (keep_c) write_restorecursor(g, p, savevar);
393
+ if (savevar) {
394
+ write_restorecursor(g, p, savevar);
395
+ }
388
396
  p = p->right;
389
397
  }
390
398
 
@@ -393,11 +401,14 @@ static void generate_or(struct generator * g, struct node * p) {
393
401
  g->failure_str = a1;
394
402
 
395
403
  generate(g, p);
396
- wsetlab_end(g, out_lab);
404
+ w(g, "~Mbreak~N~-");
397
405
  if (!end_unreachable) {
398
406
  g->unreachable = false;
399
407
  }
400
- str_delete(savevar);
408
+
409
+ if (savevar) {
410
+ str_delete(savevar);
411
+ }
401
412
  }
402
413
 
403
414
  static void generate_backwards(struct generator * g, struct node * p) {
@@ -408,10 +419,11 @@ static void generate_backwards(struct generator * g, struct node * p) {
408
419
  w(g, "~Mself.cursor = self.limit_backward~N");
409
420
  }
410
421
 
411
-
412
422
  static void generate_not(struct generator * g, struct node * p) {
413
- struct str * savevar = vars_newname(g);
414
- int keep_c = K_needed(g, p->left);
423
+ struct str * savevar = NULL;
424
+ if (K_needed_node_on_f(p->left)) {
425
+ savevar = vars_newname(g);
426
+ }
415
427
 
416
428
  int a0 = g->failure_label;
417
429
  struct str * a1 = str_copy(g->failure_str);
@@ -420,7 +432,7 @@ static void generate_not(struct generator * g, struct node * p) {
420
432
  str_clear(g->failure_str);
421
433
 
422
434
  write_comment(g, p);
423
- if (keep_c) {
435
+ if (savevar) {
424
436
  write_savecursor(g, p, savevar);
425
437
  }
426
438
 
@@ -437,20 +449,24 @@ static void generate_not(struct generator * g, struct node * p) {
437
449
  wsetlab_end(g, label);
438
450
  g->unreachable = false;
439
451
 
440
- if (keep_c) write_restorecursor(g, p, savevar);
441
- str_delete(savevar);
452
+ if (savevar) {
453
+ write_restorecursor(g, p, savevar);
454
+ str_delete(savevar);
455
+ }
442
456
  }
443
457
 
444
-
445
458
  static void generate_try(struct generator * g, struct node * p) {
446
- struct str * savevar = vars_newname(g);
447
- int keep_c = K_needed(g, p->left);
459
+ struct str * savevar = NULL;
460
+ if (K_needed(p->left)) {
461
+ savevar = vars_newname(g);
462
+ }
463
+
448
464
  int label = new_label(g);
449
465
  g->failure_label = label;
450
466
  str_clear(g->failure_str);
451
467
 
452
468
  write_comment(g, p);
453
- if (keep_c) {
469
+ if (savevar) {
454
470
  write_savecursor(g, p, savevar);
455
471
  restore_string(p, g->failure_str, savevar);
456
472
  }
@@ -460,19 +476,19 @@ static void generate_try(struct generator * g, struct node * p) {
460
476
  wsetlab_end(g, label);
461
477
  g->unreachable = false;
462
478
 
463
- str_delete(savevar);
479
+ if (savevar) {
480
+ str_delete(savevar);
481
+ }
464
482
  }
465
483
 
466
484
  static void generate_set(struct generator * g, struct node * p) {
467
485
  write_comment(g, p);
468
- g->V[0] = p->name;
469
- writef(g, "~M~V0 = True~N", p);
486
+ writef(g, "~M~V = True~N", p);
470
487
  }
471
488
 
472
489
  static void generate_unset(struct generator * g, struct node * p) {
473
490
  write_comment(g, p);
474
- g->V[0] = p->name;
475
- writef(g, "~M~V0 = False~N", p);
491
+ writef(g, "~M~V = False~N", p);
476
492
  }
477
493
 
478
494
  static void generate_fail(struct generator * g, struct node * p) {
@@ -482,38 +498,43 @@ static void generate_fail(struct generator * g, struct node * p) {
482
498
  }
483
499
 
484
500
  /* generate_test() also implements 'reverse' */
485
-
486
501
  static void generate_test(struct generator * g, struct node * p) {
487
- struct str * savevar = vars_newname(g);
488
- int keep_c = K_needed(g, p->left);
502
+ struct str * savevar = NULL;
503
+ if (K_needed(p->left)) {
504
+ savevar = vars_newname(g);
505
+ }
489
506
 
490
507
  write_comment(g, p);
491
508
 
492
- if (keep_c) {
509
+ if (savevar) {
493
510
  write_savecursor(g, p, savevar);
494
511
  }
495
512
 
496
513
  generate(g, p->left);
497
514
 
498
- if (!g->unreachable) {
499
- if (keep_c) {
515
+ if (savevar) {
516
+ if (!g->unreachable) {
500
517
  write_restorecursor(g, p, savevar);
501
518
  }
519
+ str_delete(savevar);
502
520
  }
503
- str_delete(savevar);
504
521
  }
505
522
 
506
523
  static void generate_do(struct generator * g, struct node * p) {
507
- struct str * savevar = vars_newname(g);
508
- int keep_c = K_needed(g, p->left);
524
+ struct str * savevar = NULL;
525
+ if (K_needed(p->left)) {
526
+ savevar = vars_newname(g);
527
+ }
528
+
509
529
  write_comment(g, p);
510
- if (keep_c) write_savecursor(g, p, savevar);
530
+ if (savevar) {
531
+ write_savecursor(g, p, savevar);
532
+ }
511
533
 
512
534
  if (p->left->type == c_call) {
513
535
  /* Optimise do <call> */
514
536
  write_comment(g, p->left);
515
- g->V[0] = p->left->name;
516
- w(g, "~M~V0()~N");
537
+ writef(g, "~M~V()~N", p->left);
517
538
  } else {
518
539
  int label = new_label(g);
519
540
  g->failure_label = label;
@@ -525,8 +546,10 @@ static void generate_do(struct generator * g, struct node * p) {
525
546
  g->unreachable = false;
526
547
  }
527
548
 
528
- if (keep_c) write_restorecursor(g, p, savevar);
529
- str_delete(savevar);
549
+ if (savevar) {
550
+ write_restorecursor(g, p, savevar);
551
+ str_delete(savevar);
552
+ }
530
553
  }
531
554
 
532
555
  static void generate_next(struct generator * g, struct node * p) {
@@ -540,8 +563,7 @@ static void generate_GO_grouping(struct generator * g, struct node * p, int is_g
540
563
 
541
564
  g->S[0] = p->mode == m_forward ? "" : "_b";
542
565
  g->S[1] = complement ? "in" : "out";
543
- g->V[0] = p->name;
544
- write_failure_if(g, "not self.go_~S1_grouping~S0(~n.~W0)", p);
566
+ write_failure_if(g, "not self.go_~S1_grouping~S0(~n.~W)", p);
545
567
  if (!is_goto) {
546
568
  if (p->mode == m_forward)
547
569
  w(g, "~Mself.cursor += 1~N");
@@ -550,20 +572,21 @@ static void generate_GO_grouping(struct generator * g, struct node * p, int is_g
550
572
  }
551
573
  }
552
574
 
553
- static void generate_GO(struct generator * g, struct node * p, int style) {
575
+ static void generate_GO(struct generator * g, struct node * p, int is_goto) {
554
576
  write_comment(g, p);
555
577
 
556
- int end_unreachable = false;
557
- struct str * savevar = vars_newname(g);
558
- int keep_c = style == 1 || repeat_restore(g, p->left);
559
-
560
578
  int a0 = g->failure_label;
561
579
  struct str * a1 = str_copy(g->failure_str);
562
580
 
563
- int golab = new_label(g);
564
- w(g, "~Mtry:~N~+"
565
- "~Mwhile True:~N~+");
566
- if (keep_c) write_savecursor(g, p, savevar);
581
+ bool end_unreachable = false;
582
+
583
+ w(g, "~Mwhile True:~N~+");
584
+
585
+ struct str * savevar = NULL;
586
+ if (is_goto || repeat_restore(p->left)) {
587
+ savevar = vars_newname(g);
588
+ write_savecursor(g, p, savevar);
589
+ }
567
590
 
568
591
  int label = new_label(g);
569
592
  g->failure_label = label;
@@ -577,13 +600,15 @@ static void generate_GO(struct generator * g, struct node * p, int style) {
577
600
  end_unreachable = true;
578
601
  } else {
579
602
  /* include for goto; omit for gopast */
580
- if (style == 1) write_restorecursor(g, p, savevar);
581
- g->I[0] = golab;
582
- w(g, "~Mraise lab~I0()~N");
603
+ if (is_goto) write_restorecursor(g, p, savevar);
604
+ w(g, "~Mbreak~N");
583
605
  }
584
606
  g->unreachable = false;
585
607
  wsetlab_end(g, label);
586
- if (keep_c) write_restorecursor(g, p, savevar);
608
+ if (savevar) {
609
+ write_restorecursor(g, p, savevar);
610
+ str_delete(savevar);
611
+ }
587
612
 
588
613
  g->failure_label = a0;
589
614
  str_delete(g->failure_str);
@@ -591,49 +616,45 @@ static void generate_GO(struct generator * g, struct node * p, int style) {
591
616
 
592
617
  write_check_limit(g, p);
593
618
  write_inc_cursor(g, p);
594
- w(g, "~-~-");
595
- g->I[0] = golab;
596
- w(g, "~Mexcept lab~I0: pass~N");
597
- str_delete(savevar);
619
+ w(g, "~-");
598
620
  g->unreachable = end_unreachable;
599
621
  }
600
622
 
601
623
  static void generate_loop(struct generator * g, struct node * p) {
602
- struct str * loopvar = vars_newname(g);
603
624
  write_comment(g, p);
604
- g->B[0] = str_data(loopvar);
605
625
  if (p->AE->type == c_number && p->AE->number <= 4) {
606
626
  // Use a tuple instead of range() for small constant numbers of
607
627
  // iterations.
608
- w(g, "~Mfor ~B0 in ");
628
+ w(g, "~Mfor _ in ");
609
629
  for (int i = p->AE->number; i > 0; --i) {
610
630
  w(g, "0");
611
631
  if (i > 1) w(g, ", ");
612
632
  }
613
- writef(g, ":~N", p);
633
+ writef(g, ":", p);
614
634
  } else {
615
- w(g, "~Mfor ~B0 in range(");
635
+ w(g, "~Mfor _ in range(");
616
636
  generate_AE(g, p->AE);
617
- g->B[0] = str_data(loopvar);
618
- writef(g, "):~N", p);
637
+ writef(g, "):", p);
619
638
  }
620
639
  writef(g, "~{", p);
621
640
 
622
641
  generate(g, p->left);
623
642
 
624
643
  w(g, "~}");
625
- str_delete(loopvar);
626
644
  g->unreachable = false;
627
645
  }
628
646
 
629
647
  static void generate_repeat_or_atleast(struct generator * g, struct node * p, struct str * loopvar) {
630
- struct str * savevar = vars_newname(g);
631
- int keep_c = repeat_restore(g, p->left);
632
- int label = new_label(g);
633
- g->failure_label = label;
634
648
  writef(g, "~Mwhile True:~N~+", p);
635
- if (keep_c) write_savecursor(g, p, savevar);
636
649
 
650
+ struct str * savevar = NULL;
651
+ if (repeat_restore(p->left)) {
652
+ savevar = vars_newname(g);
653
+ write_savecursor(g, p, savevar);
654
+ }
655
+
656
+ int label = new_label(g);
657
+ g->failure_label = label;
637
658
  str_clear(g->failure_str);
638
659
  wsetlab_begin(g);
639
660
  generate(g, p->left);
@@ -650,10 +671,12 @@ static void generate_repeat_or_atleast(struct generator * g, struct node * p, st
650
671
  wsetlab_end(g, label);
651
672
  g->unreachable = false;
652
673
 
653
- if (keep_c) write_restorecursor(g, p, savevar);
674
+ if (savevar) {
675
+ write_restorecursor(g, p, savevar);
676
+ str_delete(savevar);
677
+ }
654
678
 
655
679
  w(g, "~Mbreak~N~}");
656
- str_delete(savevar);
657
680
  }
658
681
 
659
682
  static void generate_repeat(struct generator * g, struct node * p) {
@@ -662,8 +685,9 @@ static void generate_repeat(struct generator * g, struct node * p) {
662
685
  }
663
686
 
664
687
  static void generate_atleast(struct generator * g, struct node * p) {
665
- struct str * loopvar = vars_newname(g);
666
688
  write_comment(g, p);
689
+
690
+ struct str * loopvar = vars_newname(g);
667
691
  g->B[0] = str_data(loopvar);
668
692
  w(g, "~M~B0 = ");
669
693
  generate_AE(g, p->AE);
@@ -683,12 +707,6 @@ static void generate_atleast(struct generator * g, struct node * p) {
683
707
  str_delete(loopvar);
684
708
  }
685
709
 
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 = self.cursor~N", p);
690
- }
691
-
692
710
  static void generate_tomark(struct generator * g, struct node * p) {
693
711
  write_comment(g, p);
694
712
  g->S[0] = p->mode == m_forward ? ">" : "<";
@@ -701,23 +719,10 @@ static void generate_tomark(struct generator * g, struct node * p) {
701
719
  w(g, "~Mself.cursor = "); generate_AE(g, p->AE); writef(g, "~N", p);
702
720
  }
703
721
 
704
- static void generate_atmark(struct generator * g, struct node * p) {
705
- write_comment(g, p);
706
- w(g, "~Mif self.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
722
  static void generate_hop(struct generator * g, struct node * p) {
714
723
  write_comment(g, p);
715
724
  g->S[0] = p->mode == m_forward ? "+" : "-";
716
725
 
717
- w(g, "~Mc = self.cursor ~S0 ");
718
- generate_AE(g, p->AE);
719
- w(g, "~N");
720
-
721
726
  g->S[1] = p->mode == m_forward ? "> self.limit" : "< self.limit_backward";
722
727
  g->S[2] = p->mode == m_forward ? "<" : ">";
723
728
  if (p->AE->type == c_number) {
@@ -725,18 +730,16 @@ static void generate_hop(struct generator * g, struct node * p) {
725
730
  //
726
731
  // No need to check for negative hop as that's converted to false by
727
732
  // the analyser.
728
- write_failure_if(g, "c ~S1", p);
733
+ g->I[0] = p->AE->number;
734
+ write_failure_if(g, "self.cursor ~S0 ~I0 ~S1", p);
735
+ w(g, "~Mself.cursor ~S0= ~I0~N");
729
736
  } else {
737
+ w(g, "~Mc = self.cursor ~S0 ");
738
+ generate_AE(g, p->AE);
739
+ w(g, "~N");
730
740
  write_failure_if(g, "c ~S1 or c ~S2 self.cursor", p);
741
+ writef(g, "~Mself.cursor = c~N", p);
731
742
  }
732
- writef(g, "~Mself.cursor = c~N", p);
733
- }
734
-
735
- static void generate_delete(struct generator * g, struct node * p) {
736
- write_comment(g, p);
737
- writef(g, "~Mif not self.slice_del():~N"
738
- "~+~Mreturn False~N~-"
739
- "~N", p);
740
743
  }
741
744
 
742
745
  static void generate_tolimit(struct generator * g, struct node * p) {
@@ -745,13 +748,6 @@ static void generate_tolimit(struct generator * g, struct node * p) {
745
748
  writef(g, "~Mself.cursor = ~S0~N", p);
746
749
  }
747
750
 
748
- static void generate_atlimit(struct generator * g, struct node * p) {
749
- write_comment(g, p);
750
- g->S[0] = p->mode == m_forward ? "self.limit" : "self.limit_backward";
751
- g->S[1] = p->mode == m_forward ? "<" : ">";
752
- write_failure_if(g, "self.cursor ~S1 ~S0", p);
753
- }
754
-
755
751
  static void generate_leftslice(struct generator * g, struct node * p) {
756
752
  write_comment(g, p);
757
753
  g->S[0] = p->mode == m_forward ? "self.bra" : "self.ket";
@@ -766,16 +762,12 @@ static void generate_rightslice(struct generator * g, struct node * p) {
766
762
 
767
763
  static void generate_assignto(struct generator * g, struct node * p) {
768
764
  write_comment(g, p);
769
- g->V[0] = p->name;
770
- writef(g, "~M~V0 = self.assign_to()~N", p);
765
+ writef(g, "~M~V = self.assign_to()~N", p);
771
766
  }
772
767
 
773
768
  static void generate_sliceto(struct generator * g, struct node * p) {
774
769
  write_comment(g, p);
775
- g->V[0] = p->name;
776
- writef(g, "~M~V0 = self.slice_to()~N"
777
- "~Mif ~V0 == '':~N"
778
- "~+~Mreturn False~N~-", p);
770
+ writef(g, "~M~V = self.slice_to()~N", p);
779
771
  }
780
772
 
781
773
  static void generate_address(struct generator * g, struct node * p) {
@@ -788,8 +780,8 @@ static void generate_address(struct generator * g, struct node * p) {
788
780
  }
789
781
 
790
782
  static void generate_insert(struct generator * g, struct node * p, int style) {
791
- int keep_c = style == c_attach;
792
783
  write_comment(g, p);
784
+ int keep_c = style == c_attach;
793
785
  if (p->mode == m_backward) keep_c = !keep_c;
794
786
  if (keep_c) w(g, "~Mc = self.cursor~N");
795
787
  writef(g, "~Mself.insert(self.cursor, self.cursor, ", p);
@@ -798,11 +790,12 @@ static void generate_insert(struct generator * g, struct node * p, int style) {
798
790
  if (keep_c) w(g, "~Mself.cursor = c~N");
799
791
  }
800
792
 
801
- static void generate_assignfrom(struct generator * g, struct node * p) {
802
- int keep_c = p->mode == m_forward; /* like 'attach' */
803
-
793
+ static void generate_stringassign(struct generator * g, struct node * p) {
804
794
  write_comment(g, p);
805
- if (keep_c) writef(g, "~Mc = self.cursor~N", p);
795
+ int keep_c = p->mode == m_forward; /* like 'attach' */
796
+ if (keep_c) {
797
+ writef(g, "~Mc = self.cursor~N", p);
798
+ }
806
799
  if (p->mode == m_forward) {
807
800
  writef(g, "~Mself.insert(self.cursor, self.limit, ", p);
808
801
  } else {
@@ -810,21 +803,27 @@ static void generate_assignfrom(struct generator * g, struct node * p) {
810
803
  }
811
804
  generate_address(g, p);
812
805
  writef(g, ")~N", p);
813
- if (keep_c) w(g, "~Mself.cursor = c~N");
806
+ if (keep_c) {
807
+ w(g, "~Mself.cursor = c~N");
808
+ }
814
809
  }
815
810
 
816
811
  static void generate_slicefrom(struct generator * g, struct node * p) {
817
812
  write_comment(g, p);
818
- w(g, "~Mif not self.slice_from(");
813
+ if (p->literalstring && SIZE(p->literalstring) == 0) {
814
+ w(g, "~Mself.slice_del()~N");
815
+ return;
816
+ }
817
+ w(g, "~Mself.slice_from(");
819
818
  generate_address(g, p);
820
- writef(g, "):~N"
821
- "~+~Mreturn False~N~-", p);
819
+ w(g, ")~N");
822
820
  }
823
821
 
824
822
  static void generate_setlimit(struct generator * g, struct node * p) {
823
+ write_comment(g, p);
825
824
  struct str * savevar = vars_newname(g);
826
825
  struct str * varname = vars_newname(g);
827
- write_comment(g, p);
826
+
828
827
  if (p->left && p->left->type == c_tomark) {
829
828
  /* Special case for:
830
829
  *
@@ -836,6 +835,7 @@ static void generate_setlimit(struct generator * g, struct node * p) {
836
835
  */
837
836
  struct node * q = p->left;
838
837
  write_comment(g, q);
838
+
839
839
  g->S[0] = q->mode == m_forward ? ">" : "<";
840
840
  w(g, "~Mif self.cursor ~S0 "); generate_AE(g, q->AE); w(g, ":");
841
841
  write_block_start(g);
@@ -845,13 +845,17 @@ static void generate_setlimit(struct generator * g, struct node * p) {
845
845
 
846
846
  g->B[0] = str_data(varname);
847
847
  if (p->mode == m_forward) {
848
- w(g, "~M~B0 = self.limit - self.cursor~N");
848
+ w(g, "~M~B0 = self.limit~N");
849
849
  w(g, "~Mself.limit = ");
850
+ generate_AE(g, q->AE);
851
+ w(g, "~N");
852
+ w(g, "~M~B0 -= self.limit~N");
850
853
  } else {
851
854
  w(g, "~M~B0 = self.limit_backward~N");
852
855
  w(g, "~Mself.limit_backward = ");
856
+ generate_AE(g, q->AE);
857
+ w(g, "~N");
853
858
  }
854
- generate_AE(g, q->AE); writef(g, "~N", q);
855
859
 
856
860
  if (p->mode == m_forward) {
857
861
  str_assign(g->failure_str, "self.limit += ");
@@ -862,6 +866,7 @@ static void generate_setlimit(struct generator * g, struct node * p) {
862
866
  }
863
867
  } else {
864
868
  write_savecursor(g, p, savevar);
869
+
865
870
  generate(g, p->left);
866
871
 
867
872
  if (!g->unreachable) {
@@ -902,47 +907,67 @@ static void generate_setlimit(struct generator * g, struct node * p) {
902
907
  /* dollar sets snowball up to operate on a string variable as if it were the
903
908
  * current string */
904
909
  static void generate_dollar(struct generator * g, struct node * p) {
910
+ write_comment(g, p);
911
+
912
+ int a0 = g->failure_label;
913
+ struct str * a1 = str_copy(g->failure_str);
914
+ int label = new_label(g);
915
+ g->failure_label = label;
916
+ str_clear(g->failure_str);
917
+
905
918
  struct str * savevar = vars_newname(g);
906
919
  g->B[0] = str_data(savevar);
907
- write_comment(g, p);
908
920
  writef(g, "~M~B0 = BaseStemmer()~N"
909
921
  "~M~B0.copy_from(self)~N", p);
910
922
 
911
- {
912
- struct str * saved_output = g->outbuf;
913
- str_clear(g->failure_str);
914
- g->outbuf = g->failure_str;
915
- g->V[0] = p->name;
916
- writef(g, "~V0 = self.current; ", p);
917
- /* For Python 3, this can just be: super().copy_from(~B0) */
918
- writef(g, "super(~n, self).copy_from(~B0)", p);
919
- g->failure_str = g->outbuf;
920
- g->outbuf = saved_output;
921
- }
922
-
923
- writef(g, "~Mself.current = ~V0~N"
923
+ writef(g, "~Mself.current = ~V~N"
924
924
  "~Mself.cursor = 0~N"
925
925
  "~Mself.limit = len(self.current)~N", p);
926
+ if (p->left->possible_signals == -1) {
927
+ /* Assume failure. */
928
+ w(g, "~M~B0_f = True~N");
929
+ }
930
+
931
+ wsetlab_begin(g);
932
+
926
933
  generate(g, p->left);
927
- if (!g->unreachable) {
928
- write_margin(g);
929
- write_str(g, g->failure_str);
930
- write_newline(g);
934
+
935
+ if (!g->unreachable && p->left->possible_signals == -1) {
936
+ /* Mark success. */
937
+ g->B[0] = str_data(savevar);
938
+ w(g, "~M~B0_f = False~N");
931
939
  }
940
+
941
+ wsetlab_end(g, g->failure_label);
942
+
943
+ g->failure_label = a0;
944
+ str_delete(g->failure_str);
945
+ g->failure_str = a1;
946
+
947
+ g->B[0] = str_data(savevar);
948
+ writef(g, "~M~V = self.current~N"
949
+ "~Msuper().copy_from(~B0)~N", p);
950
+
951
+ if (p->left->possible_signals == 0) {
952
+ // p->left always signals f.
953
+ write_failure(g);
954
+ } else if (p->left->possible_signals == -1) {
955
+ write_failure_if(g, "~B0_f", p);
956
+ }
957
+
932
958
  str_delete(savevar);
933
959
  }
934
960
 
935
961
  static void generate_integer_assign(struct generator * g, struct node * p, const char * s) {
936
962
  write_comment(g, p);
937
- g->V[0] = p->name;
938
963
  g->S[0] = s;
939
- w(g, "~M~V0 ~S0 "); generate_AE(g, p->AE); w(g, "~N");
964
+ writef(g, "~M~V ~S0 ", p); generate_AE(g, p->AE); w(g, "~N");
940
965
  }
941
966
 
942
967
  static void generate_integer_test(struct generator * g, struct node * p) {
943
968
  write_comment(g, p);
944
969
  int relop = p->type;
945
- int optimise_to_return = (g->failure_label == x_return && p->right && p->right->type == c_functionend);
970
+ int optimise_to_return = tailcallable(g, p);
946
971
  if (optimise_to_return) {
947
972
  w(g, "~Mreturn ");
948
973
  p->right = NULL;
@@ -952,8 +977,7 @@ static void generate_integer_test(struct generator * g, struct node * p) {
952
977
  relop ^= 1;
953
978
  }
954
979
  generate_AE(g, p->left);
955
- // Relational operators are the same as C.
956
- write_c_relop(g, relop);
980
+ write_relop(g, relop);
957
981
  generate_AE(g, p->AE);
958
982
  if (optimise_to_return) {
959
983
  w(g, "~N");
@@ -967,24 +991,30 @@ static void generate_integer_test(struct generator * g, struct node * p) {
967
991
  }
968
992
 
969
993
  static void generate_call(struct generator * g, struct node * p) {
970
- int signals = check_possible_signals_list(g, p->name->definition, c_define, 0);
994
+ int signals = p->name->definition->possible_signals;
971
995
  write_comment(g, p);
972
- g->V[0] = p->name;
973
- if (g->failure_label == x_return &&
974
- (signals == 0 || (p->right && p->right->type == c_functionend))) {
975
- /* Always fails or tail call. */
976
- writef(g, "~Mreturn ~V0()~N", p);
996
+ if (tailcallable(g, p)) {
997
+ /* Tail call. */
998
+ writef(g, "~Mreturn ~V()~N", p);
999
+ p->right = NULL;
1000
+ g->unreachable = true;
1001
+ return;
1002
+ }
1003
+ if (just_return_on_fail(g) && signals == 0) {
1004
+ /* Always fails. */
1005
+ writef(g, "~Mreturn ~V()~N", p);
1006
+ g->unreachable = true;
977
1007
  return;
978
1008
  }
979
1009
  if (signals == 1) {
980
1010
  /* Always succeeds. */
981
- writef(g, "~M~V0()~N", p);
1011
+ writef(g, "~M~V()~N", p);
982
1012
  } else if (signals == 0) {
983
1013
  /* Always fails. */
984
- writef(g, "~M~V0()~N", p);
1014
+ writef(g, "~M~V()~N", p);
985
1015
  write_failure(g);
986
1016
  } else {
987
- write_failure_if(g, "not ~V0()", p);
1017
+ write_failure_if(g, "not ~V()", p);
988
1018
  }
989
1019
  }
990
1020
 
@@ -993,38 +1023,57 @@ static void generate_grouping(struct generator * g, struct node * p, int complem
993
1023
 
994
1024
  g->S[0] = p->mode == m_forward ? "" : "_b";
995
1025
  g->S[1] = complement ? "out" : "in";
996
- g->V[0] = p->name;
997
- write_failure_if(g, "not self.~S1_grouping~S0(~n.~W0)", p);
1026
+ if (tailcallable(g, p)) {
1027
+ writef(g, "~Mreturn self.~S1_grouping~S0(~n.~W)~N", p);
1028
+ p->right = NULL;
1029
+ } else {
1030
+ write_failure_if(g, "not self.~S1_grouping~S0(~n.~W)", p);
1031
+ }
998
1032
  }
999
1033
 
1000
1034
  static void generate_namedstring(struct generator * g, struct node * p) {
1001
1035
  write_comment(g, p);
1002
1036
  g->S[0] = p->mode == m_forward ? "" : "_b";
1003
- g->V[0] = p->name;
1004
- write_failure_if(g, "not self.eq_s~S0(~V0)", p);
1037
+ if (tailcallable(g, p)) {
1038
+ writef(g, "~Mreturn self.eq_s~S0(~V)~N", p);
1039
+ p->right = NULL;
1040
+ } else {
1041
+ write_failure_if(g, "not self.eq_s~S0(~V)", p);
1042
+ }
1005
1043
  }
1006
1044
 
1007
1045
  static void generate_literalstring(struct generator * g, struct node * p) {
1008
- symbol * b = p->literalstring;
1009
1046
  write_comment(g, p);
1047
+ symbol * b = p->literalstring;
1048
+ if (SIZE(b) == 1) {
1049
+ /* It's quite common to compare with a single character literal string,
1050
+ * so just inline the simpler code for this case rather than making a
1051
+ * function call.
1052
+ */
1053
+ if (p->mode == m_forward) {
1054
+ writef(g, "~Mif self.cursor == self.limit or self.current[self.cursor] != ~L:~f"
1055
+ "~Mself.cursor += 1~N", p);
1056
+ } else {
1057
+ writef(g, "~Mif self.cursor <= self.limit_backward or self.current[self.cursor - 1] != ~L:~f"
1058
+ "~Mself.cursor -= 1~N", p);
1059
+ }
1060
+ return;
1061
+ }
1062
+
1010
1063
  g->S[0] = p->mode == m_forward ? "" : "_b";
1011
- g->L[0] = b;
1012
- write_failure_if(g, "not self.eq_s~S0(~L0)", p);
1064
+ if (tailcallable(g, p)) {
1065
+ writef(g, "~Mreturn self.eq_s~S0(~L)~N", p);
1066
+ p->right = NULL;
1067
+ } else {
1068
+ write_failure_if(g, "not self.eq_s~S0(~L)", p);
1069
+ }
1013
1070
  }
1014
1071
 
1015
1072
  static void generate_define(struct generator * g, struct node * p) {
1016
- struct name * q = p->name;
1017
- if (q->type == t_routine && !q->used) return;
1018
-
1019
1073
  write_newline(g);
1020
1074
  write_comment(g, p);
1021
1075
 
1022
- g->V[0] = q;
1023
- w(g, "~Mdef ~W0(self):~+~N");
1024
-
1025
- /* Save output. */
1026
- struct str * saved_output = g->outbuf;
1027
- g->outbuf = str_new();
1076
+ writef(g, "~Mdef ~W(self):~+~N", p);
1028
1077
 
1029
1078
  g->next_label = 0;
1030
1079
  g->var_number = 0;
@@ -1032,19 +1081,16 @@ static void generate_define(struct generator * g, struct node * p) {
1032
1081
  str_clear(g->failure_str);
1033
1082
  g->failure_label = x_return;
1034
1083
  g->unreachable = false;
1035
- int signals = check_possible_signals_list(g, p->left, c_define, 0);
1084
+
1085
+ /* Generate function body. */
1036
1086
  generate(g, p->left);
1037
1087
  if (p->left->right) {
1038
1088
  assert(p->left->right->type == c_functionend);
1039
- if (signals) {
1089
+ if (p->left->possible_signals) {
1040
1090
  generate(g, p->left->right);
1041
1091
  }
1042
1092
  }
1043
1093
  w(g, "~-");
1044
-
1045
- str_append(saved_output, g->outbuf);
1046
- str_delete(g->outbuf);
1047
- g->outbuf = saved_output;
1048
1094
  }
1049
1095
 
1050
1096
  static void generate_functionend(struct generator * g, struct node * p) {
@@ -1067,6 +1113,10 @@ static void generate_substring(struct generator * g, struct node * p) {
1067
1113
  }
1068
1114
  } else if (x->always_matches) {
1069
1115
  writef(g, "~Mself.find_among~S0(~n.a_~I0)~N", p);
1116
+ } else if (x->command_count == 0 && tailcallable(g, p)) {
1117
+ writef(g, "~Mreturn self.find_among~S0(~n.a_~I0) != 0~N", p);
1118
+ x->node->right = NULL;
1119
+ g->unreachable = true;
1070
1120
  } else {
1071
1121
  write_failure_if(g, "self.find_among~S0(~n.a_~I0) == 0", p);
1072
1122
  }
@@ -1085,6 +1135,20 @@ static void generate_among(struct generator * g, struct node * p) {
1085
1135
  /* Only one outcome ("no match" already handled). */
1086
1136
  generate(g, x->commands[0]);
1087
1137
  } else if (x->command_count > 0) {
1138
+ if (x->same_action == c_slicefrom && x->command_count > 1) {
1139
+ if (x->nocommand_count > 0) {
1140
+ w(g, "~Mif among_var > 0:~N~+");
1141
+ }
1142
+ write_comment(g, x->commands[0]);
1143
+ g->I[0] = x->number;
1144
+ w(g, "~Mself.slice_from(~n.as_~I0[among_var - 1])~N");
1145
+ if (x->nocommand_count > 0) {
1146
+ w(g, "~-");
1147
+ }
1148
+ g->unreachable = false;
1149
+ return;
1150
+ }
1151
+
1088
1152
  /* We dispatch the integer result in `among_var` with an if-chain,
1089
1153
  * which is O(n) unless Python has a special optimisation (and
1090
1154
  * profiling with the `timeit` module suggests it doesn't). There
@@ -1108,10 +1172,24 @@ static void generate_among(struct generator * g, struct node * p) {
1108
1172
  }
1109
1173
  }
1110
1174
 
1111
- static void generate_booltest(struct generator * g, struct node * p) {
1175
+ static void generate_booltest(struct generator * g, struct node * p, int inverted) {
1112
1176
  write_comment(g, p);
1113
- g->V[0] = p->name;
1114
- write_failure_if(g, "not ~V0", p);
1177
+ if (tailcallable(g, p)) {
1178
+ // Optimise at end of function.
1179
+ if (inverted) {
1180
+ writef(g, "~Mreturn not ~V~N", p);
1181
+ } else {
1182
+ writef(g, "~Mreturn ~V~N", p);
1183
+ }
1184
+ p->right = NULL;
1185
+ g->unreachable = true;
1186
+ return;
1187
+ }
1188
+ if (inverted) {
1189
+ write_failure_if(g, "~V", p);
1190
+ } else {
1191
+ write_failure_if(g, "not ~V", p);
1192
+ }
1115
1193
  }
1116
1194
 
1117
1195
  static void generate_false(struct generator * g, struct node * p) {
@@ -1156,25 +1234,21 @@ static void generate(struct generator * g, struct node * p) {
1156
1234
  case c_repeat: generate_repeat(g, p); break;
1157
1235
  case c_loop: generate_loop(g, p); break;
1158
1236
  case c_atleast: generate_atleast(g, p); break;
1159
- case c_setmark: generate_setmark(g, p); break;
1160
1237
  case c_tomark: generate_tomark(g, p); break;
1161
- case c_atmark: generate_atmark(g, p); break;
1162
1238
  case c_hop: generate_hop(g, p); break;
1163
- case c_delete: generate_delete(g, p); break;
1164
1239
  case c_next: generate_next(g, p); break;
1165
1240
  case c_tolimit: generate_tolimit(g, p); break;
1166
- case c_atlimit: generate_atlimit(g, p); break;
1167
1241
  case c_leftslice: generate_leftslice(g, p); break;
1168
1242
  case c_rightslice: generate_rightslice(g, p); break;
1169
1243
  case c_assignto: generate_assignto(g, p); break;
1170
1244
  case c_sliceto: generate_sliceto(g, p); break;
1171
- case c_assign: generate_assignfrom(g, p); break;
1245
+ case c_stringassign: generate_stringassign(g, p); break;
1172
1246
  case c_insert:
1173
1247
  case c_attach: generate_insert(g, p, p->type); break;
1174
1248
  case c_slicefrom: generate_slicefrom(g, p); break;
1175
1249
  case c_setlimit: generate_setlimit(g, p); break;
1176
1250
  case c_dollar: generate_dollar(g, p); break;
1177
- case c_mathassign: generate_integer_assign(g, p, "="); break;
1251
+ case c_assign: generate_integer_assign(g, p, "="); break;
1178
1252
  case c_plusassign: generate_integer_assign(g, p, "+="); break;
1179
1253
  case c_minusassign: generate_integer_assign(g, p, "-="); break;
1180
1254
  case c_multiplyassign:generate_integer_assign(g, p, "*="); break;
@@ -1182,11 +1256,8 @@ static void generate(struct generator * g, struct node * p) {
1182
1256
  /* Snowball specifies integer division with semantics matching C,
1183
1257
  * so Python's `/=` or `//=` isn't suitable (`//=` would be in
1184
1258
  * cases where we knew that the arguments had the same sign).
1185
- *
1186
- * The `float(`...`)` is needed for Python2.
1187
1259
  */
1188
- g->V[0] = p->name;
1189
- w(g, "~M~V0 = int(float(~V0) / ");
1260
+ writef(g, "~M~V = int(~V / ", p);
1190
1261
  generate_AE(g, p->AE);
1191
1262
  w(g, ")~N");
1192
1263
  break;
@@ -1205,7 +1276,8 @@ static void generate(struct generator * g, struct node * p) {
1205
1276
  case c_literalstring: generate_literalstring(g, p); break;
1206
1277
  case c_among: generate_among(g, p); break;
1207
1278
  case c_substring: generate_substring(g, p); break;
1208
- case c_booltest: generate_booltest(g, p); break;
1279
+ case c_booltest: generate_booltest(g, p, false); break;
1280
+ case c_not_booltest: generate_booltest(g, p, true); break;
1209
1281
  case c_false: generate_false(g, p); break;
1210
1282
  case c_true: break;
1211
1283
  case c_debug: generate_debug(g, p); break;
@@ -1221,13 +1293,13 @@ static void generate(struct generator * g, struct node * p) {
1221
1293
 
1222
1294
  static void generate_class_begin(struct generator * g) {
1223
1295
  w(g, "from .basestemmer import ");
1224
- w(g, g->options->parent_class_name);
1296
+ write_string(g, g->options->parent_class_name);
1225
1297
  w(g, "~N"
1226
1298
  "from .among import Among~N"
1227
1299
  "~N"
1228
1300
  "~N"
1229
1301
  "class ~n(");
1230
- w(g, g->options->parent_class_name);
1302
+ write_string(g, g->options->parent_class_name);
1231
1303
  w(g, "):~N"
1232
1304
  "~+~M'''~N"
1233
1305
  "~MThis class implements the stemming algorithm defined by a snowball script.~N"
@@ -1248,19 +1320,30 @@ static void generate_among_table(struct generator * g, struct among * x) {
1248
1320
 
1249
1321
  w(g, "~Ma_~I0 = [~N~+");
1250
1322
  for (int i = 0; i < x->literalstring_count; i++) {
1323
+ if (i) w(g, ",~N");
1251
1324
  g->I[0] = v[i].i;
1252
1325
  g->I[1] = v[i].result;
1253
- g->L[0] = v[i].b;
1254
- g->S[0] = i < x->literalstring_count - 1 ? "," : "";
1255
1326
 
1256
- w(g, "~MAmong(~L0, ~I0, ~I1");
1327
+ w(g, "~MAmong(");
1328
+ write_literal_string(g, v[i].b);
1329
+ w(g, ", ~I0, ~I1");
1257
1330
  if (v[i].function != NULL) {
1258
1331
  w(g, ", ");
1259
1332
  write_varname(g, v[i].function);
1260
1333
  }
1261
- w(g, ")~S0~N");
1334
+ w(g, ")");
1335
+ }
1336
+ w(g, "~N~-~M]~N");
1337
+
1338
+ if (x->same_action == c_slicefrom && x->command_count > 1) {
1339
+ g->I[0] = x->number;
1340
+ w(g, "~Mas_~I0 = (");
1341
+ for (int i = 1; i <= x->command_count; i++) {
1342
+ if (i > 1) w(g, ", ");
1343
+ write_literal_string(g, x->commands[i - 1]->left->literalstring);
1344
+ }
1345
+ w(g, ")~N");
1262
1346
  }
1263
- w(g, "~-~M]~N");
1264
1347
  }
1265
1348
 
1266
1349
  static void generate_amongs(struct generator * g) {
@@ -1272,13 +1355,29 @@ static void generate_amongs(struct generator * g) {
1272
1355
  static void generate_grouping_table(struct generator * g, struct grouping * q) {
1273
1356
  symbol * b = q->b;
1274
1357
 
1275
- g->V[0] = q->name;
1358
+ write_margin(g);
1359
+ write_varname(g, q->name);
1360
+ if (SIZE(b) <= 3) {
1361
+ // The `s in g` test used in base-stemmer.py works whether g is a
1362
+ // set or a string.
1363
+ //
1364
+ // The generated code for the string is smaller, faster to construct,
1365
+ // and (for a small grouping) seems to be if anything fractionally
1366
+ // faster to test.
1367
+ //
1368
+ // FIXME: The threshold seems about right for Python 3.13 but we should
1369
+ // recheck periodically.
1370
+ write_string(g, " = ");
1371
+ write_literal_string(g, b);
1372
+ w(g, "~N");
1373
+ return;
1374
+ }
1276
1375
 
1277
1376
  // We could use frozenset, but it seems slightly slower to construct which
1278
1377
  // adds to startup time.
1279
- w(g, "~M~W0 = {");
1378
+ write_string(g, " = {");
1280
1379
  for (int i = 0; i < SIZE(b); i++) {
1281
- if (i > 0) w(g, ", ");
1380
+ if (i) w(g, ", ");
1282
1381
  write_literal_char(g, b[i]);
1283
1382
  }
1284
1383
  w(g, "}~N~N");
@@ -1286,34 +1385,37 @@ static void generate_grouping_table(struct generator * g, struct grouping * q) {
1286
1385
 
1287
1386
  static void generate_groupings(struct generator * g) {
1288
1387
  for (struct grouping * q = g->analyser->groupings; q; q = q->next) {
1289
- if (q->name->used)
1290
- generate_grouping_table(g, q);
1388
+ generate_grouping_table(g, q);
1291
1389
  }
1292
1390
  }
1293
1391
 
1294
1392
  static void generate_members(struct generator * g) {
1295
1393
  for (struct name * q = g->analyser->names; q; q = q->next) {
1296
- g->V[0] = q;
1394
+ if (q->local_to) continue;
1297
1395
  switch (q->type) {
1298
1396
  case t_string:
1299
- w(g, " ~W0 = \"\"~N");
1397
+ write_string(g, " ");
1398
+ write_varname(g, q);
1399
+ w(g, " = \"\"~N");
1300
1400
  break;
1301
1401
  case t_integer:
1302
- w(g, " ~W0 = 0~N");
1402
+ write_string(g, " ");
1403
+ write_varname(g, q);
1404
+ w(g, " = 0~N");
1303
1405
  break;
1304
1406
  case t_boolean:
1305
- w(g, " ~W0 = False~N");
1407
+ write_string(g, " ");
1408
+ write_varname(g, q);
1409
+ w(g, " = False~N");
1306
1410
  break;
1307
1411
  }
1308
1412
  }
1309
1413
  }
1310
1414
 
1311
1415
  static void generate_methods(struct generator * g) {
1312
- struct node * p = g->analyser->program;
1313
- while (p != NULL) {
1416
+ for (struct node * p = g->analyser->program; p; p = p->right) {
1314
1417
  generate(g, p);
1315
1418
  g->unreachable = false;
1316
- p = p->right;
1317
1419
  }
1318
1420
  }
1319
1421
 
@@ -1328,9 +1430,7 @@ static void generate_label_classes(struct generator * g)
1328
1430
  extern void generate_program_python(struct generator * g) {
1329
1431
  g->outbuf = str_new();
1330
1432
  g->failure_str = str_new();
1331
-
1332
- // Only needed for Python 2, which defaults to ASCII.
1333
- w(g, "#-*- coding: utf-8 -*-~N");
1433
+ g->max_label = -1;
1334
1434
 
1335
1435
  write_start_comment(g, "# ", NULL);
1336
1436
  if (g->analyser->int_limits_used) {