This branch had diverged considerably, so merging it required changing a lot of code. Conflicts: project.gyp spec/compiler/build_tables/action_takes_precedence_spec.cc spec/compiler/build_tables/build_conflict_spec.cc spec/compiler/build_tables/build_parse_table_spec.cc spec/compiler/build_tables/first_symbols_spec.cc spec/compiler/build_tables/item_set_closure_spec.cc spec/compiler/build_tables/item_set_transitions_spec.cc spec/compiler/build_tables/rule_can_be_blank_spec.cc spec/compiler/helpers/containers.h spec/compiler/prepare_grammar/expand_repeats_spec.cc spec/compiler/prepare_grammar/extract_tokens_spec.cc src/compiler/build_tables/action_takes_precedence.h src/compiler/build_tables/build_parse_table.cc src/compiler/build_tables/first_symbols.cc src/compiler/build_tables/first_symbols.h src/compiler/build_tables/item_set_closure.cc src/compiler/build_tables/item_set_transitions.cc src/compiler/build_tables/parse_item.cc src/compiler/build_tables/parse_item.h src/compiler/build_tables/rule_can_be_blank.cc src/compiler/build_tables/rule_can_be_blank.h src/compiler/prepare_grammar/expand_repeats.cc src/compiler/prepare_grammar/extract_tokens.cc src/compiler/prepare_grammar/extract_tokens.h src/compiler/prepare_grammar/prepare_grammar.cc src/compiler/rules/built_in_symbols.cc src/compiler/rules/built_in_symbols.h src/compiler/syntax_grammar.cc src/compiler/syntax_grammar.h
154 lines
4.4 KiB
C++
154 lines
4.4 KiB
C++
#include "compiler/compiler_spec_helper.h"
|
|
#include "compiler/prepare_grammar/initial_syntax_grammar.h"
|
|
#include "compiler/prepare_grammar/expand_repeats.h"
|
|
|
|
START_TEST
|
|
|
|
using namespace rules;
|
|
using prepare_grammar::InitialSyntaxGrammar;
|
|
using prepare_grammar::expand_repeats;
|
|
|
|
describe("expand_repeats", []() {
|
|
it("replaces repeat rules with pairs of recursive rules", [&]() {
|
|
InitialSyntaxGrammar grammar{{
|
|
Variable("rule0", VariableTypeNamed, repeat(i_token(0))),
|
|
}, {}, {}};
|
|
|
|
auto result = expand_repeats(grammar);
|
|
|
|
AssertThat(result.variables, Equals(vector<Variable>({
|
|
Variable("rule0", VariableTypeNamed, choice({ i_sym(1), blank() })),
|
|
Variable("rule0_repeat1", VariableTypeAuxiliary, seq({
|
|
i_token(0),
|
|
choice({ i_sym(1), blank() })
|
|
})),
|
|
})));
|
|
});
|
|
|
|
it("replaces repeats inside of sequences", [&]() {
|
|
InitialSyntaxGrammar grammar{{
|
|
Variable("rule0", VariableTypeNamed, seq({
|
|
i_token(10),
|
|
repeat(i_token(11)),
|
|
})),
|
|
}, {}, {}};
|
|
|
|
auto result = expand_repeats(grammar);
|
|
|
|
AssertThat(result.variables, Equals(vector<Variable>({
|
|
Variable("rule0", VariableTypeNamed, seq({
|
|
i_token(10),
|
|
choice({ i_sym(1), blank() })
|
|
})),
|
|
Variable("rule0_repeat1", VariableTypeAuxiliary, seq({
|
|
i_token(11),
|
|
choice({ i_sym(1), blank() })
|
|
})),
|
|
})));
|
|
});
|
|
|
|
it("replaces repeats inside of choices", [&]() {
|
|
InitialSyntaxGrammar grammar{{
|
|
Variable("rule0", VariableTypeNamed, choice({
|
|
i_token(10),
|
|
repeat(i_token(11))
|
|
})),
|
|
}, {}, {}};
|
|
|
|
auto result = expand_repeats(grammar);
|
|
|
|
AssertThat(result.variables, Equals(vector<Variable>({
|
|
Variable("rule0", VariableTypeNamed, choice({ i_token(10), i_sym(1), blank() })),
|
|
Variable("rule0_repeat1", VariableTypeAuxiliary, seq({
|
|
i_token(11),
|
|
choice({ i_sym(1), blank() }),
|
|
})),
|
|
})));
|
|
});
|
|
|
|
it("does not create redundant auxiliary rules", [&]() {
|
|
InitialSyntaxGrammar grammar{{
|
|
Variable("rule0", VariableTypeNamed, choice({
|
|
seq({ i_token(1), repeat(i_token(4)) }),
|
|
seq({ i_token(2), repeat(i_token(4)) }),
|
|
})),
|
|
Variable("rule1", VariableTypeNamed, seq({
|
|
i_token(3),
|
|
repeat(i_token(4))
|
|
})),
|
|
}, {}, {}};
|
|
|
|
auto result = expand_repeats(grammar);
|
|
|
|
AssertThat(result.variables, Equals(vector<Variable>({
|
|
Variable("rule0", VariableTypeNamed, choice({
|
|
seq({ i_token(1), choice({ i_sym(2), blank() }) }),
|
|
seq({ i_token(2), choice({ i_sym(2), blank() }) }),
|
|
})),
|
|
Variable("rule1", VariableTypeNamed, seq({
|
|
i_token(3),
|
|
choice({ i_sym(2), blank() })
|
|
})),
|
|
Variable("rule0_repeat1", VariableTypeAuxiliary, seq({
|
|
i_token(4),
|
|
choice({ i_sym(2), blank() }),
|
|
})),
|
|
})));
|
|
});
|
|
|
|
it("can replace multiple repeats in the same rule", [&]() {
|
|
InitialSyntaxGrammar grammar{{
|
|
Variable("rule0", VariableTypeNamed, seq({
|
|
repeat(i_token(10)),
|
|
repeat(i_token(11)),
|
|
})),
|
|
}, {}, {}};
|
|
|
|
auto result = expand_repeats(grammar);
|
|
|
|
AssertThat(result.variables, Equals(vector<Variable>({
|
|
Variable("rule0", VariableTypeNamed, seq({
|
|
choice({ i_sym(1), blank() }),
|
|
choice({ i_sym(2), blank() }),
|
|
})),
|
|
Variable("rule0_repeat1", VariableTypeAuxiliary, seq({
|
|
i_token(10),
|
|
choice({ i_sym(1), blank() }),
|
|
})),
|
|
Variable("rule0_repeat2", VariableTypeAuxiliary, seq({
|
|
i_token(11),
|
|
choice({ i_sym(2), blank() }),
|
|
})),
|
|
})));
|
|
});
|
|
|
|
it("can replace repeats in multiple rules", [&]() {
|
|
InitialSyntaxGrammar grammar{{
|
|
Variable("rule0", VariableTypeNamed, repeat(i_token(10))),
|
|
Variable("rule1", VariableTypeNamed, repeat(i_token(11))),
|
|
}, {}, {}};
|
|
|
|
auto result = expand_repeats(grammar);
|
|
|
|
AssertThat(result.variables, Equals(vector<Variable>({
|
|
Variable("rule0", VariableTypeNamed, choice({
|
|
i_sym(2),
|
|
blank(),
|
|
})),
|
|
Variable("rule1", VariableTypeNamed, choice({
|
|
i_sym(3),
|
|
blank(),
|
|
})),
|
|
Variable("rule0_repeat1", VariableTypeAuxiliary, seq({
|
|
i_token(10),
|
|
choice({ i_sym(2), blank() }),
|
|
})),
|
|
Variable("rule1_repeat1", VariableTypeAuxiliary, seq({
|
|
i_token(11),
|
|
choice({ i_sym(3), blank() })
|
|
})),
|
|
})));
|
|
});
|
|
});
|
|
|
|
END_TEST
|