@@ -132,6 +132,143 @@ INTVAL quicksort(INTVAL *arr, INTVAL elements) {
132
132
return 1;
133
133
}
134
134
135
+ /* Does a run of the NFA. Produces a list of integers indicating the
136
+ * chosen ordering. */
137
+ static INTVAL * nqp_nfa_run(PARROT_INTERP, PMC *states, STRING *target, INTVAL offset, INTVAL *total_fates_out) {
138
+ INTVAL eos = Parrot_str_length(interp, target);
139
+ INTVAL gen = 1;
140
+ PMC *curst = nfa_curst;
141
+ PMC *nextst = nfa_nextst;
142
+ INTVAL *done, *fates;
143
+ INTVAL i, num_states, total_fates, prev_fates;
144
+
145
+ /* Zero out the done array; we don't get zeroed memory by default. */
146
+ num_states = VTABLE_elements(interp, states);
147
+ done = mem_sys_allocate_zeroed(num_states * sizeof(INTVAL));
148
+
149
+ /* Clear out other re-used arrays. */
150
+ VTABLE_set_integer_native(interp, curst, 0);
151
+ VTABLE_set_integer_native(interp, nextst, 0);
152
+
153
+ /* Allocate fates array. */
154
+ fates = mem_sys_allocate(sizeof(INTVAL) * (1 + VTABLE_elements(interp,
155
+ VTABLE_get_pmc_keyed_int(interp, states, 0))));
156
+ total_fates = 0;
157
+
158
+ VTABLE_push_integer(interp, nextst, 1);
159
+ while (VTABLE_elements(interp, nextst) && offset <= eos) {
160
+ /* Translation of:
161
+ * my @curst := @nextst;
162
+ * @nextst := [];
163
+ * But avoids an extra allocation per offset. */
164
+ PMC *temp = curst;
165
+ curst = nextst;
166
+ VTABLE_set_integer_native(interp, temp, 0);
167
+ nextst = temp;
168
+
169
+ /* Save how many fates we have before this position is considered. */
170
+ prev_fates = total_fates;
171
+
172
+ while (VTABLE_elements(interp, curst)) {
173
+ PMC *edge_info;
174
+ INTVAL edge_info_elems;
175
+
176
+ INTVAL st = VTABLE_pop_integer(interp, curst);
177
+ if (st < num_states) {
178
+ if (done[st] == gen)
179
+ continue;
180
+ done[st] = gen;
181
+ }
182
+
183
+ edge_info = VTABLE_get_pmc_keyed_int(interp, states, st);
184
+ edge_info_elems = VTABLE_elements(interp, edge_info);
185
+ for (i = 0; i < edge_info_elems; i += 3) {
186
+ INTVAL act = VTABLE_get_integer_keyed_int(interp, edge_info, i);
187
+ INTVAL to = VTABLE_get_integer_keyed_int(interp, edge_info, i + 2);
188
+
189
+ if (act == EDGE_FATE) {
190
+ /* Crossed a fate edge. Check if we already saw this, and
191
+ * if so bump the entry we already saw. */
192
+ INTVAL arg = VTABLE_get_integer_keyed_int(interp, edge_info, i + 1);
193
+ INTVAL j;
194
+ INTVAL found_fate = 0;
195
+ for (j = 0; j < total_fates; j++) {
196
+ if (found_fate)
197
+ fates[j - 1] = fates[j];
198
+ if (fates[j] == arg) {
199
+ found_fate = 1;
200
+ if (j < prev_fates)
201
+ prev_fates--;
202
+ }
203
+ }
204
+ if (found_fate)
205
+ fates[total_fates - 1] = arg;
206
+ else
207
+ fates[total_fates++] = arg;
208
+ }
209
+ else if (act == EDGE_EPSILON && to < num_states && done[to] != gen) {
210
+ VTABLE_push_integer(interp, curst, to);
211
+ }
212
+ else if (offset >= eos) {
213
+ /* Can't match, so drop state. */
214
+ }
215
+ else if (act == EDGE_CODEPOINT) {
216
+ UINTVAL arg = VTABLE_get_integer_keyed_int(interp, edge_info, i + 1);
217
+ if (STRING_ord(interp, target, offset) == arg)
218
+ VTABLE_push_integer(interp, nextst, to);
219
+ }
220
+ else if (act == EDGE_CODEPOINT_NEG) {
221
+ UINTVAL arg = VTABLE_get_integer_keyed_int(interp, edge_info, i + 1);
222
+ if (STRING_ord(interp, target, offset) != arg)
223
+ VTABLE_push_integer(interp, nextst, to);
224
+ }
225
+ else if (act == EDGE_CHARCLASS) {
226
+ INTVAL arg = VTABLE_get_integer_keyed_int(interp, edge_info, i + 1);
227
+ if (Parrot_str_is_cclass(interp, arg, target, offset))
228
+ VTABLE_push_integer(interp, nextst, to);
229
+ }
230
+ else if (act == EDGE_CHARCLASS_NEG) {
231
+ INTVAL arg = VTABLE_get_integer_keyed_int(interp, edge_info, i + 1);
232
+ if (!Parrot_str_is_cclass(interp, arg, target, offset))
233
+ VTABLE_push_integer(interp, nextst, to);
234
+ }
235
+ else if (act == EDGE_CHARLIST) {
236
+ STRING *arg = VTABLE_get_string_keyed_int(interp, edge_info, i + 1);
237
+ STRING *chr = STRING_substr(interp, target, offset, 1);
238
+ if (STRING_index(interp, arg, chr, 0) >= 0)
239
+ VTABLE_push_integer(interp, nextst, to);
240
+ }
241
+ else if (act == EDGE_CHARLIST_NEG) {
242
+ STRING *arg = VTABLE_get_string_keyed_int(interp, edge_info, i + 1);
243
+ STRING *chr = STRING_substr(interp, target, offset, 1);
244
+ if (STRING_index(interp, arg, chr, 0) < 0)
245
+ VTABLE_push_integer(interp, nextst, to);
246
+ }
247
+ }
248
+ }
249
+
250
+ /* Move to next character and generation. */
251
+ offset++;
252
+ gen++;
253
+
254
+ /* If we got multiple fates at this offset, sort them by the
255
+ * declaration order (represented by the fate number). In the
256
+ * future, we'll want to factor in longest literal prefix too. */
257
+ if (total_fates - prev_fates > 1) {
258
+ INTVAL char_fates = total_fates - prev_fates;
259
+ for (i = total_fates - char_fates; i < total_fates; i++)
260
+ fates[i] = -fates[i];
261
+ quicksort(&fates[total_fates - char_fates], char_fates);
262
+ for (i = total_fates - char_fates; i < total_fates; i++)
263
+ fates[i] = -fates[i];
264
+ }
265
+ }
266
+ mem_sys_free(done);
267
+
268
+ *total_fates_out = total_fates;
269
+ return fates;
270
+ }
271
+
135
272
END_OPS_PREAMBLE
136
273
137
274
/*
@@ -2197,143 +2334,16 @@ inline op nqp_push_label(in PMC, in LABEL) :base_core {
2197
2334
}
2198
2335
2199
2336
inline op nqp_nfa_run_new(out PMC, in PMC, in STR, in INT) :base_core {
2200
- PMC *states = $2;
2201
- STRING *target = $3;
2202
- INTVAL offset = $4;
2203
- INTVAL eos = Parrot_str_length(interp, target);
2204
- PMC *fatepmc = Parrot_pmc_new(interp, enum_class_ResizableIntegerArray);
2205
- INTVAL gen = 1;
2206
- PMC *curst = nfa_curst;
2207
- PMC *nextst = nfa_nextst;
2208
- INTVAL *done, *fates;
2209
- INTVAL i, num_states, total_fates, prev_fates;
2337
+ /* Run the NFA. */
2338
+ INTVAL total_fates, i;
2339
+ INTVAL *fates = nqp_nfa_run(interp, $2, $3, $4, &total_fates);
2210
2340
2211
- /* Zero out the done array; we don't get zeroed memory by default. */
2212
- num_states = VTABLE_elements(interp, states);
2213
- done = mem_sys_allocate_zeroed(num_states * sizeof(INTVAL));
2214
-
2215
- /* Clear out other re-used arrays. */
2216
- VTABLE_set_integer_native(interp, curst, 0);
2217
- VTABLE_set_integer_native(interp, nextst, 0);
2218
-
2219
- /* Allocate fates array. */
2220
- fates = mem_sys_allocate(sizeof(INTVAL) * (1 + VTABLE_elements(interp,
2221
- VTABLE_get_pmc_keyed_int(interp, states, 0))));
2222
- total_fates = 0;
2223
-
2224
- VTABLE_push_integer(interp, nextst, 1);
2225
- while (VTABLE_elements(interp, nextst) && offset <= eos) {
2226
- /* Translation of:
2227
- * my @curst := @nextst;
2228
- * @nextst := [];
2229
- * But avoids an extra allocation per offset. */
2230
- PMC *temp = curst;
2231
- curst = nextst;
2232
- VTABLE_set_integer_native(interp, temp, 0);
2233
- nextst = temp;
2234
-
2235
- /* Save how many fates we have before this position is considered. */
2236
- prev_fates = total_fates;
2237
-
2238
- while (VTABLE_elements(interp, curst)) {
2239
- PMC *edge_info;
2240
- INTVAL edge_info_elems;
2241
-
2242
- INTVAL st = VTABLE_pop_integer(interp, curst);
2243
- if (st < num_states) {
2244
- if (done[st] == gen)
2245
- continue;
2246
- done[st] = gen;
2247
- }
2248
-
2249
- edge_info = VTABLE_get_pmc_keyed_int(interp, states, st);
2250
- edge_info_elems = VTABLE_elements(interp, edge_info);
2251
- for (i = 0; i < edge_info_elems; i += 3) {
2252
- INTVAL act = VTABLE_get_integer_keyed_int(interp, edge_info, i);
2253
- INTVAL to = VTABLE_get_integer_keyed_int(interp, edge_info, i + 2);
2254
-
2255
- if (act == EDGE_FATE) {
2256
- /* Crossed a fate edge. Check if we already saw this, and
2257
- * if so bump the entry we already saw. */
2258
- INTVAL arg = VTABLE_get_integer_keyed_int(interp, edge_info, i + 1);
2259
- INTVAL j;
2260
- INTVAL found_fate = 0;
2261
- for (j = 0; j < total_fates; j++) {
2262
- if (found_fate)
2263
- fates[j - 1] = fates[j];
2264
- if (fates[j] == arg) {
2265
- found_fate = 1;
2266
- if (j < prev_fates)
2267
- prev_fates--;
2268
- }
2269
- }
2270
- if (found_fate)
2271
- fates[total_fates - 1] = arg;
2272
- else
2273
- fates[total_fates++] = arg;
2274
- }
2275
- else if (act == EDGE_EPSILON && to < num_states && done[to] != gen) {
2276
- VTABLE_push_integer(interp, curst, to);
2277
- }
2278
- else if (offset >= eos) {
2279
- /* Can't match, so drop state. */
2280
- }
2281
- else if (act == EDGE_CODEPOINT) {
2282
- UINTVAL arg = VTABLE_get_integer_keyed_int(interp, edge_info, i + 1);
2283
- if (STRING_ord(interp, target, offset) == arg)
2284
- VTABLE_push_integer(interp, nextst, to);
2285
- }
2286
- else if (act == EDGE_CODEPOINT_NEG) {
2287
- UINTVAL arg = VTABLE_get_integer_keyed_int(interp, edge_info, i + 1);
2288
- if (STRING_ord(interp, target, offset) != arg)
2289
- VTABLE_push_integer(interp, nextst, to);
2290
- }
2291
- else if (act == EDGE_CHARCLASS) {
2292
- INTVAL arg = VTABLE_get_integer_keyed_int(interp, edge_info, i + 1);
2293
- if (Parrot_str_is_cclass(interp, arg, target, offset))
2294
- VTABLE_push_integer(interp, nextst, to);
2295
- }
2296
- else if (act == EDGE_CHARCLASS_NEG) {
2297
- INTVAL arg = VTABLE_get_integer_keyed_int(interp, edge_info, i + 1);
2298
- if (!Parrot_str_is_cclass(interp, arg, target, offset))
2299
- VTABLE_push_integer(interp, nextst, to);
2300
- }
2301
- else if (act == EDGE_CHARLIST) {
2302
- STRING *arg = VTABLE_get_string_keyed_int(interp, edge_info, i + 1);
2303
- STRING *chr = STRING_substr(interp, target, offset, 1);
2304
- if (STRING_index(interp, arg, chr, 0) >= 0)
2305
- VTABLE_push_integer(interp, nextst, to);
2306
- }
2307
- else if (act == EDGE_CHARLIST_NEG) {
2308
- STRING *arg = VTABLE_get_string_keyed_int(interp, edge_info, i + 1);
2309
- STRING *chr = STRING_substr(interp, target, offset, 1);
2310
- if (STRING_index(interp, arg, chr, 0) < 0)
2311
- VTABLE_push_integer(interp, nextst, to);
2312
- }
2313
- }
2314
- }
2315
-
2316
- /* Move to next character and generation. */
2317
- offset++;
2318
- gen++;
2319
-
2320
- /* If we got multiple fates at this offset, sort them by the
2321
- * declaration order (represented by the fate number). In the
2322
- * future, we'll want to factor in longest literal prefix too. */
2323
- if (total_fates - prev_fates > 1) {
2324
- INTVAL char_fates = total_fates - prev_fates;
2325
- for (i = total_fates - char_fates; i < total_fates; i++)
2326
- fates[i] = -fates[i];
2327
- quicksort(&fates[total_fates - char_fates], char_fates);
2328
- for (i = total_fates - char_fates; i < total_fates; i++)
2329
- fates[i] = -fates[i];
2330
- }
2331
- }
2332
- mem_sys_free(done);
2333
-
2334
- /* Copy fates managed in C array into result PMC. */
2341
+ /* Copy results into an RIA. */
2342
+ PMC *fatepmc = Parrot_pmc_new(interp, enum_class_ResizableIntegerArray);
2335
2343
for (i = 0; i < total_fates; i++)
2336
2344
VTABLE_set_integer_keyed_int(interp, fatepmc, i, fates[i]);
2345
+ free(fates);
2346
+
2337
2347
$1 = fatepmc;
2338
2348
}
2339
2349
0 commit comments