mirror of
https://github.com/janet-lang/janet
synced 2024-11-29 03:19:54 +00:00
Simplify peg caching further.
Remove the multiple caching tables we were using and use the grammar table for caching. This works well because we can use raw_get for checking the local cache, and normal get fro checking the global cache.
This commit is contained in:
parent
54a04b5894
commit
98eaadf2d1
@ -445,8 +445,6 @@ tail:
|
||||
|
||||
typedef struct {
|
||||
JanetTable *grammar;
|
||||
JanetTable *memoized;
|
||||
JanetTable *memoized_scopes;
|
||||
JanetTable *tags;
|
||||
Janet *constants;
|
||||
uint32_t *bytecode;
|
||||
@ -881,16 +879,54 @@ static uint32_t peg_compile1(Builder *b, Janet peg) {
|
||||
|
||||
/* Keep track of the form being compiled for error purposes */
|
||||
Janet old_form = b->form;
|
||||
JanetTable *old_grammar = b->grammar;
|
||||
b->form = peg;
|
||||
|
||||
/* Check depth */
|
||||
if (b->depth-- == 0) {
|
||||
peg_panic(b, "peg grammar recursed too deeply");
|
||||
/* Resolve keyword references */
|
||||
int i = JANET_RECURSION_GUARD;
|
||||
JanetTable *grammar = old_grammar;
|
||||
for (; i > 0 && janet_checktype(peg, JANET_KEYWORD); --i) {
|
||||
peg = janet_table_get_ex(grammar, peg, &grammar);
|
||||
if (!grammar)
|
||||
peg_panic(b, "unknown rule");
|
||||
b->form = peg;
|
||||
b->grammar = grammar;
|
||||
}
|
||||
if (i == 0)
|
||||
peg_panic(b, "reference chain too deep");
|
||||
|
||||
/* Check cache - for tuples we check only the local cache, as
|
||||
* in a different grammar, the same tuple can compile to a different
|
||||
* rule - for example, (+ :a :b) depends on whatever :a and :b are bound to. */
|
||||
Janet check = janet_checktype(peg, JANET_TUPLE)
|
||||
? janet_table_rawget(grammar, peg)
|
||||
: janet_table_get(grammar, peg);
|
||||
if (!janet_checktype(check, JANET_NIL)) {
|
||||
b->form = old_form;
|
||||
b->grammar = old_grammar;
|
||||
return (uint32_t) janet_unwrap_number(check);
|
||||
}
|
||||
|
||||
/* Check depth */
|
||||
if (b->depth-- == 0)
|
||||
peg_panic(b, "peg grammar recursed too deeply");
|
||||
|
||||
/* The final rule to return */
|
||||
uint32_t rule = janet_v_count(b->bytecode);
|
||||
|
||||
/* Add to cache. Do not cache structs, as we don't yet know
|
||||
* what rule they will return! We can just as effectively cache
|
||||
* the structs main rule. */
|
||||
if (!janet_checktype(peg, JANET_STRUCT)) {
|
||||
JanetTable *which_grammar = grammar;
|
||||
/* If we are a primitive pattern, add to the global cache (root grammar table) */
|
||||
if (!janet_checktype(peg, JANET_TUPLE)) {
|
||||
while (which_grammar->proto)
|
||||
which_grammar = which_grammar->proto;
|
||||
}
|
||||
janet_table_put(which_grammar, peg, janet_wrap_number(rule));
|
||||
}
|
||||
|
||||
switch (janet_type(peg)) {
|
||||
default:
|
||||
peg_panic(b, "unexpected peg source");
|
||||
@ -911,37 +947,22 @@ static uint32_t peg_compile1(Builder *b, Janet peg) {
|
||||
emit_bytes(b, RULE_LITERAL, len, str);
|
||||
break;
|
||||
}
|
||||
case JANET_KEYWORD: {
|
||||
/* Find rule in grammar */
|
||||
JanetTable *scope = NULL;
|
||||
Janet check = janet_table_get_ex(b->grammar, peg, &scope);
|
||||
if (scope == NULL)
|
||||
peg_panic(b, "unknown rule");
|
||||
|
||||
/* Check if we should compile as a recursion */
|
||||
Janet memo_rule = janet_table_get(b->memoized, peg);
|
||||
Janet memo_scope = janet_table_get(b->memoized_scopes, peg);
|
||||
if (!janet_checktype(memo_rule, JANET_NIL) &&
|
||||
scope == janet_unwrap_table(memo_scope)) {
|
||||
rule = (uint32_t) janet_unwrap_number(memo_rule);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Compile with rule and current scope memoized. This will
|
||||
* let child rules refer to this rule for recursion */
|
||||
janet_table_put(b->memoized, peg, janet_wrap_number(rule));
|
||||
janet_table_put(b->memoized_scopes, peg, janet_wrap_table(scope));
|
||||
rule = peg_compile1(b, check);
|
||||
janet_table_put(b->memoized, peg, memo_rule);
|
||||
janet_table_put(b->memoized_scopes, peg, memo_scope);
|
||||
break;
|
||||
}
|
||||
case JANET_STRUCT: {
|
||||
JanetTable *grammar = janet_struct_to_table(janet_unwrap_struct(peg));
|
||||
grammar->proto = b->grammar;
|
||||
b->grammar = grammar;
|
||||
rule = peg_compile1(b, janet_ckeywordv("main"));
|
||||
b->grammar = grammar->proto;
|
||||
/* Build grammar table */
|
||||
const JanetKV *st = janet_unwrap_struct(peg);
|
||||
JanetTable *new_grammar = janet_table(2 * janet_struct_capacity(st));
|
||||
for (int32_t i = 0; i < janet_struct_capacity(st); i++) {
|
||||
if (janet_checktype(st[i].key, JANET_KEYWORD)) {
|
||||
janet_table_put(new_grammar, st[i].key, st[i].value);
|
||||
}
|
||||
}
|
||||
new_grammar->proto = grammar;
|
||||
b->grammar = grammar = new_grammar;
|
||||
/* Run the main rule */
|
||||
Janet main_rule = janet_table_rawget(grammar, janet_ckeywordv("main"));
|
||||
if (janet_checktype(main_rule, JANET_NIL))
|
||||
peg_panic(b, "grammar requires :main rule");
|
||||
rule = peg_compile1(b, main_rule);
|
||||
break;
|
||||
}
|
||||
case JANET_TUPLE: {
|
||||
@ -968,6 +989,7 @@ static uint32_t peg_compile1(Builder *b, Janet peg) {
|
||||
/* Increase depth again */
|
||||
b->depth++;
|
||||
b->form = old_form;
|
||||
b->grammar = old_grammar;
|
||||
return rule;
|
||||
}
|
||||
|
||||
@ -1194,8 +1216,6 @@ static Peg *make_peg(Builder *b) {
|
||||
static Peg *compile_peg(Janet x) {
|
||||
Builder builder;
|
||||
builder.grammar = janet_table(0);
|
||||
builder.memoized = janet_table(0);
|
||||
builder.memoized_scopes = janet_table(0);
|
||||
builder.tags = janet_table(0);
|
||||
builder.constants = NULL;
|
||||
builder.bytecode = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user