diff --git a/docs/index.js b/docs/index.js
index bacadac..f8cad8d 100644
--- a/docs/index.js
+++ b/docs/index.js
@@ -45,7 +45,11 @@ function generateErrorListHTML(errors) {
let html = '
';
html += $.map(errors, function (x) {
- return '- ' + x.ln + ':' + x.col + ' ' + escapeHtml(x.msg) + '
';
+ if (x.gln && x.gcol) {
+ return `- ${x.ln}:${x.col} ${escapeHtml(x.msg)}
`;
+ } else {
+ return `- ${x.ln}:${x.col} ${escapeHtml(x.msg)}
`;
+ }
}).join('');
html += '';
@@ -149,6 +153,11 @@ function makeOnClickInInfo(editor) {
editor.navigateTo(el.data('ln') - 1, el.data('col') - 1);
editor.scrollToLine(el.data('ln') - 1, true, false, null);
editor.focus();
+
+ if(el.data('gln') && el.data('gcol')) {
+ grammar.navigateTo(el.data('gln') - 1, el.data('gcol') - 1);
+ grammar.scrollToLine(el.data('gln') - 1, true, false, null);
+ }
}
};
$('#grammar-info').on('click', 'li', makeOnClickInInfo(grammar));
diff --git a/docs/native.cpp b/docs/native.cpp
index 4777274..815682e 100644
--- a/docs/native.cpp
+++ b/docs/native.cpp
@@ -18,15 +18,24 @@ std::string escape_json(const std::string &s) {
return o.str();
}
-std::function
-makeJSONFormatter(std::string &json, bool &init) {
+std::function
+makeJSONFormatter(peg::parser &peg, std::string &json, bool &init) {
init = true;
- return [&](size_t ln, size_t col, const std::string &msg) mutable {
+ return [&](size_t ln, size_t col, const std::string &msg, const std::string &rule) mutable {
if (!init) { json += ","; }
json += "{";
json += R"("ln":)" + std::to_string(ln) + ",";
json += R"("col":)" + std::to_string(col) + ",";
json += R"("msg":")" + escape_json(msg) + R"(")";
+ if (!rule.empty()) {
+ auto it = peg.get_grammar().find(rule);
+ if (it != peg.get_grammar().end()) {
+ auto [gln, gcol] = it->second.line_;
+ json += ",";
+ json += R"("gln":)" + std::to_string(gln) + ",";
+ json += R"("gcol":)" + std::to_string(gcol);
+ }
+ }
json += "}";
init = false;
@@ -36,7 +45,7 @@ makeJSONFormatter(std::string &json, bool &init) {
bool parse_grammar(const std::string &text, peg::parser &peg,
std::string &json) {
bool init;
- peg.set_logger(makeJSONFormatter(json, init));
+ peg.set_logger(makeJSONFormatter(peg, json, init));
json += "[";
auto ret = peg.load_grammar(text.data(), text.size());
json += "]";
@@ -47,7 +56,7 @@ bool parse_code(const std::string &text, peg::parser &peg, std::string &json,
std::shared_ptr &ast) {
peg.enable_ast();
bool init;
- peg.set_logger(makeJSONFormatter(json, init));
+ peg.set_logger(makeJSONFormatter(peg, json, init));
json += "[";
auto ret = peg.parse_n(text.data(), text.size(), ast);
json += "]";
diff --git a/docs/native.wasm b/docs/native.wasm
index c11f203..80970ce 100755
Binary files a/docs/native.wasm and b/docs/native.wasm differ
diff --git a/peglib.h b/peglib.h
index fe4f092..ad7b2d7 100644
--- a/peglib.h
+++ b/peglib.h
@@ -2328,6 +2328,7 @@ public:
std::string name;
const char *s_ = nullptr;
+ std::pair line_ = {1, 1};
std::function
@@ -2557,6 +2558,9 @@ inline void ErrorInfo::output_log(const Log &log, const char *s, size_t n) {
msg += "'";
} else {
msg += "<" + error_rule->name + ">";
+ if (label.empty()) {
+ label = error_rule->name;
+ }
}
first_item = false;
}
@@ -2937,12 +2941,10 @@ inline size_t Recovery::parse_core(const char *s, size_t n,
// Custom error message
if (c.log) {
auto label = dynamic_cast(rule.args_[0].get());
- if (label) {
- if (!label->rule_->error_message.empty()) {
- c.error_info.message_pos = s;
- c.error_info.message = label->rule_->error_message;
- c.error_info.label = label->rule_->name;
- }
+ if (label && !label->rule_->error_message.empty()) {
+ c.error_info.message_pos = s;
+ c.error_info.message = label->rule_->error_message;
+ c.error_info.label = label->rule_->name;
}
}
@@ -3481,13 +3483,14 @@ private:
rule <= ope;
rule.name = name;
rule.s_ = vs.sv().data();
+ rule.line_ = line_info(vs.ss, rule.s_);
rule.ignoreSemanticValue = ignore;
rule.is_macro = is_macro;
rule.params = params;
if (data.start.empty()) {
- data.start = name;
- data.start_pos = vs.sv().data();
+ data.start = rule.name;
+ data.start_pos = rule.s_;
}
} else {
data.duplicates_of_definition.emplace_back(name, vs.sv().data());
@@ -4549,13 +4552,7 @@ public:
const Definition &operator[](const char *s) const { return (*grammar_)[s]; }
- std::vector get_rule_names() const {
- std::vector rules;
- for (auto &[name, _] : *grammar_) {
- rules.push_back(name);
- }
- return rules;
- }
+ const Grammar &get_grammar() const { return *grammar_; }
void disable_eoi_check() {
if (grammar_ != nullptr) {
diff --git a/test/test1.cc b/test/test1.cc
index 3139dda..1f6e801 100644
--- a/test/test1.cc
+++ b/test/test1.cc
@@ -901,7 +901,8 @@ TEST(GeneralTest, Semantic_values_test) {
x <- 'x'
)");
- for (const auto &rule : parser.get_rule_names()) {
+ for (const auto &item : parser.get_grammar()) {
+ const auto &rule = item.first;
parser[rule.data()] = [rule](const SemanticValues &vs, std::any &) {
if (rule == "term") {
EXPECT_EQ("a at 0", std::any_cast(vs[0]));