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
@@ -0,0 +1,1476 @@
1
+ #include <assert.h>
2
+ #include <stdio.h> /* for fprintf etc */
3
+ #include <stdlib.h> /* for exit */
4
+ #include <string.h> /* for strlen */
5
+ #include "header.h"
6
+
7
+ /* prototype functions for recursive use: */
8
+
9
+ static void generate(struct generator * g, struct node * p);
10
+ static void w(struct generator * g, const char * s);
11
+ static void writef(struct generator * g, const char * s, struct node * p);
12
+
13
+ /* Write routines for items from the syntax tree */
14
+
15
+ static void write_relop(struct generator * g, int relop) {
16
+ // Relational operators are the same as C.
17
+ write_c_relop(g, relop);
18
+ }
19
+
20
+ static void write_varname(struct generator * g, struct name * p) {
21
+ if (p->type == t_external) {
22
+ if (g->options->externals_prefix) {
23
+ write_string(g, g->options->externals_prefix);
24
+ }
25
+ } else {
26
+ // We use the same naming scheme for both global and local variables.
27
+ write_char(g, "SBIrxg"[p->type]);
28
+ write_char(g, '_');
29
+ }
30
+ write_s(g, p->s);
31
+ }
32
+
33
+ /* Reference to variable, e.g. when assigning to or using in an expression. */
34
+ static void write_varref(struct generator * g, struct name * p) {
35
+ /* In Dart, references look just the same */
36
+ write_varname(g, p);
37
+ }
38
+
39
+ static void write_literal_string(struct generator * g, symbol * p) {
40
+ write_char(g, '"');
41
+ for (int i = 0; i < SIZE(p); i++) {
42
+ int ch = p[i];
43
+ if (32 <= ch && ch < 127) {
44
+ if (ch == '"' || ch == '\\' || ch == '$') write_char(g, '\\');
45
+ write_char(g, ch);
46
+ } else {
47
+ write_string(g, "\\u");
48
+ write_hex4(g, ch);
49
+ }
50
+ }
51
+ write_char(g, '"');
52
+ }
53
+
54
+ static void write_comment(struct generator * g, struct node * p) {
55
+ if (!g->options->comments) return;
56
+ write_margin(g);
57
+ write_string(g, "// ");
58
+ write_comment_content(g, p, NULL);
59
+ write_newline(g);
60
+ }
61
+
62
+ static void write_block_start(struct generator * g) {
63
+ w(g, "~M{~+~N");
64
+ }
65
+
66
+ static void write_block_end(struct generator * g) {
67
+ w(g, "~-~M}~N");
68
+ }
69
+
70
+ static void write_savecursor(struct generator * g, struct node * p,
71
+ struct str * savevar) {
72
+ g->B[0] = str_data(savevar);
73
+ g->S[1] = "";
74
+ if (p->mode != m_forward) g->S[1] = "limit - ";
75
+ writef(g, "~Mint ~B0 = ~S1cursor;~N", p);
76
+ }
77
+
78
+ static void append_restore_string(struct node * p, struct str * out, struct str * savevar) {
79
+ str_append_string(out, "cursor = ");
80
+ if (p->mode != m_forward) str_append_string(out, "limit - ");
81
+ str_append(out, savevar);
82
+ str_append_ch(out, ';');
83
+ }
84
+
85
+ static void write_restorecursor(struct generator * g, struct node * p, struct str * savevar) {
86
+ write_margin(g);
87
+ append_restore_string(p, g->outbuf, savevar);
88
+ write_newline(g);
89
+ }
90
+
91
+ static void write_inc_cursor(struct generator * g, struct node * p) {
92
+ write_margin(g);
93
+ write_string(g, p->mode == m_forward ? "cursor++;" : "cursor--;");
94
+ write_newline(g);
95
+ }
96
+
97
+ static void wsetlab_begin(struct generator * g, int n) {
98
+ w(g, "~Mlab");
99
+ write_int(g, n);
100
+ w(g, ": while (true) {~+~N");
101
+ }
102
+
103
+ static void wsetlab_end(struct generator * g, int n) {
104
+ if (!g->unreachable) {
105
+ w(g, "~Mbreak lab");
106
+ write_int(g, n);
107
+ w(g, ";~N");
108
+ } else {
109
+ g->unreachable = false;
110
+ }
111
+ w(g, "~-~M}~N");
112
+ }
113
+
114
+ static void wgotol(struct generator * g, int n) {
115
+ write_margin(g);
116
+ write_string(g, "break lab");
117
+ write_int(g, n);
118
+ write_char(g, ';');
119
+ write_newline(g);
120
+ g->unreachable = true;
121
+ }
122
+
123
+ static void write_failure(struct generator * g) {
124
+ if (str_len(g->failure_str) != 0) {
125
+ write_margin(g);
126
+ write_str(g, g->failure_str);
127
+ write_newline(g);
128
+ }
129
+ write_margin(g);
130
+ switch (g->failure_label) {
131
+ case x_return:
132
+ write_string(g, "return false;");
133
+ break;
134
+ default:
135
+ write_string(g, "break lab");
136
+ write_int(g, g->failure_label);
137
+ write_char(g, ';');
138
+ }
139
+ write_newline(g);
140
+ g->unreachable = true;
141
+ }
142
+
143
+ static void write_failure_if(struct generator * g, const char * s, struct node * p) {
144
+ writef(g, "~Mif (", p);
145
+ writef(g, s, p);
146
+ writef(g, ")~N", p);
147
+ write_block_start(g);
148
+ write_failure(g);
149
+ write_block_end(g);
150
+ g->unreachable = false;
151
+ }
152
+
153
+ /* if at limit fail */
154
+ static void write_check_limit(struct generator * g, struct node * p) {
155
+ if (p->mode == m_forward) {
156
+ write_failure_if(g, "cursor >= limit", p);
157
+ } else {
158
+ write_failure_if(g, "cursor <= limit_backward", p);
159
+ }
160
+ }
161
+
162
+ /* Formatted write. */
163
+ static void writef(struct generator * g, const char * input, struct node * p) {
164
+ int i = 0;
165
+
166
+ while (input[i]) {
167
+ int ch = input[i++];
168
+ if (ch != '~') {
169
+ write_char(g, ch);
170
+ continue;
171
+ }
172
+ ch = input[i++];
173
+ switch (ch) {
174
+ case '~': write_char(g, '~'); continue;
175
+ case 'f': write_block_start(g);
176
+ write_failure(g);
177
+ g->unreachable = false;
178
+ write_block_end(g);
179
+ continue;
180
+ case 'M': write_margin(g); continue;
181
+ case 'N': write_newline(g); continue;
182
+ case '{': write_block_start(g); continue;
183
+ case '}': write_block_end(g); continue;
184
+ case 'S': {
185
+ int j = input[i++] - '0';
186
+ if (j < 0 || j > (int)(sizeof(g->S) / sizeof(g->S[0]))) {
187
+ printf("Invalid escape sequence ~%c%c in writef(g, \"%s\", p)\n",
188
+ ch, input[i - 1], input);
189
+ exit(1);
190
+ }
191
+ write_string(g, g->S[j]);
192
+ continue;
193
+ }
194
+ case 'B': {
195
+ int j = input[i++] - '0';
196
+ if (j < 0 || j > (int)(sizeof(g->B) / sizeof(g->B[0])))
197
+ goto invalid_escape2;
198
+ write_s(g, g->B[j]);
199
+ continue;
200
+ }
201
+ case 'F': {
202
+ struct among * x = NULL;
203
+ if (p) x = p->among;
204
+ if (x == NULL) {
205
+ write_string(g, "null");
206
+ continue;
207
+ }
208
+ if (x->function_count == 0) {
209
+ write_string(g, "null");
210
+ continue;
211
+ }
212
+ if (x->function_count == 1) {
213
+ struct amongvec * v = x->b;
214
+ int found = 0;
215
+ for (int j = 0; j < x->literalstring_count; j++) {
216
+ if (v[j].function) {
217
+ write_varref(g, v[j].function);
218
+ found = 1;
219
+ break;
220
+ }
221
+ }
222
+ if (!found) {
223
+ fprintf(stderr, "function_count == 1 but no among functions\n");
224
+ exit(1);
225
+ }
226
+ continue;
227
+ }
228
+
229
+ w(g, "af_");
230
+ write_int(g, x->number);
231
+ continue;
232
+ }
233
+ case 'I': {
234
+ int j = input[i++] - '0';
235
+ if (j < 0 || j > (int)(sizeof(g->I) / sizeof(g->I[0])))
236
+ goto invalid_escape2;
237
+ write_int(g, g->I[j]);
238
+ continue;
239
+ }
240
+ case 'V':
241
+ write_varref(g, p->name);
242
+ continue;
243
+ case 'W':
244
+ write_varname(g, p->name);
245
+ continue;
246
+ case 'L':
247
+ write_literal_string(g, p->literalstring);
248
+ continue;
249
+ case '+': g->margin++; continue;
250
+ case '-': g->margin--; continue;
251
+ case 'n': write_s(g, g->options->name); continue;
252
+ default:
253
+ printf("Invalid escape sequence ~%c in writef(g, \"%s\", p)\n",
254
+ ch, input);
255
+ exit(1);
256
+ invalid_escape2:
257
+ printf("Invalid escape sequence ~%c%c in writef(g, \"%s\", p)\n",
258
+ ch, input[i - 1], input);
259
+ exit(1);
260
+ }
261
+ }
262
+ }
263
+
264
+ static void w(struct generator * g, const char * s) {
265
+ writef(g, s, NULL);
266
+ }
267
+
268
+ static void generate_AE(struct generator * g, struct node * p) {
269
+ const char * s;
270
+ switch (p->type) {
271
+ case c_name:
272
+ write_varref(g, p->name);
273
+ break;
274
+ case c_number:
275
+ write_int(g, p->number);
276
+ break;
277
+ case c_maxint:
278
+ write_string(g, "9007199254740992");
279
+ break;
280
+ case c_minint:
281
+ write_string(g, "-9007199254740992");
282
+ break;
283
+ case c_neg:
284
+ write_char(g, '-');
285
+ generate_AE(g, p->right);
286
+ break;
287
+ case c_multiply:
288
+ s = " * ";
289
+ goto label0;
290
+ case c_divide:
291
+ s = " ~/ ";
292
+ goto label0;
293
+ case c_plus:
294
+ s = " + ";
295
+ goto label0;
296
+ case c_minus:
297
+ s = " - ";
298
+ label0:
299
+ write_char(g, '(');
300
+ generate_AE(g, p->left);
301
+ write_string(g, s);
302
+ generate_AE(g, p->right);
303
+ write_char(g, ')');
304
+ break;
305
+ case c_cursor:
306
+ w(g, "cursor");
307
+ break;
308
+ case c_limit:
309
+ w(g, p->mode == m_forward ? "limit" : "limit_backward");
310
+ break;
311
+ case c_len: /* Same as size() for Dart. */
312
+ case c_size:
313
+ w(g, "current.length");
314
+ break;
315
+ case c_lenof: /* Same as sizeof() for Dart. */
316
+ case c_sizeof:
317
+ writef(g, "~V.length", p);
318
+ break;
319
+ }
320
+ }
321
+
322
+ static void generate_bra(struct generator * g, struct node * p) {
323
+ write_comment(g, p);
324
+ p = p->left;
325
+ while (p) {
326
+ generate(g, p);
327
+ p = p->right;
328
+ }
329
+ }
330
+
331
+ static void generate_and(struct generator * g, struct node * p) {
332
+ struct str * savevar = NULL;
333
+ if (K_needed_for_and(p->left)) {
334
+ savevar = vars_newname(g);
335
+ }
336
+
337
+ write_comment(g, p);
338
+
339
+ if (savevar) {
340
+ write_savecursor(g, p, savevar);
341
+ }
342
+
343
+ p = p->left;
344
+ while (p) {
345
+ generate(g, p);
346
+ if (g->unreachable) break;
347
+ if (savevar && p->right != NULL) write_restorecursor(g, p, savevar);
348
+ p = p->right;
349
+ }
350
+
351
+ if (savevar) {
352
+ str_delete(savevar);
353
+ }
354
+ }
355
+
356
+ static void generate_or(struct generator * g, struct node * p) {
357
+ struct str * savevar = NULL;
358
+ if (K_needed_for_or(p->left)) {
359
+ savevar = vars_newname(g);
360
+ }
361
+
362
+ int a0 = g->failure_label;
363
+ struct str * a1 = str_copy(g->failure_str);
364
+
365
+ int out_lab = new_label(g);
366
+ bool end_unreachable = true;
367
+
368
+ write_comment(g, p);
369
+ wsetlab_begin(g, out_lab);
370
+
371
+ if (savevar && K_needed_node_on_f(p)) {
372
+ write_savecursor(g, p, savevar);
373
+ }
374
+
375
+ p = p->left;
376
+ str_clear(g->failure_str);
377
+
378
+ if (p == NULL) {
379
+ /* p should never be NULL after an or: there should be at least two
380
+ * sub nodes. */
381
+ fprintf(stderr, "Error: \"or\" node without children nodes.");
382
+ exit(1);
383
+ }
384
+ while (p->right != NULL) {
385
+ int label = new_label(g);
386
+ g->failure_label = label;
387
+ wsetlab_begin(g, g->failure_label);
388
+ generate(g, p);
389
+ if (!g->unreachable) {
390
+ wgotol(g, out_lab);
391
+ end_unreachable = false;
392
+ }
393
+
394
+ wsetlab_end(g, g->failure_label);
395
+ g->unreachable = false;
396
+ if (savevar) {
397
+ write_restorecursor(g, p, savevar);
398
+ }
399
+ p = p->right;
400
+ }
401
+
402
+ g->failure_label = a0;
403
+ str_delete(g->failure_str);
404
+ g->failure_str = a1;
405
+
406
+ generate(g, p);
407
+
408
+ wsetlab_end(g, out_lab);
409
+ if (!end_unreachable) {
410
+ g->unreachable = false;
411
+ }
412
+
413
+ if (savevar) {
414
+ str_delete(savevar);
415
+ }
416
+ }
417
+
418
+ static void generate_backwards(struct generator * g, struct node * p) {
419
+ write_comment(g, p);
420
+ writef(g, "~Mlimit_backward = cursor;~N"
421
+ "~Mcursor = limit;~N", p);
422
+ generate(g, p->left);
423
+ w(g, "~Mcursor = limit_backward;~N");
424
+ }
425
+
426
+ static void generate_not(struct generator * g, struct node * p) {
427
+ struct str * savevar = NULL;
428
+ if (K_needed_node_on_f(p->left)) {
429
+ savevar = vars_newname(g);
430
+ }
431
+
432
+ int a0 = g->failure_label;
433
+ struct str * a1 = str_copy(g->failure_str);
434
+
435
+ write_comment(g, p);
436
+ if (savevar) {
437
+ write_block_start(g);
438
+ write_savecursor(g, p, savevar);
439
+ }
440
+
441
+ int label = new_label(g);
442
+ g->failure_label = label;
443
+ str_clear(g->failure_str);
444
+
445
+ wsetlab_begin(g, g->failure_label);
446
+
447
+ generate(g, p->left);
448
+
449
+ g->failure_label = a0;
450
+ str_delete(g->failure_str);
451
+ g->failure_str = a1;
452
+
453
+ if (!g->unreachable) write_failure(g);
454
+
455
+ wsetlab_end(g, g->failure_label);
456
+
457
+ g->unreachable = false;
458
+
459
+ if (savevar) {
460
+ write_restorecursor(g, p, savevar);
461
+ write_block_end(g);
462
+ str_delete(savevar);
463
+ }
464
+ }
465
+
466
+ static void generate_try(struct generator * g, struct node * p) {
467
+ struct str * savevar = NULL;
468
+ if (K_needed(p->left)) {
469
+ savevar = vars_newname(g);
470
+ }
471
+
472
+ int label = new_label(g);
473
+ g->failure_label = label;
474
+ str_clear(g->failure_str);
475
+
476
+ write_comment(g, p);
477
+ if (savevar) {
478
+ write_savecursor(g, p, savevar);
479
+ append_restore_string(p, g->failure_str, savevar);
480
+ }
481
+
482
+ wsetlab_begin(g, g->failure_label);
483
+
484
+ generate(g, p->left);
485
+
486
+ wsetlab_end(g, g->failure_label);
487
+ g->unreachable = false;
488
+
489
+ if (savevar) {
490
+ str_delete(savevar);
491
+ }
492
+ }
493
+
494
+ static void generate_set(struct generator * g, struct node * p) {
495
+ write_comment(g, p);
496
+ writef(g, "~M~V = true;~N", p);
497
+ }
498
+
499
+ static void generate_unset(struct generator * g, struct node * p) {
500
+ write_comment(g, p);
501
+ writef(g, "~M~V = false;~N", p);
502
+ }
503
+
504
+ static void generate_fail(struct generator * g, struct node * p) {
505
+ write_comment(g, p);
506
+ generate(g, p->left);
507
+ if (!g->unreachable) write_failure(g);
508
+ }
509
+
510
+ /* generate_test() also implements 'reverse' */
511
+ static void generate_test(struct generator * g, struct node * p) {
512
+ struct str * savevar = NULL;
513
+ if (K_needed(p->left)) {
514
+ savevar = vars_newname(g);
515
+ }
516
+
517
+ write_comment(g, p);
518
+
519
+ if (savevar) {
520
+ write_savecursor(g, p, savevar);
521
+ }
522
+
523
+ generate(g, p->left);
524
+
525
+ if (savevar) {
526
+ if (!g->unreachable) {
527
+ write_restorecursor(g, p, savevar);
528
+ }
529
+ str_delete(savevar);
530
+ }
531
+ }
532
+
533
+ static void generate_do(struct generator * g, struct node * p) {
534
+ struct str * savevar = NULL;
535
+ if (K_needed(p->left)) {
536
+ savevar = vars_newname(g);
537
+ }
538
+
539
+ write_comment(g, p);
540
+ if (savevar) {
541
+ write_savecursor(g, p, savevar);
542
+ }
543
+
544
+ if (p->left->type == c_call) {
545
+ /* Optimise do <call> */
546
+ write_comment(g, p->left);
547
+ writef(g, "~M~V();~N", p->left);
548
+ } else {
549
+ int label = new_label(g);
550
+ g->failure_label = label;
551
+ str_clear(g->failure_str);
552
+
553
+ wsetlab_begin(g, g->failure_label);
554
+
555
+ generate(g, p->left);
556
+
557
+ wsetlab_end(g, g->failure_label);
558
+ g->unreachable = false;
559
+ }
560
+
561
+ if (savevar) {
562
+ write_restorecursor(g, p, savevar);
563
+ str_delete(savevar);
564
+ }
565
+ }
566
+
567
+ static void generate_next(struct generator * g, struct node * p) {
568
+ write_comment(g, p);
569
+ write_check_limit(g, p);
570
+ write_inc_cursor(g, p);
571
+ }
572
+
573
+ static void generate_GO_grouping(struct generator * g, struct node * p, int is_goto, int complement) {
574
+ write_comment(g, p);
575
+
576
+ struct grouping * q = p->name->grouping;
577
+ g->S[0] = p->mode == m_forward ? "" : "_b";
578
+ g->S[1] = complement ? "in" : "out";
579
+ g->I[0] = q->smallest_ch;
580
+ g->I[1] = q->largest_ch;
581
+ write_failure_if(g, "!go_~S1_grouping~S0(~V, ~I0, ~I1)", p);
582
+ if (!is_goto) {
583
+ if (p->mode == m_forward)
584
+ w(g, "~Mcursor++;~N");
585
+ else
586
+ w(g, "~Mcursor--;~N");
587
+ }
588
+ }
589
+
590
+ static void generate_GO(struct generator * g, struct node * p, int is_goto) {
591
+ write_comment(g, p);
592
+
593
+ int a0 = g->failure_label;
594
+ struct str * a1 = str_copy(g->failure_str);
595
+
596
+ bool end_unreachable = false;
597
+
598
+ int golab = new_label(g);
599
+ g->I[0] = golab;
600
+ w(g, "~Mgolab~I0: while(true)~N");
601
+ w(g, "~{");
602
+
603
+ struct str * savevar = NULL;
604
+ if (is_goto || repeat_restore(p->left)) {
605
+ savevar = vars_newname(g);
606
+ write_savecursor(g, p, savevar);
607
+ }
608
+
609
+ int label = new_label(g);
610
+ g->failure_label = label;
611
+ str_clear(g->failure_str);
612
+ wsetlab_begin(g, g->failure_label);
613
+ generate(g, p->left);
614
+
615
+ if (g->unreachable) {
616
+ /* Cannot break out of this loop: therefore the code after the
617
+ * end of the loop is unreachable.*/
618
+ end_unreachable = true;
619
+ g->unreachable = false;
620
+ } else {
621
+ /* include for goto; omit for gopast */
622
+ if (is_goto) write_restorecursor(g, p, savevar);
623
+ g->I[0] = golab;
624
+ w(g, "~Mbreak golab~I0;~N");
625
+ g->unreachable = true;
626
+ }
627
+
628
+ wsetlab_end(g, g->failure_label);
629
+ if (savevar) {
630
+ write_restorecursor(g, p, savevar);
631
+ str_delete(savevar);
632
+ }
633
+
634
+ g->failure_label = a0;
635
+ str_delete(g->failure_str);
636
+ g->failure_str = a1;
637
+
638
+ write_check_limit(g, p);
639
+ write_inc_cursor(g, p);
640
+ write_block_end(g);
641
+ g->unreachable = end_unreachable;
642
+ }
643
+
644
+ static void generate_loop(struct generator * g, struct node * p) {
645
+ write_comment(g, p);
646
+ struct str * loopvar = vars_newname(g);
647
+ g->B[0] = str_data(loopvar);
648
+ w(g, "~Mfor (int ~B0 = ");
649
+ generate_AE(g, p->AE);
650
+ g->B[0] = str_data(loopvar);
651
+ writef(g, "; ~B0 > 0; ~B0--)~N", p);
652
+ writef(g, "~{", p);
653
+
654
+ generate(g, p->left);
655
+
656
+ w(g, "~}");
657
+ str_delete(loopvar);
658
+ g->unreachable = false;
659
+ }
660
+
661
+ static void generate_repeat_or_atleast(struct generator * g, struct node * p, struct str * loopvar) {
662
+ int replab = new_label(g);
663
+ w(g, "~Mreplab");
664
+ write_int(g, replab);
665
+ writef(g, ": while(true)~N~{", p);
666
+
667
+ struct str * savevar = NULL;
668
+ if (repeat_restore(p->left)) {
669
+ savevar = vars_newname(g);
670
+ write_savecursor(g, p, savevar);
671
+ }
672
+
673
+ int label = new_label(g);
674
+ g->failure_label = label;
675
+ str_clear(g->failure_str);
676
+ wsetlab_begin(g, g->failure_label);
677
+
678
+ generate(g, p->left);
679
+
680
+ if (!g->unreachable) {
681
+ if (loopvar != NULL) {
682
+ g->B[0] = str_data(loopvar);
683
+ w(g, "~M~B0--;~N");
684
+ }
685
+
686
+ w(g, "~Mcontinue replab");
687
+ write_int(g, replab);
688
+ w(g, ";~N");
689
+ g->unreachable = true;
690
+ }
691
+
692
+ wsetlab_end(g, g->failure_label);
693
+ g->unreachable = false;
694
+
695
+ if (savevar) {
696
+ write_restorecursor(g, p, savevar);
697
+ str_delete(savevar);
698
+ }
699
+
700
+ w(g, "~Mbreak replab");
701
+ write_int(g, replab);
702
+ w(g, ";~N~}");
703
+ }
704
+
705
+ static void generate_repeat(struct generator * g, struct node * p) {
706
+ write_comment(g, p);
707
+ generate_repeat_or_atleast(g, p, NULL);
708
+ }
709
+
710
+ static void generate_atleast(struct generator * g, struct node * p) {
711
+ write_comment(g, p);
712
+
713
+ w(g, "~{");
714
+ struct str * loopvar = vars_newname(g);
715
+ g->B[0] = str_data(loopvar);
716
+ w(g, "~Mint ~B0 = ");
717
+ generate_AE(g, p->AE);
718
+ w(g, ";~N");
719
+ {
720
+ int a0 = g->failure_label;
721
+ struct str * a1 = str_copy(g->failure_str);
722
+
723
+ generate_repeat_or_atleast(g, p, loopvar);
724
+
725
+ g->failure_label = a0;
726
+ str_delete(g->failure_str);
727
+ g->failure_str = a1;
728
+ }
729
+ g->B[0] = str_data(loopvar);
730
+ write_failure_if(g, "~B0 > 0", p);
731
+ w(g, "~}");
732
+ str_delete(loopvar);
733
+ }
734
+
735
+ static void generate_tomark(struct generator * g, struct node * p) {
736
+ write_comment(g, p);
737
+ g->S[0] = p->mode == m_forward ? ">" : "<";
738
+
739
+ w(g, "~Mif (cursor ~S0 "); generate_AE(g, p->AE); w(g, ")~N");
740
+ write_block_start(g);
741
+ write_failure(g);
742
+ write_block_end(g);
743
+ g->unreachable = false;
744
+ w(g, "~Mcursor = "); generate_AE(g, p->AE); writef(g, ";~N", p);
745
+ }
746
+
747
+ static void generate_hop(struct generator * g, struct node * p) {
748
+ write_comment(g, p);
749
+ g->S[0] = p->mode == m_forward ? "+" : "-";
750
+
751
+ w(g, "~{~Mint c = cursor ~S0 ");
752
+ generate_AE(g, p->AE);
753
+ w(g, ";~N");
754
+
755
+ g->S[1] = p->mode == m_forward ? "> limit" : "< limit_backward";
756
+ g->S[2] = p->mode == m_forward ? "<" : ">";
757
+ if (p->AE->type == c_number) {
758
+ // Constant distance hop.
759
+ //
760
+ // No need to check for negative hop as that's converted to false by
761
+ // the analyser.
762
+ write_failure_if(g, "c ~S1", p);
763
+ } else {
764
+ write_failure_if(g, "c ~S1 || c ~S2 cursor", p);
765
+ }
766
+ writef(g, "~Mcursor = c;~N", p);
767
+ writef(g, "~}", p);
768
+ }
769
+
770
+ static void generate_tolimit(struct generator * g, struct node * p) {
771
+ write_comment(g, p);
772
+ g->S[0] = p->mode == m_forward ? "limit" : "limit_backward";
773
+ writef(g, "~Mcursor = ~S0;~N", p);
774
+ }
775
+
776
+ static void generate_leftslice(struct generator * g, struct node * p) {
777
+ write_comment(g, p);
778
+ g->S[0] = p->mode == m_forward ? "bra" : "ket";
779
+ writef(g, "~M~S0 = cursor;~N", p);
780
+ }
781
+
782
+ static void generate_rightslice(struct generator * g, struct node * p) {
783
+ write_comment(g, p);
784
+ g->S[0] = p->mode == m_forward ? "ket" : "bra";
785
+ writef(g, "~M~S0 = cursor;~N", p);
786
+ }
787
+
788
+ static void generate_assignto(struct generator * g, struct node * p) {
789
+ write_comment(g, p);
790
+ writef(g, "~M~V = assign_to();~N", p);
791
+ }
792
+
793
+ static void generate_sliceto(struct generator * g, struct node * p) {
794
+ write_comment(g, p);
795
+ writef(g, "~M~V = slice_to();~N", p);
796
+ }
797
+
798
+ static void generate_address(struct generator * g, struct node * p) {
799
+ symbol * b = p->literalstring;
800
+ if (b != NULL) {
801
+ write_literal_string(g, b);
802
+ } else {
803
+ write_varref(g, p->name);
804
+ }
805
+ }
806
+
807
+ static void generate_insert(struct generator * g, struct node * p, int style) {
808
+ write_comment(g, p);
809
+ int keep_c = style == c_attach;
810
+ if (p->mode == m_backward) keep_c = !keep_c;
811
+ if (keep_c) w(g, "~{~Mint c = cursor;~N");
812
+ writef(g, "~Minsert(cursor, cursor, ", p);
813
+ generate_address(g, p);
814
+ writef(g, ");~N", p);
815
+ if (keep_c) w(g, "~Mcursor = c;~N~}");
816
+ }
817
+
818
+ static void generate_stringassign(struct generator * g, struct node * p) {
819
+ write_comment(g, p);
820
+ int keep_c = p->mode == m_forward; /* like 'attach' */
821
+ if (keep_c) {
822
+ writef(g, "~{~Mint c = cursor;~N", p);
823
+ }
824
+ if (p->mode == m_forward) {
825
+ writef(g, "~Minsert(cursor, limit, ", p);
826
+ } else {
827
+ writef(g, "~Minsert(limit_backward, cursor, ", p);
828
+ }
829
+ generate_address(g, p);
830
+ writef(g, ");~N", p);
831
+ if (keep_c) {
832
+ w(g, "~Mcursor = c;~N~}");
833
+ }
834
+ }
835
+
836
+ static void generate_slicefrom(struct generator * g, struct node * p) {
837
+ write_comment(g, p);
838
+ if (p->literalstring && SIZE(p->literalstring) == 0) {
839
+ w(g, "~Mslice_del();~N");
840
+ return;
841
+ }
842
+ w(g, "~Mslice_from(");
843
+ generate_address(g, p);
844
+ w(g, ");~N");
845
+ }
846
+
847
+ static void generate_setlimit(struct generator * g, struct node * p) {
848
+ write_comment(g, p);
849
+ struct str * varname = vars_newname(g);
850
+
851
+ if (p->left && p->left->type == c_tomark) {
852
+ /* Special case for:
853
+ *
854
+ * setlimit tomark AE for C
855
+ *
856
+ * All uses of setlimit in the current stemmers we ship follow this
857
+ * pattern, and by special-casing we can avoid having to save and
858
+ * restore c.
859
+ */
860
+ struct node * q = p->left;
861
+ write_comment(g, q);
862
+
863
+ g->S[0] = q->mode == m_forward ? ">" : "<";
864
+ w(g, "~Mif (cursor ~S0 "); generate_AE(g, q->AE); w(g, ")~N");
865
+ write_block_start(g);
866
+ write_failure(g);
867
+ write_block_end(g);
868
+ g->unreachable = false;
869
+
870
+ g->B[0] = str_data(varname);
871
+ if (p->mode == m_forward) {
872
+ w(g, "~Mint ~B0 = limit;~N");
873
+ w(g, "~Mlimit = ");
874
+ generate_AE(g, q->AE);
875
+ w(g, ";~N");
876
+ w(g, "~M~B0 -= limit;~N");
877
+ } else {
878
+ w(g, "~Mint ~B0 = limit_backward;~N");
879
+ w(g, "~Mlimit_backward = ");
880
+ generate_AE(g, q->AE);
881
+ w(g, ";~N");
882
+ }
883
+
884
+ if (p->mode == m_forward) {
885
+ str_assign(g->failure_str, "limit += ");
886
+ str_append(g->failure_str, varname);
887
+ str_append_ch(g->failure_str, ';');
888
+ } else {
889
+ str_assign(g->failure_str, "limit_backward = ");
890
+ str_append(g->failure_str, varname);
891
+ str_append_ch(g->failure_str, ';');
892
+ }
893
+ } else {
894
+ struct str * savevar = vars_newname(g);
895
+ write_savecursor(g, p, savevar);
896
+
897
+ generate(g, p->left);
898
+
899
+ if (!g->unreachable) {
900
+ g->B[0] = str_data(varname);
901
+ if (p->mode == m_forward) {
902
+ w(g, "~Mint ~B0 = limit - cursor;~N");
903
+ w(g, "~Mlimit = cursor;~N");
904
+ } else {
905
+ w(g, "~Mint ~B0 = limit_backward;~N");
906
+ w(g, "~Mlimit_backward = cursor;~N");
907
+ }
908
+ write_restorecursor(g, p, savevar);
909
+
910
+ if (p->mode == m_forward) {
911
+ str_assign(g->failure_str, "limit += ");
912
+ str_append(g->failure_str, varname);
913
+ str_append_ch(g->failure_str, ';');
914
+ } else {
915
+ str_assign(g->failure_str, "limit_backward = ");
916
+ str_append(g->failure_str, varname);
917
+ str_append_ch(g->failure_str, ';');
918
+ }
919
+ }
920
+ str_delete(savevar);
921
+ }
922
+
923
+ if (!g->unreachable) {
924
+ generate(g, p->aux);
925
+
926
+ if (!g->unreachable) {
927
+ write_margin(g);
928
+ write_str(g, g->failure_str);
929
+ write_newline(g);
930
+ }
931
+ }
932
+ str_delete(varname);
933
+ }
934
+
935
+ /* dollar sets snowball up to operate on a string variable as if it were the
936
+ * current string */
937
+ static void generate_dollar(struct generator * g, struct node * p) {
938
+ write_comment(g, p);
939
+
940
+ int a0 = g->failure_label;
941
+ struct str * a1 = str_copy(g->failure_str);
942
+ int label = new_label(g);
943
+ g->failure_label = label;
944
+ str_clear(g->failure_str);
945
+
946
+ struct str * savevar = vars_newname(g);
947
+ g->B[0] = str_data(savevar);
948
+ writef(g, "~{~N"
949
+ "~Mfinal SnowballProgram ~B0 = SnowballProgram.from(this);~N", p);
950
+ writef(g, "~Mcurrent = ~V;~N"
951
+ "~Mcursor = 0;~N"
952
+ "~Mlimit = current.length;~N", p);
953
+ if (p->left->possible_signals == -1) {
954
+ /* Assume failure. */
955
+ w(g, "~Mbool ~B0_f = true;~N");
956
+ }
957
+
958
+ wsetlab_begin(g, g->failure_label);
959
+
960
+ generate(g, p->left);
961
+
962
+ if (!g->unreachable && p->left->possible_signals == -1) {
963
+ /* Mark success. */
964
+ g->B[0] = str_data(savevar);
965
+ w(g, "~M~B0_f = false;~N");
966
+ }
967
+
968
+ wsetlab_end(g, g->failure_label);
969
+
970
+ g->failure_label = a0;
971
+ str_delete(g->failure_str);
972
+ g->failure_str = a1;
973
+
974
+ g->B[0] = str_data(savevar);
975
+ writef(g, "~M~V = current;~N"
976
+ "~Mcopy_from(~B0);~N", p);
977
+
978
+ if (p->left->possible_signals == 0) {
979
+ // p->left always signals f.
980
+ write_failure(g);
981
+ } else if (p->left->possible_signals == -1) {
982
+ write_failure_if(g, "~B0_f", p);
983
+ }
984
+ w(g, "~}");
985
+
986
+ str_delete(savevar);
987
+ }
988
+
989
+ static void generate_integer_assign(struct generator * g, struct node * p, const char * s) {
990
+ write_comment(g, p);
991
+ g->S[0] = s;
992
+ writef(g, "~M~V ~S0 ", p);
993
+ generate_AE(g, p->AE);
994
+ w(g, ";~N");
995
+ }
996
+
997
+ static void generate_integer_test(struct generator * g, struct node * p) {
998
+ write_comment(g, p);
999
+ int relop = p->type;
1000
+ int optimise_to_return = tailcallable(g, p);
1001
+ if (optimise_to_return) {
1002
+ w(g, "~Mreturn ");
1003
+ p->right = NULL;
1004
+ } else {
1005
+ w(g, "~Mif (");
1006
+ // We want the inverse of the snowball test here.
1007
+ relop ^= 1;
1008
+ }
1009
+ generate_AE(g, p->left);
1010
+ write_relop(g, relop);
1011
+ generate_AE(g, p->AE);
1012
+ if (optimise_to_return) {
1013
+ w(g, ";~N");
1014
+ } else {
1015
+ w(g, ")~N");
1016
+ write_block_start(g);
1017
+ write_failure(g);
1018
+ write_block_end(g);
1019
+ g->unreachable = false;
1020
+ }
1021
+ }
1022
+
1023
+ static void generate_call(struct generator * g, struct node * p) {
1024
+ int signals = p->name->definition->possible_signals;
1025
+ write_comment(g, p);
1026
+ if (tailcallable(g, p)) {
1027
+ /* Tail call. */
1028
+ writef(g, "~Mreturn ~V();~N", p);
1029
+ p->right = NULL;
1030
+ g->unreachable = true;
1031
+ return;
1032
+ }
1033
+ if (just_return_on_fail(g) && signals == 0) {
1034
+ /* Always fails. */
1035
+ writef(g, "~Mreturn ~V();~N", p);
1036
+ g->unreachable = true;
1037
+ return;
1038
+ }
1039
+ if (signals == 1) {
1040
+ /* Always succeeds. */
1041
+ writef(g, "~M~V();~N", p);
1042
+ } else if (signals == 0) {
1043
+ /* Always fails. */
1044
+ writef(g, "~M~V();~N", p);
1045
+ write_failure(g);
1046
+ } else {
1047
+ write_failure_if(g, "!~V()", p);
1048
+ }
1049
+ }
1050
+
1051
+ static void generate_grouping(struct generator * g, struct node * p, int complement) {
1052
+ write_comment(g, p);
1053
+
1054
+ struct grouping * q = p->name->grouping;
1055
+ g->S[0] = p->mode == m_forward ? "" : "_b";
1056
+ g->S[1] = complement ? "out" : "in";
1057
+ g->I[0] = q->smallest_ch;
1058
+ g->I[1] = q->largest_ch;
1059
+ if (tailcallable(g, p)) {
1060
+ writef(g, "~Mreturn ~S1_grouping~S0(~V, ~I0, ~I1);~N", p);
1061
+ p->right = NULL;
1062
+ } else {
1063
+ write_failure_if(g, "!(~S1_grouping~S0(~V, ~I0, ~I1))", p);
1064
+ }
1065
+ }
1066
+
1067
+ static void generate_namedstring(struct generator * g, struct node * p) {
1068
+ write_comment(g, p);
1069
+ g->S[0] = p->mode == m_forward ? "" : "_b";
1070
+ if (tailcallable(g, p)) {
1071
+ writef(g, "~Mreturn eq_s~S0(~V);~N", p);
1072
+ p->right = NULL;
1073
+ } else {
1074
+ write_failure_if(g, "!(eq_s~S0(~V))", p);
1075
+ }
1076
+ }
1077
+
1078
+ static void generate_literalstring(struct generator * g, struct node * p) {
1079
+ write_comment(g, p);
1080
+ g->S[0] = p->mode == m_forward ? "" : "_b";
1081
+ if (tailcallable(g, p)) {
1082
+ writef(g, "~Mreturn eq_s~S0(~L);~N", p);
1083
+ p->right = NULL;
1084
+ } else {
1085
+ write_failure_if(g, "!(eq_s~S0(~L))", p);
1086
+ }
1087
+ }
1088
+
1089
+ static void generate_define(struct generator * g, struct node * p) {
1090
+ struct name * q = p->name;
1091
+
1092
+ write_newline(g);
1093
+ write_comment(g, p);
1094
+
1095
+ if (q->type != t_routine) {
1096
+ if (SIZE(q->s) == 4 && memcmp(q->s, "stem", 4) == 0) {
1097
+ w(g, "~M@override~N");
1098
+ }
1099
+ }
1100
+ writef(g, "~Mbool ~V() {~+~N", p);
1101
+
1102
+ g->next_label = 0;
1103
+ g->var_number = 0;
1104
+
1105
+ if (q->amongvar_needed) {
1106
+ w(g, "~Mint among_var;~N");
1107
+ }
1108
+
1109
+ /* Declare localised variables. */
1110
+ for (struct name * name = g->analyser->names; name; name = name->next) {
1111
+ if (name->local_to == q) {
1112
+ switch (name->type) {
1113
+ case t_string:
1114
+ w(g, "~MString ");
1115
+ write_varname(g, name);
1116
+ w(g, ";~N");
1117
+ break;
1118
+ case t_integer:
1119
+ w(g, "~Mint ");
1120
+ write_varname(g, name);
1121
+ w(g, ";~N");
1122
+ break;
1123
+ case t_boolean:
1124
+ w(g, "~Mbool ");
1125
+ write_varname(g, name);
1126
+ w(g, ";~N");
1127
+ break;
1128
+ }
1129
+ }
1130
+ }
1131
+
1132
+ str_clear(g->failure_str);
1133
+ g->failure_label = x_return;
1134
+ g->unreachable = false;
1135
+
1136
+ /* Generate function body. */
1137
+ generate(g, p->left);
1138
+ if (p->left->right) {
1139
+ assert(p->left->right->type == c_functionend);
1140
+ if (p->left->possible_signals) {
1141
+ generate(g, p->left->right);
1142
+ }
1143
+ }
1144
+ w(g, "~}");
1145
+ }
1146
+
1147
+ static void generate_functionend(struct generator * g, struct node * p) {
1148
+ (void)p;
1149
+ w(g, "~Mreturn true;~N");
1150
+ }
1151
+
1152
+ static void generate_substring(struct generator * g, struct node * p) {
1153
+ write_comment(g, p);
1154
+
1155
+ struct among * x = p->among;
1156
+
1157
+ g->S[0] = p->mode == m_forward ? "" : "_b";
1158
+ g->I[0] = x->number;
1159
+
1160
+ if (x->amongvar_needed) {
1161
+ writef(g, "~Mamong_var = find_among~S0(a_~I0, ~F);~N", p);
1162
+ if (!x->always_matches) {
1163
+ write_failure_if(g, "among_var == 0", p);
1164
+ }
1165
+ } else if (x->always_matches) {
1166
+ writef(g, "~Mfind_among~S0(a_~I0, ~F);~N", p);
1167
+ } else if (x->command_count == 0 && tailcallable(g, p)) {
1168
+ writef(g, "~Mreturn find_among~S0(a_~I0, ~F) != 0;~N", p);
1169
+ x->node->right = NULL;
1170
+ g->unreachable = true;
1171
+ } else {
1172
+ write_failure_if(g, "find_among~S0(a_~I0, ~F) == 0", p);
1173
+ }
1174
+ }
1175
+
1176
+ static void generate_among(struct generator * g, struct node * p) {
1177
+ struct among * x = p->among;
1178
+
1179
+ if (x->substring == NULL) {
1180
+ generate_substring(g, p);
1181
+ } else {
1182
+ write_comment(g, p);
1183
+ }
1184
+
1185
+ if (x->command_count == 1 && x->nocommand_count == 0) {
1186
+ /* Only one outcome ("no match" already handled). */
1187
+ generate(g, x->commands[0]);
1188
+ } else if (x->command_count > 0) {
1189
+ w(g, "~Mswitch (among_var) {~N~+");
1190
+ for (int i = 1; i <= x->command_count; i++) {
1191
+ g->I[0] = i;
1192
+ w(g, "~Mcase ~I0:~N~+");
1193
+ generate(g, x->commands[i - 1]);
1194
+ if (!g->unreachable) w(g, "~Mbreak;~N");
1195
+ w(g, "~-");
1196
+ g->unreachable = false;
1197
+ }
1198
+ write_block_end(g);
1199
+ }
1200
+ }
1201
+
1202
+ static void generate_booltest(struct generator * g, struct node * p, int inverted) {
1203
+ write_comment(g, p);
1204
+ if (tailcallable(g, p)) {
1205
+ // Optimise at end of function.
1206
+ if (inverted) {
1207
+ writef(g, "~Mreturn !~V;~N", p);
1208
+ } else {
1209
+ writef(g, "~Mreturn ~V;~N", p);
1210
+ }
1211
+ p->right = NULL;
1212
+ g->unreachable = true;
1213
+ return;
1214
+ }
1215
+ if (inverted) {
1216
+ write_failure_if(g, "~V", p);
1217
+ } else {
1218
+ write_failure_if(g, "!~V", p);
1219
+ }
1220
+ }
1221
+
1222
+ static void generate_false(struct generator * g, struct node * p) {
1223
+ write_comment(g, p);
1224
+ write_failure(g);
1225
+ }
1226
+
1227
+ static void generate_debug(struct generator * g, struct node * p) {
1228
+ write_comment(g, p);
1229
+ g->I[0] = g->debug_count++;
1230
+ g->I[1] = p->line_number;
1231
+ writef(g, "~Mdebug(~I0, ~I1);~N", p);
1232
+ }
1233
+
1234
+ static void generate(struct generator * g, struct node * p) {
1235
+ if (g->unreachable) return;
1236
+
1237
+ int a0 = g->failure_label;
1238
+ struct str * a1 = str_copy(g->failure_str);
1239
+
1240
+ switch (p->type) {
1241
+ case c_define: generate_define(g, p); break;
1242
+ case c_bra: generate_bra(g, p); break;
1243
+ case c_and: generate_and(g, p); break;
1244
+ case c_or: generate_or(g, p); break;
1245
+ case c_backwards: generate_backwards(g, p); break;
1246
+ case c_not: generate_not(g, p); break;
1247
+ case c_set: generate_set(g, p); break;
1248
+ case c_unset: generate_unset(g, p); break;
1249
+ case c_try: generate_try(g, p); break;
1250
+ case c_fail: generate_fail(g, p); break;
1251
+ case c_reverse:
1252
+ case c_test: generate_test(g, p); break;
1253
+ case c_do: generate_do(g, p); break;
1254
+ case c_goto: generate_GO(g, p, 1); break;
1255
+ case c_gopast: generate_GO(g, p, 0); break;
1256
+ case c_goto_grouping: generate_GO_grouping(g, p, 1, 0); break;
1257
+ case c_gopast_grouping:
1258
+ generate_GO_grouping(g, p, 0, 0); break;
1259
+ case c_goto_non: generate_GO_grouping(g, p, 1, 1); break;
1260
+ case c_gopast_non: generate_GO_grouping(g, p, 0, 1); break;
1261
+ case c_repeat: generate_repeat(g, p); break;
1262
+ case c_loop: generate_loop(g, p); break;
1263
+ case c_atleast: generate_atleast(g, p); break;
1264
+ case c_tomark: generate_tomark(g, p); break;
1265
+ case c_hop: generate_hop(g, p); break;
1266
+ case c_next: generate_next(g, p); break;
1267
+ case c_tolimit: generate_tolimit(g, p); break;
1268
+ case c_leftslice: generate_leftslice(g, p); break;
1269
+ case c_rightslice: generate_rightslice(g, p); break;
1270
+ case c_assignto: generate_assignto(g, p); break;
1271
+ case c_sliceto: generate_sliceto(g, p); break;
1272
+ case c_stringassign: generate_stringassign(g, p); break;
1273
+ case c_insert:
1274
+ case c_attach: generate_insert(g, p, p->type); break;
1275
+ case c_slicefrom: generate_slicefrom(g, p); break;
1276
+ case c_setlimit: generate_setlimit(g, p); break;
1277
+ case c_dollar: generate_dollar(g, p); break;
1278
+ case c_assign: generate_integer_assign(g, p, "="); break;
1279
+ case c_plusassign: generate_integer_assign(g, p, "+="); break;
1280
+ case c_minusassign: generate_integer_assign(g, p, "-="); break;
1281
+ case c_multiplyassign:generate_integer_assign(g, p, "*="); break;
1282
+ case c_divideassign: generate_integer_assign(g, p, "~/="); break;
1283
+ case c_eq:
1284
+ case c_ne:
1285
+ case c_gt:
1286
+ case c_ge:
1287
+ case c_lt:
1288
+ case c_le:
1289
+ generate_integer_test(g, p);
1290
+ break;
1291
+ case c_call: generate_call(g, p); break;
1292
+ case c_grouping: generate_grouping(g, p, false); break;
1293
+ case c_non: generate_grouping(g, p, true); break;
1294
+ case c_name: generate_namedstring(g, p); break;
1295
+ case c_literalstring: generate_literalstring(g, p); break;
1296
+ case c_among: generate_among(g, p); break;
1297
+ case c_substring: generate_substring(g, p); break;
1298
+ case c_booltest: generate_booltest(g, p, false); break;
1299
+ case c_not_booltest: generate_booltest(g, p, true); break;
1300
+ case c_false: generate_false(g, p); break;
1301
+ case c_true: break;
1302
+ case c_debug: generate_debug(g, p); break;
1303
+ case c_functionend: generate_functionend(g, p); break;
1304
+ default: fprintf(stderr, "%d encountered\n", p->type);
1305
+ exit(1);
1306
+ }
1307
+
1308
+ g->failure_label = a0;
1309
+ str_delete(g->failure_str);
1310
+ g->failure_str = a1;
1311
+ }
1312
+
1313
+ static void generate_class_begin(struct generator * g) {
1314
+ w(g, "// ignore_for_file: non_constant_identifier_names, slash_for_doc_comments, camel_case_types~N~N");
1315
+
1316
+ w(g, "import '../src/snowball.dart';~N~N");
1317
+
1318
+ w(g, "/**~N"
1319
+ " * This class implements the stemming algorithm defined by a snowball script.~N"
1320
+ " *~N"
1321
+ " * ");
1322
+ write_generated_comment_content(g);
1323
+ w(g, "~N */~N"
1324
+ "class ~n extends ");
1325
+ write_string(g, g->options->parent_class_name);
1326
+ w(g, " {~+~N");
1327
+ }
1328
+
1329
+ static void generate_class_end(struct generator * g) {
1330
+ w(g, "~-~M~N");
1331
+ w(g, "}~N");
1332
+ }
1333
+
1334
+ static void generate_equals(struct generator * g) {
1335
+ w(g, "~N"
1336
+ "~M@override~N"
1337
+ "~Mbool operator ==(Object other) => other is ");
1338
+ write_s(g, g->options->name);
1339
+ w(g, ";~N~N"
1340
+ "~M@override~N"
1341
+ "~Mint get hashCode => runtimeType.toString().hashCode;~N");
1342
+ }
1343
+
1344
+ static void generate_among_table(struct generator * g, struct among * x) {
1345
+ write_comment(g, x->node);
1346
+
1347
+ struct amongvec * v = x->b;
1348
+
1349
+ g->I[0] = x->number;
1350
+
1351
+ w(g, "~Mstatic final a_~I0 = [~N~+");
1352
+ for (int i = 0; i < x->literalstring_count; i++) {
1353
+ if (i) w(g, ",~N");
1354
+ g->I[3] = v[i].i;
1355
+ g->I[4] = v[i].result;
1356
+ g->I[5] = v[i].function_index;
1357
+
1358
+ w(g, "~MAmong(");
1359
+ write_literal_string(g, v[i].b);
1360
+ w(g, ", ~I3, ~I4, ~I5)");
1361
+ }
1362
+ w(g, "~N~-~M];~N~N");
1363
+
1364
+ if (x->function_count <= 1) return;
1365
+
1366
+ w(g, "~N~Mbool af_~I0() {~N~+");
1367
+ w(g, "~Mswitch (af) {~N~+");
1368
+ for (int n = 1; n <= x->function_count; n++) {
1369
+ w(g, "~Mcase ");
1370
+ write_int(g, n);
1371
+ w(g, ": return ");
1372
+ for (int i = 0; i < x->literalstring_count; i++) {
1373
+ if (v[i].function_index == n) {
1374
+ write_varref(g, v[i].function);
1375
+ w(g, "();~N");
1376
+ break;
1377
+ }
1378
+ }
1379
+ }
1380
+ w(g, "~-~M}~N");
1381
+ w(g, "~Mreturn false;~N");
1382
+ w(g, "~-~M}~N");
1383
+ }
1384
+
1385
+ static void generate_amongs(struct generator * g) {
1386
+ for (struct among * x = g->analyser->amongs; x; x = x->next) {
1387
+ generate_among_table(g, x);
1388
+ }
1389
+ }
1390
+
1391
+ static void set_bit(symbol * b, int i) { b[i >> 3] |= 1 << (i & 7); }
1392
+
1393
+ static void generate_grouping_table(struct generator * g, struct grouping * q) {
1394
+ int range = q->largest_ch - q->smallest_ch + 1;
1395
+ int size = (range + 7) / 8; /* assume 8 bits per symbol */
1396
+ symbol * b = q->b;
1397
+ symbol * map = create_b(size);
1398
+
1399
+ for (int i = 0; i < size; i++) map[i] = 0;
1400
+
1401
+ for (int i = 0; i < SIZE(b); i++) set_bit(map, b[i] - q->smallest_ch);
1402
+
1403
+ w(g, "~Mstatic final ");
1404
+ write_varname(g, q->name);
1405
+ write_string(g, " = String.fromCharCodes([");
1406
+ for (int i = 0; i < size; i++) {
1407
+ if (i) w(g, ", ");
1408
+ write_int(g, map[i]);
1409
+ }
1410
+ w(g, "]);~N~N");
1411
+
1412
+ lose_b(map);
1413
+ }
1414
+
1415
+ static void generate_groupings(struct generator * g) {
1416
+ for (struct grouping * q = g->analyser->groupings; q; q = q->next) {
1417
+ generate_grouping_table(g, q);
1418
+ }
1419
+ }
1420
+
1421
+ static void generate_members(struct generator * g) {
1422
+ bool wrote_members = false;
1423
+
1424
+ for (struct name * q = g->analyser->names; q; q = q->next) {
1425
+ if (q->local_to) continue;
1426
+ switch (q->type) {
1427
+ case t_string:
1428
+ w(g, "~MString ");
1429
+ write_varname(g, q);
1430
+ w(g, " = '';~N");
1431
+ wrote_members = true;
1432
+ break;
1433
+ case t_integer:
1434
+ w(g, "~Mint ");
1435
+ write_varname(g, q);
1436
+ w(g, " = 0;~N");
1437
+ wrote_members = true;
1438
+ break;
1439
+ case t_boolean:
1440
+ w(g, "~Mbool ");
1441
+ write_varname(g, q);
1442
+ w(g, " = false;~N");
1443
+ wrote_members = true;
1444
+ break;
1445
+ }
1446
+ }
1447
+ if (wrote_members) w(g, "~N");
1448
+ }
1449
+
1450
+ static void generate_methods(struct generator * g) {
1451
+ for (struct node * p = g->analyser->program; p; p = p->right) {
1452
+ generate(g, p);
1453
+ g->unreachable = false;
1454
+ }
1455
+ }
1456
+
1457
+ extern void generate_program_dart(struct generator * g) {
1458
+ g->outbuf = str_new();
1459
+ g->failure_str = str_new();
1460
+
1461
+ write_start_comment(g, "// ", NULL);
1462
+ generate_class_begin(g);
1463
+
1464
+ generate_amongs(g);
1465
+ generate_groupings(g);
1466
+
1467
+ generate_members(g);
1468
+ generate_methods(g);
1469
+ generate_equals(g);
1470
+
1471
+ generate_class_end(g);
1472
+
1473
+ output_str(g->options->output_src, g->outbuf);
1474
+ str_delete(g->failure_str);
1475
+ str_delete(g->outbuf);
1476
+ }