Fix infinite loops during table generation for left-recursive rules

Add function calls for arbitrary expressions and dot property access to javascript grammar
This commit is contained in:
Max Brunsfeld 2014-03-26 22:43:08 -07:00
parent 3f770ff3c3
commit 820b6f4020
7 changed files with 2824 additions and 2292 deletions

View file

@ -68,6 +68,21 @@ describe("computing FIRST sets", []() {
})));
});
});
describe("when there are left-recursive rules", [&]() {
it("terminates", [&]() {
Grammar grammar({
{ "expression", choice({
seq({ sym("expression"), sym("x") }),
sym("y"),
}) },
});
AssertThat(first_set(sym("expression"), grammar), Equals(set<Symbol>({
Symbol("y")
})));
});
});
});
END_TEST
END_TEST

View file

@ -1,5 +1,6 @@
#include "compiler_spec_helper.h"
#include "compiler/build_tables/rule_can_be_blank.h"
#include "compiler/prepared_grammar.h"
using namespace rules;
using build_tables::rule_can_be_blank;
@ -7,21 +8,63 @@ using build_tables::rule_can_be_blank;
START_TEST
describe("checking if rules can be blank", [&]() {
it("handles sequences", [&]() {
rule_ptr rule = seq({
choice({
str("x"),
blank(),
}),
str("y"),
});
rule_ptr rule;
AssertThat(rule_can_be_blank(rule), Equals(false));
it("returns false for basic rules", [&]() {
AssertThat(rule_can_be_blank(sym("x")), IsFalse());
AssertThat(rule_can_be_blank(str("x")), IsFalse());
AssertThat(rule_can_be_blank(pattern("x")), IsFalse());
});
it("returns true for blanks", [&]() {
AssertThat(rule_can_be_blank(blank()), IsTrue());
});
it("returns true for repeats", [&]() {
rule_ptr rule = repeat(str("x"));
AssertThat(rule_can_be_blank(rule), Equals(true));
AssertThat(rule_can_be_blank(repeat(str("x"))), IsTrue());
});
it("returns true for choices iff one or more sides can be blank", [&]() {
rule = choice({ sym("x"), blank() });
AssertThat(rule_can_be_blank(rule), IsTrue());
rule = choice({ blank(), sym("x") });
AssertThat(rule_can_be_blank(rule), IsTrue());
rule = choice({ sym("x"), sym("y") });
AssertThat(rule_can_be_blank(rule), IsFalse());
});
it("returns true for sequences iff both sides can be blank", [&]() {
rule = seq({ blank(), str("x") });
AssertThat(rule_can_be_blank(rule), IsFalse());
rule = seq({ str("x"), blank() });
AssertThat(rule_can_be_blank(rule), IsFalse());
rule = seq({ blank(), choice({ sym("x"), blank() }) });
AssertThat(rule_can_be_blank(rule), IsTrue());
});
describe("checking recursively (by expanding non-terminals)", [&]() {
PreparedGrammar grammar({
{ "A", choice({
seq({ sym("A"), sym("x") }),
blank() }) },
{ "B", choice({
seq({ sym("B"), sym("y") }),
sym("z") }) },
}, {});
it("terminates for left-recursive rules that can be blank", [&]() {
rule = sym("A");
AssertThat(rule_can_be_blank(rule, grammar), IsTrue());
});
it("terminates for left-recursive rules that can't be blank", [&]() {
rule = sym("B");
AssertThat(rule_can_be_blank(rule, grammar), IsFalse());
});
});
});