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