Try to address memoization problem in pegs.

This commit is contained in:
Calvin Rose 2019-08-29 19:09:43 -05:00
parent d4b49cd622
commit 8bc8709d0e
2 changed files with 26 additions and 8 deletions

View File

@ -426,7 +426,7 @@ tail:
Janet capture = s->captures->data[i];
if (!janet_checktype(capture, JANET_STRING))
return NULL;
const uint8_t *bytes = janet_unwrap_string(capture);
const uint8_t *bytes = janet_unwrap_string(capture);
int32_t len = janet_string_length(bytes);
if (text + len > s->text_end)
return NULL;
@ -879,10 +879,14 @@ static const SpecialPair peg_specials[] = {
static uint32_t peg_compile1(Builder *b, Janet peg) {
/* Check for already compiled rules */
Janet check = janet_table_get(b->memoized, peg);
if (!janet_checktype(check, JANET_NIL)) {
uint32_t rule = (uint32_t) janet_unwrap_number(check);
return rule;
int is_keyword = janet_checktype(peg, JANET_KEYWORD);
Janet old_memo = janet_wrap_nil(); /* for compiler warnings */
if (is_keyword) {
old_memo = janet_table_get(b->memoized, peg);
if (!janet_checktype(old_memo, JANET_NIL)) {
uint32_t rule = (uint32_t) janet_unwrap_number(old_memo);
return rule;
}
}
/* Keep track of the form being compiled for error purposes */
@ -896,10 +900,10 @@ static uint32_t peg_compile1(Builder *b, Janet peg) {
/* The final rule to return */
uint32_t rule = janet_v_count(b->bytecode);
if (!janet_checktype(peg, JANET_KEYWORD) &&
!janet_checktype(peg, JANET_STRUCT)) {
/* Cache keywords for recursion points (loops) */
if (is_keyword)
janet_table_put(b->memoized, peg, janet_wrap_number(rule));
}
switch (janet_type(peg)) {
default:
@ -960,6 +964,10 @@ static uint32_t peg_compile1(Builder *b, Janet peg) {
}
}
/* Reset old cached rule */
if (is_keyword)
janet_table_put(b->memoized, peg, old_memo);
/* Increase depth again */
b->depth++;
b->form = old_form;

View File

@ -421,4 +421,14 @@
(assert (= (tuple/type (-> '(1 2 3) marshal unmarshal)) :parens) "normal tuple marshalled/unmarshalled")
(assert (= (tuple/type (-> '[1 2 3] marshal unmarshal)) :brackets) "normal tuple marshalled/unmarshalled")
# Check for bad memoization (+ :a) should mean different things in different contexts.
(def redef-a
~{:a "abc"
:c (+ :a)
:main (* :c {:a "def" :main (+ :a)} -1)})
(check-match redef-a "abcdef" true)
(check-match redef-a "abcabc" false)
(check-match redef-a "defdef" false)
(end-suite)