mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 11:55:30 +00:00
Throw operator support
This commit is contained in:
parent
d4aa6e7df5
commit
0dab91d8d9
File diff suppressed because one or more lines are too long
BIN
docs/native.wasm
BIN
docs/native.wasm
Binary file not shown.
22
peglib.h
22
peglib.h
@ -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
|
||||||
|
134
test/test2.cc
134
test/test2.cc
@ -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)
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user