Throw operator support

This commit is contained in:
yhirose 2021-01-15 20:18:19 -05:00
parent d4aa6e7df5
commit 0dab91d8d9
4 changed files with 154 additions and 4 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -2918,7 +2918,8 @@ private:
opt(g["Instruction"]))); opt(g["Instruction"])));
g["Expression"] <= seq(g["Sequence"], zom(seq(g["SLASH"], g["Sequence"]))); g["Expression"] <= seq(g["Sequence"], zom(seq(g["SLASH"], g["Sequence"])));
g["Sequence"] <= zom(g["Prefix"]); g["Sequence"] <= zom(g["Prefix"]);
g["Prefix"] <= seq(opt(cho(g["AND"], g["NOT"])), g["Suffix"]); g["Prefix"] <= seq(opt(cho(g["AND"], g["NOT"])), g["SuffixWithLabel"]);
g["SuffixWithLabel"] <= seq(g["Suffix"], opt(seq(g["HAT"], g["Identifier"])));
g["Suffix"] <= seq(g["Primary"], opt(g["Loop"])); g["Suffix"] <= seq(g["Primary"], opt(g["Loop"]));
g["Loop"] <= cho(g["QUESTION"], g["STAR"], g["PLUS"], g["Repetition"]); g["Loop"] <= cho(g["QUESTION"], g["STAR"], g["PLUS"], g["Repetition"]);
g["Primary"] <= g["Primary"] <=
@ -2991,6 +2992,7 @@ private:
~g["PIPE"] <= seq(chr('|'), g["Spacing"]); ~g["PIPE"] <= seq(chr('|'), g["Spacing"]);
g["AND"] <= seq(chr('&'), g["Spacing"]); g["AND"] <= seq(chr('&'), g["Spacing"]);
g["NOT"] <= seq(chr('!'), g["Spacing"]); g["NOT"] <= seq(chr('!'), g["Spacing"]);
~g["HAT"] <= seq(chr('^'), g["Spacing"]);
g["QUESTION"] <= seq(chr('?'), g["Spacing"]); g["QUESTION"] <= seq(chr('?'), g["Spacing"]);
g["STAR"] <= seq(chr('*'), g["Spacing"]); g["STAR"] <= seq(chr('*'), g["Spacing"]);
g["PLUS"] <= seq(chr('+'), g["Spacing"]); g["PLUS"] <= seq(chr('+'), g["Spacing"]);
@ -3064,7 +3066,7 @@ private:
void setup_actions() { void setup_actions() {
g["Definition"] = [&](const SemanticValues &vs, std::any &dt) { g["Definition"] = [&](const SemanticValues &vs, std::any &dt) {
Data &data = *std::any_cast<Data *>(dt); auto &data = *std::any_cast<Data *>(dt);
auto is_macro = vs.choice() == 0; auto is_macro = vs.choice() == 0;
auto ignore = std::any_cast<bool>(vs[0]); auto ignore = std::any_cast<bool>(vs[0]);
@ -3150,6 +3152,20 @@ private:
return ope; return ope;
}; };
g["SuffixWithLabel"] = [&](const SemanticValues &vs, std::any &dt) {
auto ope = std::any_cast<std::shared_ptr<Ope>>(vs[0]);
if (vs.size() == 1) {
return ope;
} else {
assert(vs.size() == 2);
auto &data = *std::any_cast<Data *>(dt);
const auto &ident = std::any_cast<std::string>(vs[1]);
auto label = ref(*data.grammar, ident, vs.sv().data(), false, {});
auto recovery = rec(ref(*data.grammar, RECOVER_DEFINITION_NAME, vs.sv().data(), true, {label}));
return cho(ope, recovery);
}
};
struct Loop { struct Loop {
enum class Type { opt = 0, zom, oom, rep }; enum class Type { opt = 0, zom, oom, rep };
Type type; Type type;
@ -3211,7 +3227,7 @@ private:
}; };
g["Primary"] = [&](const SemanticValues &vs, std::any &dt) { g["Primary"] = [&](const SemanticValues &vs, std::any &dt) {
Data &data = *std::any_cast<Data *>(dt); auto &data = *std::any_cast<Data *>(dt);
switch (vs.choice()) { switch (vs.choice()) {
case 0: // Macro Reference case 0: // Macro Reference

View File

@ -1251,3 +1251,137 @@ R"(+ START
+ ITEM/2 + ITEM/2
)"); )");
} }
TEST_CASE("Error recovery Java", "[error]") {
parser pg(R"(
Prog PUBLIC CLASS NAME LCUR PUBLIC STATIC VOID MAIN LPAR STRING LBRA RBRA NAME RPAR BlockStmt RCUR
BlockStmt LCUR (Stmt)* RCUR^rcblk
Stmt IfStmt / WhileStmt / PrintStmt / DecStmt / AssignStmt / BlockStmt
IfStmt IF LPAR Exp RPAR Stmt (ELSE Stmt)?
WhileStmt WHILE LPAR Exp RPAR Stmt
DecStmt INT NAME (ASSIGN Exp)? SEMI
AssignStmt NAME ASSIGN Exp SEMI^semia
PrintStmt PRINTLN LPAR Exp RPAR SEMI
Exp RelExp (EQ RelExp)*
RelExp AddExp (LT AddExp)*
AddExp MulExp ((PLUS / MINUS) MulExp)*
MulExp AtomExp ((TIMES / DIV) AtomExp)*
AtomExp LPAR Exp RPAR / NUMBER / NAME
NUMBER < [0-9]+ >
NAME < [a-zA-Z_][a-zA-Z_0-9]* >
~LPAR '('
~RPAR ')'
~LCUR '{'
~RCUR '}'
~LBRA '['
~RBRA ']'
~SEMI ';'
~EQ '=='
~LT '<'
~ASSIGN '='
~IF 'if'
~ELSE 'else'
~WHILE 'while'
PLUS '+'
MINUS '-'
TIMES '*'
DIV '/'
CLASS 'class'
PUBLIC 'public'
STATIC 'static'
VOID 'void'
INT 'int'
MAIN 'main'
STRING 'String'
PRINTLN 'System.out.println'
%whitespace [ \t\n]*
%word NAME
# Throw operator labels
rcblk SkipToRCUR { message "missing end of block." }
semia '' { message "missing simicolon in assignment." }
# Recovery expressions
SkipToRCUR (!RCUR (LCUR SkipToRCUR / .))* RCUR
)");
REQUIRE(!!pg); // OK
std::vector<std::string> errors{
R"(8:5: missing simicolon in assignment.)",
R"(8:6: missing end of block.)",
};
size_t i = 0;
pg.log = [&](size_t ln, size_t col, const std::string &msg) {
std::stringstream ss;
ss << ln << ":" << col << ": " << msg;
REQUIRE(ss.str() == errors[i++]);
};
pg.enable_ast();
std::shared_ptr<Ast> ast;
REQUIRE_FALSE(pg.parse(R"(public class Example {
public static void main(String[] args) {
int n = 5;
int f = 1;
while(0 < n) {
f = f * n;
n = n - 1
};
System.out.println(f);
}
}
)", ast));
ast = peg::AstOptimizer(true, {"ENTRIES"}).optimize(ast);
REQUIRE(ast_to_s(ast) ==
R"(+ Prog
- PUBLIC (public)
- CLASS (class)
- NAME (Example)
- PUBLIC (public)
- STATIC (static)
- VOID (void)
- MAIN (main)
- STRING (String)
- NAME (args)
+ BlockStmt
+ Stmt/3[DecStmt]
- INT (int)
- NAME (n)
- Exp/0[NUMBER] (5)
+ Stmt/3[DecStmt]
- INT (int)
- NAME (f)
- Exp/0[NUMBER] (1)
+ Stmt/1[WhileStmt]
+ Exp/0[RelExp]
- AddExp/0[NUMBER] (0)
- AddExp/0[NAME] (n)
+ Stmt/5[BlockStmt]
+ Stmt/4[AssignStmt]
- NAME (f)
+ Exp/0[MulExp]
- AtomExp/2[NAME] (f)
- TIMES (*)
- AtomExp/2[NAME] (n)
+ Stmt/4[AssignStmt]
- NAME (n)
+ Exp/0[AddExp]
- MulExp/0[NAME] (n)
- MINUS (-)
- MulExp/0[NUMBER] (1)
)");
}