mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Fix #231
This commit is contained in:
parent
eab2ea05cd
commit
c4772a1b00
File diff suppressed because one or more lines are too long
BIN
docs/native.wasm
BIN
docs/native.wasm
Binary file not shown.
85
peglib.h
85
peglib.h
@ -819,6 +819,10 @@ public:
|
||||
std::vector<std::map<std::string_view, std::string>> capture_scope_stack;
|
||||
size_t capture_scope_stack_size = 0;
|
||||
|
||||
std::vector<std::map<std::string, std::unordered_set<std::string>>>
|
||||
symbol_tables_stack;
|
||||
size_t symbol_tables_stack_size = 0;
|
||||
|
||||
std::vector<bool> cut_stack;
|
||||
|
||||
const size_t def_count;
|
||||
@ -834,8 +838,6 @@ public:
|
||||
std::any trace_data;
|
||||
const bool verbose_trace;
|
||||
|
||||
std::map<std::string, std::unordered_set<std::string>> symbol_tables;
|
||||
|
||||
Log log;
|
||||
|
||||
Context(const char *path, const char *s, size_t l, size_t def_count,
|
||||
@ -851,11 +853,19 @@ public:
|
||||
trace_data(trace_data), verbose_trace(verbose_trace), log(log) {
|
||||
|
||||
args_stack.resize(1);
|
||||
|
||||
push_capture_scope();
|
||||
push_symbol_tables();
|
||||
}
|
||||
|
||||
~Context() { assert(!value_stack_size); }
|
||||
~Context() {
|
||||
pop_capture_scope();
|
||||
pop_symbol_tables();
|
||||
|
||||
assert(!value_stack_size);
|
||||
assert(!capture_scope_stack_size);
|
||||
assert(!symbol_tables_stack_size);
|
||||
assert(cut_stack.empty());
|
||||
}
|
||||
|
||||
Context(const Context &) = delete;
|
||||
Context(Context &&) = delete;
|
||||
@ -942,7 +952,7 @@ public:
|
||||
void pop_capture_scope() { capture_scope_stack_size--; }
|
||||
|
||||
void shift_capture_values() {
|
||||
assert(capture_scope_stack.size() >= 2);
|
||||
assert(capture_scope_stack_size >= 2);
|
||||
auto curr = &capture_scope_stack[capture_scope_stack_size - 1];
|
||||
auto prev = curr - 1;
|
||||
for (const auto &[k, v] : *curr) {
|
||||
@ -950,6 +960,50 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void push_symbol_tables() {
|
||||
assert(symbol_tables_stack_size <= symbol_tables_stack.size());
|
||||
if (symbol_tables_stack_size == symbol_tables_stack.size()) {
|
||||
symbol_tables_stack.emplace_back(
|
||||
std::map<std::string, std::unordered_set<std::string>>());
|
||||
} else {
|
||||
auto &tables = symbol_tables_stack[symbol_tables_stack_size];
|
||||
if (!tables.empty()) { tables.clear(); }
|
||||
}
|
||||
symbol_tables_stack_size++;
|
||||
}
|
||||
|
||||
void pop_symbol_tables() { symbol_tables_stack_size--; }
|
||||
|
||||
void shift_symbol_tables() {
|
||||
assert(symbol_tables_stack_size >= 2);
|
||||
auto curr = &symbol_tables_stack[symbol_tables_stack_size - 1];
|
||||
auto prev = curr - 1;
|
||||
for (const auto &[k, v] : *curr) {
|
||||
(*prev)[k].insert(v.begin(), v.end());
|
||||
}
|
||||
}
|
||||
|
||||
void declare_symbol(const std::string &table_name,
|
||||
const std::string &symbol) {
|
||||
assert(symbol_tables_stack_size >= 1);
|
||||
auto &table = symbol_tables_stack[symbol_tables_stack_size - 1][table_name];
|
||||
table.insert(symbol);
|
||||
}
|
||||
|
||||
bool check_symbol(const std::string &table_name, const std::string &symbol) {
|
||||
int i = symbol_tables_stack_size - 1;
|
||||
while (i >= 0) {
|
||||
const auto &tables = symbol_tables_stack[i];
|
||||
if (auto it = tables.find(table_name); it != tables.end()) {
|
||||
if (const auto &table = it->second; table.find(symbol) != table.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i--;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void set_error_pos(const char *a_s, const char *literal = nullptr);
|
||||
|
||||
void trace_enter(const Ope &ope, const char *a_s, size_t n,
|
||||
@ -1036,10 +1090,12 @@ public:
|
||||
|
||||
auto &chvs = c.push_semantic_values_scope();
|
||||
c.push_capture_scope();
|
||||
c.push_symbol_tables();
|
||||
c.error_info.keep_previous_token = id > 0;
|
||||
auto se = scope_exit([&]() {
|
||||
c.pop_semantic_values_scope();
|
||||
c.pop_capture_scope();
|
||||
c.pop_symbol_tables();
|
||||
c.error_info.keep_previous_token = false;
|
||||
});
|
||||
|
||||
@ -1059,6 +1115,7 @@ public:
|
||||
vs.tokens.emplace_back(std::move(tok));
|
||||
}
|
||||
c.shift_capture_values();
|
||||
c.shift_symbol_tables();
|
||||
break;
|
||||
} else if (!c.cut_stack.empty() && c.cut_stack.back()) {
|
||||
break;
|
||||
@ -1092,9 +1149,11 @@ public:
|
||||
while (count < min_) {
|
||||
auto &chvs = c.push_semantic_values_scope();
|
||||
c.push_capture_scope();
|
||||
c.push_symbol_tables();
|
||||
auto se = scope_exit([&]() {
|
||||
c.pop_semantic_values_scope();
|
||||
c.pop_capture_scope();
|
||||
c.pop_symbol_tables();
|
||||
});
|
||||
|
||||
auto len = ope_->parse(s + i, n - i, chvs, c, dt);
|
||||
@ -1111,6 +1170,7 @@ public:
|
||||
vs.tokens.emplace_back(std::move(tok));
|
||||
}
|
||||
c.shift_capture_values();
|
||||
c.shift_symbol_tables();
|
||||
} else {
|
||||
return len;
|
||||
}
|
||||
@ -1121,9 +1181,11 @@ public:
|
||||
while (count < max_) {
|
||||
auto &chvs = c.push_semantic_values_scope();
|
||||
c.push_capture_scope();
|
||||
c.push_symbol_tables();
|
||||
auto se = scope_exit([&]() {
|
||||
c.pop_semantic_values_scope();
|
||||
c.pop_capture_scope();
|
||||
c.pop_symbol_tables();
|
||||
});
|
||||
|
||||
auto len = ope_->parse(s + i, n - i, chvs, c, dt);
|
||||
@ -1140,6 +1202,7 @@ public:
|
||||
vs.tokens.emplace_back(std::move(tok));
|
||||
}
|
||||
c.shift_capture_values();
|
||||
c.shift_symbol_tables();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -1182,9 +1245,11 @@ public:
|
||||
Context &c, std::any &dt) const override {
|
||||
auto &chvs = c.push_semantic_values_scope();
|
||||
c.push_capture_scope();
|
||||
c.push_symbol_tables();
|
||||
auto se = scope_exit([&]() {
|
||||
c.pop_semantic_values_scope();
|
||||
c.pop_capture_scope();
|
||||
c.pop_symbol_tables();
|
||||
});
|
||||
|
||||
auto len = ope_->parse(s, n, chvs, c, dt);
|
||||
@ -1209,9 +1274,11 @@ public:
|
||||
Context &c, std::any &dt) const override {
|
||||
auto &chvs = c.push_semantic_values_scope();
|
||||
c.push_capture_scope();
|
||||
c.push_symbol_tables();
|
||||
auto se = scope_exit([&]() {
|
||||
c.pop_semantic_values_scope();
|
||||
c.pop_capture_scope();
|
||||
c.pop_symbol_tables();
|
||||
});
|
||||
auto len = ope_->parse(s, n, chvs, c, dt);
|
||||
if (success(len)) {
|
||||
@ -2732,18 +2799,16 @@ inline size_t Holder::parse_core(const char *s, size_t n, SemanticValues &vs,
|
||||
} else if (outer_->declare_symbol) {
|
||||
assert(outer_->is_token());
|
||||
auto symbol = chvs.token_to_string();
|
||||
auto &table = c.symbol_tables[outer_->symbol_table_name];
|
||||
if (table.find(symbol) != table.end()) {
|
||||
if (c.check_symbol(outer_->symbol_table_name, symbol)) {
|
||||
msg = "'" + symbol + "' already exists.";
|
||||
len = static_cast<size_t>(-1);
|
||||
} else {
|
||||
table.insert(symbol);
|
||||
c.declare_symbol(outer_->symbol_table_name, symbol);
|
||||
}
|
||||
} else if (outer_->check_symbol) {
|
||||
assert(outer_->is_token());
|
||||
auto symbol = chvs.token_to_string();
|
||||
auto &table = c.symbol_tables[outer_->symbol_table_name];
|
||||
if (table.find(symbol) == table.end()) {
|
||||
if (!c.check_symbol(outer_->symbol_table_name, symbol)) {
|
||||
msg = "'" + symbol + "' doesn't exist.";
|
||||
len = static_cast<size_t>(-1);
|
||||
}
|
||||
|
@ -862,8 +862,7 @@ TEST(PredicateTest, Semantic_predicate_test) {
|
||||
}
|
||||
|
||||
TEST(SymbolTableTest, symbol_instruction_test) {
|
||||
parser parser(R"(
|
||||
S <- (Decl / Ref)*
|
||||
parser parser(R"(S <- (Decl / Ref)*
|
||||
Decl <- 'decl' symbol
|
||||
Ref <- 'ref' is_symbol
|
||||
Name <- < [a-zA-Z]+ >
|
||||
@ -900,6 +899,44 @@ decl aaa
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SymbolTableTest, symbol_instruction_backtrack_test) {
|
||||
parser parser(R"(S <- (DeclBT / Decl / Ref)*
|
||||
DeclBT <- 'decl' symbol 'backtrack' # match fails, so symbol should not be set
|
||||
Decl <- 'decl' symbol
|
||||
Ref <- 'ref' is_symbol
|
||||
Name <- < [a-zA-Z]+ >
|
||||
%whitespace <- [ \t\r\n]*
|
||||
|
||||
# 'var_table' is a table name.
|
||||
symbol <- Name { declare_symbol var_table } # Declare symbol instruction
|
||||
is_symbol <- Name { check_symbol var_table } # Check symbol instruction
|
||||
)");
|
||||
|
||||
const auto source = R"(decl foo
|
||||
ref foo
|
||||
)";
|
||||
EXPECT_TRUE(parser.parse(source));
|
||||
}
|
||||
|
||||
TEST(SymbolTableTest, symbol_instruction_backtrack_test2) {
|
||||
parser parser(R"(S <- DeclBT* Decl Ref
|
||||
DeclBT <- 'decl' symbol 'backtrack' # match fails, so symbol should not be set
|
||||
Decl <- 'decl' symbol
|
||||
Ref <- 'ref' is_symbol
|
||||
Name <- < [a-zA-Z]+ >
|
||||
%whitespace <- [ \t\r\n]*
|
||||
|
||||
# 'var_table' is a table name.
|
||||
symbol <- Name { declare_symbol var_table } # Declare symbol instruction
|
||||
is_symbol <- Name { check_symbol var_table } # Check symbol instruction
|
||||
)");
|
||||
|
||||
const auto source = R"(decl foo
|
||||
ref foo
|
||||
)";
|
||||
EXPECT_TRUE(parser.parse(source));
|
||||
}
|
||||
|
||||
TEST(SymbolTableTest, typedef_test) {
|
||||
parser parser(R"(
|
||||
S <- (Decl / TypeDef)*
|
||||
|
Loading…
Reference in New Issue
Block a user