mittens 0.1.0

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