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