Skip to content

Commit

Permalink
Fix #304
Browse files Browse the repository at this point in the history
  • Loading branch information
yhirose committed Sep 2, 2024
1 parent 2b02299 commit 6602b1d
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 63 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,25 @@ custom_message.txt:1:8: code format error...

NOTE: If there are more than one elements with error message instruction in a prioritized choice, this feature may not work as you expect.

Change the Start Definition Rule
--------------------------------

We can change the start definition rule as below.

```cpp
peg::parser parser(
R"(
Start <- A
A <- B (',' B)*
B <- '[one]' / '[two]'
%whitespace <- [ \t\n]*
)",
"A" // Start Rule is "A"
)";

parser.parse(" [one] , [two] "); // OK
```

peglint - PEG syntax lint utility
---------------------------------

Expand Down
1 change: 1 addition & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<li><span>Source Code</span></li>
<li class="editor-options">
<ul class="editor-header-options">
<li class="option"><label>Start Rule: </label><input id="start-rule" type="text"></li>
<li class="option"><input id="packrat" type="checkbox"><label>Packrat</label></li>
<li class="option"><input id="auto-refresh" type="checkbox"><label>Auto Refresh</label></li>
<li class="option"><button id="parse" class="parse">Parse</button></li>
Expand Down
6 changes: 5 additions & 1 deletion docs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const codeAstOptimized = setupInfoArea("code-ast-optimized");
const codeProfile = setupInfoArea("code-profile");

