Skip to content

Commit f60f402

Browse files
committed
Refactor to pull much of the NFA runner out of the op body.
1 parent ac5f5fc commit f60f402

File tree

1 file changed

+144
-134
lines changed

1 file changed

+144
-134
lines changed

src/ops/nqp.ops

Lines changed: 144 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,143 @@ INTVAL quicksort(INTVAL *arr, INTVAL elements) {
132132
return 1;
133133
}
134134

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+
135272
END_OPS_PREAMBLE
136273

137274
/*
@@ -2197,143 +2334,16 @@ inline op nqp_push_label(in PMC, in LABEL) :base_core {
21972334
}
21982335

21992336
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);
22102340

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);
23352343
for (i = 0; i < total_fates; i++)
23362344
VTABLE_set_integer_keyed_int(interp, fatepmc, i, fates[i]);
2345+
free(fates);
2346+
23372347
$1 = fatepmc;
23382348
}
23392349

0 commit comments

Comments
 (0)