$('#opt-mode').val(localStorage.getItem('optimizationMode') || 'all');
$('#start-rule').val(localStorage.getItem('startRule') || '');
$('#packrat').prop('checked', localStorage.getItem('packrat') === 'true');
$('#auto-refresh').prop('checked', localStorage.getItem('autoRefresh') === 'true');
$('#parse').prop('disabled', $('#auto-refresh').prop('checked'));
Expand Down Expand Up @@ -61,6 +62,7 @@ function updateLocalStorage() {
localStorage.setItem('grammarText', grammar.getValue());
localStorage.setItem('codeText', code.getValue());
localStorage.setItem('optimizationMode', $('#opt-mode').val());
localStorage.setItem('startRule', $('#start-rule').val());
localStorage.setItem('packrat', $('#packrat').prop('checked'));
localStorage.setItem('autoRefresh', $('#auto-refresh').prop('checked'));
}
Expand All @@ -75,6 +77,7 @@ function parse() {
const codeText = code.getValue();

const optimizationMode = $('#opt-mode').val();
const startRule = $('#start-rule').val();
const packrat = $('#packrat').prop('checked');

$grammarInfo.html('');
Expand All @@ -97,7 +100,7 @@ function parse() {
'background-color': 'rgba(0, 0, 0, 0.1)'
});
window.setTimeout(() => {
const data = JSON.parse(Module.lint(grammarText, codeText, mode, packrat));
const data = JSON.parse(Module.lint(grammarText, codeText, mode, packrat, startRule));
$('#overlay').css({
'z-index': '-1',
'display': 'none',
Expand Down Expand Up @@ -165,6 +168,7 @@ $('#code-info').on('click', 'li', makeOnClickInInfo(code));

// Event handing in the AST optimization
$('#opt-mode').on('change', setupTimer);
$('#start-rule').on('keydown', setupTimer);
$('#packrat').on('change', setupTimer);
$('#auto-refresh').on('change', () => {
updateLocalStorage();
Expand Down
12 changes: 7 additions & 5 deletions docs/native.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ std::string escape_json(const std::string &s) {
std::function<void(size_t, size_t, const std::string &, const std::string &)>
makeJSONFormatter(peg::parser &peg, std::string &json, bool &init) {
init = true;
return [&](size_t ln, size_t col, const std::string &msg, const std::string &rule) 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) + ",";
Expand All @@ -43,11 +44,11 @@ makeJSONFormatter(peg::parser &peg, std::string &json, bool &init) {
}

bool parse_grammar(const std::string &text, peg::parser &peg,
std::string &json) {
const std::string &startRule, std::string &json) {
bool init;
peg.set_logger(makeJSONFormatter(peg, json, init));
json += "[";
auto ret = peg.load_grammar(text.data(), text.size());
auto ret = peg.load_grammar(text.data(), text.size(), startRule);
json += "]";
return ret;
}
Expand All @@ -64,15 +65,16 @@ bool parse_code(const std::string &text, peg::parser &peg, std::string &json,
}

std::string lint(const std::string &grammarText, const std::string &codeText,
bool opt_mode, bool packrat) {
bool opt_mode, bool packrat, const std::string &startRule) {
std::string grammarResult;
std::string codeResult;
std::string astResult;
std::string astResultOptimized;
std::string profileResult;

peg::parser peg;
auto is_grammar_valid = parse_grammar(grammarText, peg, grammarResult);
auto is_grammar_valid =
parse_grammar(grammarText, peg, startRule, grammarResult);
auto is_source_valid = false;

if (is_grammar_valid && peg) {
Expand Down
Binary file modified docs/native.wasm
Binary file not shown.
117 changes: 67 additions & 50 deletions peglib.h
Original file line number Diff line number Diff line change
Expand Up @@ -3298,18 +3298,15 @@ using Rules = std::unordered_map<std::string, std::shared_ptr<Ope>>;

class ParserGenerator {
public:
static std::shared_ptr<Grammar> parse(const char *s, size_t n,
const Rules &rules, std::string &start,
bool &enablePackratParsing, Log log) {
return get_instance().perform_core(s, n, rules, start, enablePackratParsing,
log);
}
struct ParserContext {
std::shared_ptr<Grammar> grammar;
std::string start;
bool enablePackratParsing = false;
};

static std::shared_ptr<Grammar> parse(const char *s, size_t n,
std::string &start,
bool &enablePackratParsing, Log log) {
Rules dummy;
return parse(s, n, dummy, start, enablePackratParsing, log);
static ParserContext parse(const char *s, size_t n, const Rules &rules,
Log log, std::string_view start) {
return get_instance().perform_core(s, n, rules, log, std::string(start));
}

// For debugging purpose
Expand Down Expand Up @@ -3989,9 +3986,8 @@ class ParserGenerator {
return true;
}

std::shared_ptr<Grammar> perform_core(const char *s, size_t n,
const Rules &rules, std::string &start,
bool &enablePackratParsing, Log log) {
ParserContext perform_core(const char *s, size_t n, const Rules &rules,
Log log, std::string requested_start) {
Data data;
auto &grammar = *data.grammar;

Expand Down Expand Up @@ -4023,7 +4019,7 @@ class ParserGenerator {
log(line.first, line.second, "syntax error", r.error_info.label);
}
}
return nullptr;
return {};
}

// User provided rules
Expand Down Expand Up @@ -4081,7 +4077,25 @@ class ParserGenerator {
}

// Set root definition
auto &start_rule = grammar[data.start];
auto start = data.start;

if (!requested_start.empty()) {
if (grammar.count(requested_start)) {
start = requested_start;
} else {
if (log) {
auto line = line_info(s, s);
log(line.first, line.second,
"The specified start rule '" + requested_start + "' is undefined.",
"");
}
ret = false;
}
}

if (!ret) { return {}; }

auto &start_rule = grammar[start];

// Check if the start rule has ignore operator
{
Expand All @@ -4096,7 +4110,7 @@ class ParserGenerator {
}
}

if (!ret) { return nullptr; }
if (!ret) { return {}; }

// Check missing definitions
auto referenced = std::unordered_set<std::string>{
Expand Down Expand Up @@ -4129,7 +4143,7 @@ class ParserGenerator {
}
}

if (!ret) { return nullptr; }
if (!ret) { return {}; }

// Link references
for (auto &x : grammar) {
Expand All @@ -4153,10 +4167,10 @@ class ParserGenerator {
}
}

if (!ret) { return nullptr; }
if (!ret) { return {}; }

// Check infinite loop
if (detect_infiniteLoop(data, start_rule, log, s)) { return nullptr; }
if (detect_infiniteLoop(data, start_rule, log, s)) { return {}; }

// Automatic whitespace skipping
if (grammar.count(WHITESPACE_DEFINITION_NAME)) {
Expand All @@ -4169,15 +4183,15 @@ class ParserGenerator {
auto &rule = grammar[WHITESPACE_DEFINITION_NAME];
start_rule.whitespaceOpe = wsp(rule.get_core_operator());

if (detect_infiniteLoop(data, rule, log, s)) { return nullptr; }
if (detect_infiniteLoop(data, rule, log, s)) { return {}; }
}

// Word expression
if (grammar.count(WORD_DEFINITION_NAME)) {
auto &rule = grammar[WORD_DEFINITION_NAME];
start_rule.wordOpe = rule.get_core_operator();

if (detect_infiniteLoop(data, rule, log, s)) { return nullptr; }
if (detect_infiniteLoop(data, rule, log, s)) { return {}; }
}

// Apply instructions
Expand All @@ -4189,9 +4203,7 @@ class ParserGenerator {
const auto &info =
std::any_cast<PrecedenceClimbing::BinOpeInfo>(instruction.data);

if (!apply_precedence_instruction(rule, info, s, log)) {
return nullptr;
}
if (!apply_precedence_instruction(rule, info, s, log)) { return {}; }
} else if (instruction.type == "error_message") {
rule.error_message = std::any_cast<std::string>(instruction.data);
} else if (instruction.type == "no_ast_opt") {
Expand All @@ -4200,11 +4212,7 @@ class ParserGenerator {
}
}

// Set root definition
start = data.start;
enablePackratParsing = data.enablePackratParsing;

return data.grammar;
return {data.grammar, start, data.enablePackratParsing};
}

bool detect_infiniteLoop(const Data &data, Definition &rule, const Log &log,
Expand Down Expand Up @@ -4530,43 +4538,52 @@ class parser {
public:
parser() = default;

parser(const char *s, size_t n, const Rules &rules) {
load_grammar(s, n, rules);
parser(const char *s, size_t n, const Rules &rules,
std::string_view start = {}) {
load_grammar(s, n, rules, start);
}

parser(const char *s, size_t n) : parser(s, n, Rules()) {}
parser(const char *s, size_t n, std::string_view start = {})
: parser(s, n, Rules(), start) {}

parser(std::string_view sv, const Rules &rules)
: parser(sv.data(), sv.size(), rules) {}
parser(std::string_view sv, const Rules &rules, std::string_view start = {})
: parser(sv.data(), sv.size(), rules, start) {}

parser(std::string_view sv) : parser(sv.data(), sv.size(), Rules()) {}
parser(std::string_view sv, std::string_view start = {})
: parser(sv.data(), sv.size(), Rules(), start) {}

#if defined(__cpp_lib_char8_t)
parser(std::u8string_view sv, const Rules &rules)
: parser(reinterpret_cast<const char *>(sv.data()), sv.size(), rules) {}
parser(std::u8string_view sv, const Rules &rules, std::string_view start = {})
: parser(reinterpret_cast<const char *>(sv.data()), sv.size(), rules,
start) {}

parser(std::u8string_view sv)
: parser(reinterpret_cast<const char *>(sv.data()), sv.size(), Rules()) {}
parser(std::u8string_view sv, std::string_view start = {})
: parser(reinterpret_cast<const char *>(sv.data()), sv.size(), Rules(),
start) {}
#endif

operator bool() { return grammar_ != nullptr; }

bool load_grammar(const char *s, size_t n, const Rules &rules) {
grammar_ = ParserGenerator::parse(s, n, rules, start_,
enablePackratParsing_, log_);
bool load_grammar(const char *s, size_t n, const Rules &rules,
std::string_view start = {}) {
auto cxt = ParserGenerator::parse(s, n, rules, log_, start);
grammar_ = cxt.grammar;
start_ = cxt.start;
enablePackratParsing_ = cxt.enablePackratParsing;
return grammar_ != nullptr;
}

bool load_grammar(const char *s, size_t n) {
return load_grammar(s, n, Rules());
bool load_grammar(const char *s, size_t n, std::string_view start = {}) {
return load_grammar(s, n, Rules(), start);
}

bool load_grammar(std::string_view sv, const Rules &rules) {
return load_grammar(sv.data(), sv.size(), rules);
bool load_grammar(std::string_view sv, const Rules &rules,
std::string_view start = {}) {
return load_grammar(sv.data(), sv.size(), rules, start);
}

bool load_grammar(std::string_view sv) {
return load_grammar(sv.data(), sv.size());
bool load_grammar(std::string_view sv, std::string_view start = {}) {
return load_grammar(sv.data(), sv.size(), start);
}

bool parse_n(const char *s, size_t n, const char *path = nullptr) const {
Expand Down Expand Up @@ -4671,7 +4688,7 @@ class parser {
void enable_packrat_parsing() {
if (grammar_ != nullptr) {
auto &rule = (*grammar_)[start_];
rule.enablePackratParsing = enablePackratParsing_ && true;
rule.enablePackratParsing = enablePackratParsing_;
}
}

Expand Down
Loading

0 comments on commit 6602b1d

Please sign in to comment.