# Seq PEG grammar # Adpoted from Python 3's PEG grammar (https://docs.python.org/3/reference/grammar.html) # TODO: nice docstrs %preamble { #include "parser/peg/rules.h" #include using namespace std; using namespace seq::ast; #define V0 VS[0] #define V1 VS[1] #define V2 VS[2] #define ac std::any_cast #define ac_expr std::any_cast #define ac_stmt std::any_cast #define SemVals peg::SemanticValues template auto vmap(const peg::SemanticValues &c, F &&f) { return vmap(static_cast&>(c), f); } template auto ast(Tsv &s, Ts &&...args) { auto t = make_shared(std::forward(args)...); t->setSrcInfo(s); return std::static_pointer_cast(t); } auto chain(peg::SemanticValues &VS, const seq::SrcInfo &LOC) { auto b = ac_expr(V0); for (int i = 1; i < VS.size(); i++) b = ast(LOC, b, VS.token_to_string(i - 1), ac_expr(VS[i])); return b; } auto wrap_tuple(peg::SemanticValues &VS, const seq::SrcInfo &LOC) { if (VS.size() == 1 && VS.tokens.empty()) return ac_expr(V0); return ast(LOC, VS.transform()); } } program <- (statements (_ EOL)* / (_ EOL)*) !. { if (VS.empty()) return ast(LOC); return ac_stmt(V0); } fstring <- star_expressions _ !. # Macros list(c, e) <- e (_ c _ e)* tlist(c, e) <- e (_ c _ e)* (_ )? statements <- ((_ EOL)* statement)+ { return ast(LOC, VS.transform()); } statement <- SAMEDENT compound_stmt / SAMEDENT simple_stmt simple_stmt <- tlist(';', small_stmt) _ EOL { return ast(LOC, VS.transform()); } small_stmt <- / assignment / 'pass' &(SPACE / ';' / EOL) { return any(ast(LOC)); } / 'break' &(SPACE / ';' / EOL) { return any(ast(LOC)); } / 'continue' &(SPACE / ';' / EOL) { return any(ast(LOC)); } / global_stmt / yield_stmt / assert_stmt / del_stmt / return_stmt / raise_stmt / print_stmt / import_stmt / expressions &(_ ';' / _ EOL) { return any(ast(LOC, ac_expr(V0))); } / NAME SPACE expressions { auto kwd = ac(V0); if (!CTX.hasCustomExprStmt(kwd)) { auto s = "keyword '" + kwd + "' not recognized"; throw peg::parse_error(s.c_str()); } return any(ast(LOC, kwd, ac_expr(V1), nullptr)); } assignment <- / id _ ':' _ expression (_ '=' _ star_expressions)? { return ast(LOC, ac_expr(V0), VS.size() > 2 ? ac_expr(V2) : nullptr, ac_expr(V1) ); } / (star_targets _ (!'==' '=') _)+ star_expressions !(_ '=') { vector stmts; for (int i = int(VS.size()) - 2; i >= 0; i--) stmts.push_back(ast(LOC, ac_expr(VS[i]), ac_expr(VS[i + 1]))); return ast(LOC, move(stmts)); } / star_expression _ augassign '=' ^ _ star_expressions { return ast(LOC, ac_expr(V0), ast(LOC, ac_expr(V0), ac(V1), ac_expr(V2), true) ); } augassign <- < '+' / '-' / '**' / '*' / '@' / '//' / '/' / '%' / '&' / '|' / '^' / '<<' / '>>' > { return VS.token_to_string(); } global_stmt <- 'global' SPACE tlist(',', NAME) { return ast(LOC, vmap(VS, [&](const any &i) { return ast(LOC, ac(i)); }) ); } yield_stmt <- / 'yield' SPACE 'from' SPACE expression { return ast(LOC, ac_expr(V0)); } / 'yield' (SPACE expressions)? { return ast(LOC, !VS.empty() ? ac_expr(V0) : nullptr); } assert_stmt <- 'assert' SPACE expression (_ ',' _ expression)? { return ast(LOC, ac_expr(V0), VS.size() > 1 ? ac_expr(V1) : nullptr); } # TODO: do targets as in Python del_stmt <- 'del' SPACE tlist(',', expression) { return ast(LOC, vmap(VS, [&](const any &i) { return ast(LOC, ac_expr(i)); }) ); } return_stmt <- 'return' (SPACE expressions)? { return ast(LOC, !VS.empty() ? ac_expr(V0) : nullptr); } # TODO: raise expression 'from' expression raise_stmt <- 'raise' (SPACE expression)? { return ast(LOC, !VS.empty() ? ac_expr(V0) : nullptr); } print_stmt <- / 'print' SPACE star_expression (_ ',' _ star_expression)* (_ <','>)? { return ast(LOC, VS.transform(), !VS.tokens.empty()); } / 'print' _ &EOL { return ast(LOC, vector{}, false); } import_stmt <- import_name / import_from import_name <- 'import' SPACE list(',', as_name) { return ast(LOC, vmap(VS.transform>(), [&](const pair &i) { return ast(LOC, i.first, nullptr, vector{}, nullptr, i.second); }) ); } as_name <- dot_name (SPACE 'as' SPACE NAME)? { return pair(ac_expr(V0), VS.size() > 1 ? ac(V1) : ""); } import_from <- / 'from' SPACE (_ <'.'>)* (_ dot_name)? SPACE 'import' SPACE '*' { return ast(LOC, VS.size() == 1 ? ac_expr(V0) : nullptr, ast(LOC, "*"), vector{}, nullptr, "", int(VS.tokens.size()) ); } / 'from' SPACE (_ <'.'>)* (_ dot_name)? SPACE 'import' SPACE (from_as_parens / from_as_items) { auto f = VS.size() == 2 ? ac_expr(V0) : nullptr; return ast(LOC, vmap( ac(VS.size() == 2 ? V1 : V0), [&](const any &i) { auto p = ac>(i); auto t = ac, ExprPtr>>(p.first); return ast(LOC, f, get<0>(t), move(get<1>(t)), get<2>(t), p.second, int(VS.tokens.size()) ); } ) ); } from_as_parens <- '(' _ tlist(',', from_as) _ ')' { return VS; } from_as_items <- list(',', from_as) { return VS; } from_as <- from_id (SPACE 'as' SPACE NAME)? { return pair(V0, VS.size() > 1 ? ac(V1) : ""); } from_id <- / dot_name _ from_params (_ '->' _ expression)? { return tuple( ac_expr(V0), ac(V1).transform(), VS.size() > 2 ? ac_expr(V2) : ast(LOC, "void") ); } / dot_name { return tuple(ac_expr(V0), vector{}, (ExprPtr)nullptr); } dot_name <- id (_ '.' _ NAME)* { if (VS.size() == 1) return ac_expr(V0); auto dot = ast(LOC, ac_expr(V0), ac(V1)); for (int i = 2; i < VS.size(); i++) dot = ast(LOC, dot, ac(VS[i])); return dot; } from_params <- '(' _ tlist(',', from_param)? _ ')' { return VS; } from_param <- expression { return Param{"", ac_expr(V0), nullptr}; } #TODO expand import logic / param { return ac(V0); } suite <- (simple_stmt / (_ EOL)+ &INDENT statements (_ EOL)* &DEDENT) { auto s = ac_stmt(V0); dynamic_pointer_cast(s)->ownBlock = true; return s; } compound_stmt <- / function / if_stmt / class / with_stmt / for / try_stmt / while_stmt / match_stmt / custom_stmt if_stmt <- ('if' SPACE named_expression _ ':' _ suite) (SAMEDENT 'elif' SPACE named_expression _ ':' _ suite)* (SAMEDENT 'else' _ ':' _ suite)? { shared_ptr stmt = ast(LOC, nullptr, nullptr); IfStmt *p = (IfStmt*)stmt.get(); for (int i = 0; i < VS.size(); i += 2) { if (i == VS.size() - 1) { p->elseSuite = ac_stmt(VS[i]); } else { if (i) { p->elseSuite = ast(LOC, nullptr, nullptr); p = (IfStmt*)(p->elseSuite.get()); } p->cond = ac_expr(VS[i]); p->ifSuite = ac_stmt(VS[i + 1]); } } return stmt; } while_stmt <- ('while' SPACE named_expression _ ':' _ suite) (SAMEDENT 'else' (SPACE 'not' SPACE 'break')* _ ':' _ suite)? { return ast(LOC, ac_expr(V0), ac_stmt(V1), VS.size() > 2 ? ac_stmt(V2) : nullptr ); } for <- decorator? for_stmt { if (VS.size() > 1) { auto s = dynamic_pointer_cast(ac_stmt(V1)); s->decorator = ac_expr(V0); return static_pointer_cast(s); } return ac_stmt(V0); } for_stmt <- ('for' SPACE star_targets) (SPACE 'in' SPACE star_expressions _ ':' _ suite) (SAMEDENT 'else' (SPACE 'not' SPACE 'break')* _ ':' _ suite)? { return ast(LOC, ac_expr(V0), ac_expr(V1), ac_stmt(V2), VS.size() > 3 ? ac_stmt(VS[3]) : nullptr ); } with_stmt <- 'with' SPACE (with_parens_item / with_item) _ ':' _ suite { return ast(LOC, ac(V0).transform>(), ac_stmt(V1) ); } with_parens_item <- '(' _ tlist(',', as_item) _ ')' { return VS; } with_item <- list(',', as_item) { return VS; } as_item <- / expression SPACE 'as' SPACE star_target &(_ (',' / ')' / ':')) { return pair(ac_expr(V0), ac_expr(V1)); } / expression { return pair(ac_expr(V0), (ExprPtr)nullptr); } # TODO: else block? try_stmt <- / ('try' _ ':' _ suite) excepts (SAMEDENT 'finally' _ ':' _ suite)? { return ast(LOC, ac_stmt(V0), ac(V1).transform(), VS.size() > 2 ? ac_stmt(V2): nullptr ); } / ('try' _ ':' _ suite) (SAMEDENT 'finally' _ ':' _ suite)? { return ast(LOC, ac_stmt(V0), vector{}, VS.size() > 1 ? ac_stmt(V1): nullptr ); } excepts <- (SAMEDENT except_block)+ { return VS; } except_block <- / 'except' SPACE expression (SPACE 'as' SPACE NAME)? _ ':' _ suite { if (VS.size() == 3) return TryStmt::Catch{ac(V1), ac_expr(V0), ac_stmt(V2)}; else return TryStmt::Catch{"", ac_expr(V0), ac_stmt(V1)}; } / 'except' _ ':' _ suite { return TryStmt::Catch{"", nullptr, ac_stmt(V0)}; } function <- / extern_decorators function_def (_ EOL)+ &INDENT extern (_ EOL)* &DEDENT { auto fn = dynamic_pointer_cast(ac_stmt(V1)); fn->decorators = ac>(V0); fn->suite = ast(LOC, ast(LOC, ac(V2))); return static_pointer_cast(fn); } / decorators? function_def _ suite { auto fn = dynamic_pointer_cast(ac_stmt(VS.size() > 2 ? V1 : V0)); if (VS.size() > 2) fn->decorators = ac>(V0); fn->suite = ac_stmt(VS.size() > 2 ? V2 : V1); return static_pointer_cast(fn); } extern <- (empty_line* EXTERNDENT (!EOL .)* EOL empty_line*)+ { return string(VS.sv()); } ~empty_line <- [ \t]* EOL function_def <- / 'def' SPACE NAME _ generics _ params (_ '->' _ expression)? _ ':' { auto params = ac(V2).transform(); for (auto &p: ac>(V1)) params.push_back(p); return ast(LOC, ac(V0), VS.size() == 4 ? ac_expr(VS[3]) : nullptr, params, nullptr ); } / 'def' SPACE NAME _ params (_ '->' _ expression)? _ ':' { return ast(LOC, ac(V0), VS.size() == 3 ? ac_expr(VS[2]) : nullptr, ac(V1).transform(), nullptr ); } params <- '(' _ tlist(',', param)? _ ')' { return VS; } param <- / param_name _ ':' _ expression (_ '=' _ expression)? { return Param(ac(V0), ac_expr(V1), VS.size() > 2 ? ac_expr(V2) : nullptr); } / param_name (_ '=' _ expression)? { return Param(ac(V0), nullptr, VS.size() > 1 ? ac_expr(V1) : nullptr); } param_name <- <'**' / '*'>? _ NAME { return (!VS.tokens.empty() ? VS.token_to_string() : "") + ac(V0); } generics <- '[' _ tlist(',', param) _ ']' { vector params; for (auto &p: VS) { auto v = ac(p); v.generic = true; if (!v.type) v.type = ast(LOC, "type"); params.push_back(v); } return params; } decorators <- decorator+ { return VS.transform(); } decorator <- ('@' _ !(('llvm' / 'python') _ EOL) named_expression _ EOL SAMEDENT) { return ac_expr(V0); } extern_decorators <- / decorators? ('@' _ <'llvm'/'python'> _ EOL SAMEDENT) decorators? { vector vs{ast(LOC, VS.token_to_string())}; for (auto &v: VS) { auto nv = ac>(v); vs.insert(vs.end(), nv.begin(), nv.end()); } return vs; } class <- decorators? class_def { if (VS.size() == 2) { auto fn = ac_stmt(V1); dynamic_pointer_cast(fn)->decorators = ac>(V0); return fn; } return ac_stmt(V0); } base_class_args <- '(' _ tlist(',', expression)? _ ')' { return VS.transform(); } class_args <- / generics _ base_class_args { return make_pair(ac>(V0), ac>(V1)); } / generics { return make_pair(ac>(V0), vector{}); } / base_class_args { return make_pair(vector{}, ac>(V0)); } class_def <- 'class' SPACE NAME _ class_args? _ ':' _ suite { vector generics; vector baseClasses; if (VS.size() == 3) std::tie(generics, baseClasses) = ac, vector>>(V1); vector args; auto suite = make_shared(); auto s = const_cast(ac_stmt(VS.size() == 3 ? V2 : V1)->getSuite()); seqassert(s, "not a suite"); for (auto &i: s->stmts) { if (auto a = const_cast(i->getAssign())) if (a->lhs->getId()) { args.push_back(Param(a->lhs->getId()->value, move(a->type), move(a->rhs))); continue; } suite->stmts.push_back(i); } for (auto &p: generics) args.push_back(p); return ast(LOC, ac(V0), move(args), suite, Attr(), vector{}, baseClasses ); } match_stmt <- 'match' SPACE expression _ ':' (_ EOL)+ &INDENT (SAMEDENT case)+ (_ EOL)* &DEDENT { return ast(LOC, ac_expr(V0), VS.transform(1)); } case <- / 'case' SPACE expression SPACE 'if' SPACE pipe _ ':' _ suite { return MatchStmt::MatchCase{ac_expr(V0), ac_expr(V1), ac_stmt(V2)}; } / 'case' SPACE expression _ ':' _ suite { return MatchStmt::MatchCase{ac_expr(V0), nullptr, ac_stmt(V1)}; } custom_stmt <- / NAME SPACE expression _ ':' _ suite { auto kwd = ac(V0); if (!CTX.hasCustomStmtKeyword(kwd, true)) { auto s = "keyword '" + kwd + "' not recognized"; throw peg::parse_error(s.c_str()); } return ast(LOC, kwd, ac_expr(V1), ac_stmt(V2)); } / NAME _ ':' _ suite { auto kwd = ac(V0); if (!CTX.hasCustomStmtKeyword(kwd, false)) { auto s = "keyword '" + kwd + "' not recognized"; throw peg::parse_error(s.c_str()); } return ast(LOC, kwd, nullptr, ac_stmt(V2)); } ######################################################################################## # (2) Expressions ######################################################################################## expressions <- tlist(',', expression) { return wrap_tuple(VS, LOC); } expression <- / lambdef { return ac_expr(V0); } / disjunction SPACE 'if' SPACE disjunction SPACE 'else' SPACE expression { return ast(LOC, ac_expr(V1), ac_expr(V0), ac_expr(V2)); } / pipe { return ac_expr(V0); } # TODO: make it more pythonic lambdef <- / 'lambda' SPACE list(',', NAME) _ ':' _ expression { return ast(LOC, VS.transform(0, VS.size() - 1), ac_expr(VS.back()) ); } / 'lambda' _ ':' _ expression { return ast(LOC, vector{}, ac_expr(VS.back())); } pipe <- / disjunction (_ <'|>' / '||>'> _ disjunction)+ { vector v; for (int i = 0; i < VS.size(); i++) v.push_back(PipeExpr::Pipe{i ? VS.token_to_string(i - 1) : "", ac_expr(VS[i])}); return ast(LOC, move(v)); } / disjunction { return ac_expr(V0); } disjunction <- / conjunction (SPACE 'or' SPACE conjunction)+ { auto b = ast(LOC, ac_expr(V0), "||", ac_expr(V1)); for (int i = 2; i < VS.size(); i++) b = ast(LOC, b, "||", ac_expr(VS[i])); return b; } / conjunction { return ac_expr(V0); } conjunction <- / inversion (SPACE 'and' SPACE inversion)+ { auto b = ast(LOC, ac_expr(V0), "&&", ac_expr(V1)); for (int i = 2; i < VS.size(); i++) b = ast(LOC, b, "&&", ac_expr(VS[i])); return b; } / inversion { return ac_expr(V0); } inversion <- / 'not' SPACE inversion { return ast(LOC, "!", ac_expr(V0)); } / comparison { return ac_expr(V0); } comparison <- bitwise_or compare_op_bitwise_or* { if (VS.size() == 1) { return ac_expr(V0); } else if (VS.size() == 2) { auto p = ac>(V1); return ast(LOC, ac_expr(V0), p.first, p.second); } else { vector> v{pair(string(), ac_expr(V0))}; auto vp = VS.transform>(1); v.insert(v.end(), vp.begin(), vp.end()); return ast(LOC, move(v)); } } compare_op_bitwise_or <- / SPACE 'not' SPACE 'in' SPACE bitwise_or { return pair(string("not in"), ac_expr(V0)); } / SPACE 'is' SPACE 'not' SPACE bitwise_or { return pair(string("is not"), ac_expr(V0)); } / SPACE <'in' / 'is'> SPACE bitwise_or { return pair(VS.token_to_string(), ac_expr(V0)); } / _ <'==' / '!=' / '<=' / '<' / '>=' / '>'> _ bitwise_or { return pair(VS.token_to_string(), ac_expr(V0)); } bitwise_or <- bitwise_xor (_ <'|'> _ bitwise_xor)* { return chain(VS, LOC); } bitwise_xor <- bitwise_and (_ <'^'> _ bitwise_and)* { return chain(VS, LOC); } bitwise_and <- shift_expr (_ <'&'> _ shift_expr )* { return chain(VS, LOC); } shift_expr <- sum (_ <'<<' / '>>'> _ sum )* { return chain(VS, LOC); } sum <- term (_ <'+' / '-'> _ term)* { return chain(VS, LOC); } term <- factor (_ <'*' / '//' / '/' / '%' / '@'> _ factor)* { return chain(VS, LOC); } factor <- / <'+' / '-' / '~'> _ factor { return ast(LOC, VS.token_to_string(), ac_expr(V0)); } / power { return ac_expr(V0); } power <- / primary _ <'**'> _ factor { return ast(LOC, ac_expr(V0), "**", ac_expr(V1)); } / primary { return ac_expr(V0); } primary <- atom (_ primary_tail)* { auto e = ac(V0); for (int i = 1; i < VS.size(); i++) { auto p = ac>(VS[i]); if (p.first == 0) e = ast(LOC, e, ac(p.second)); else if (p.first == 1) e = ast(LOC, e, ac_expr(p.second)); else if (p.first == 2) e = ast(LOC, e, ac>(p.second)); else e = ast(LOC, e, ac_expr(p.second)); } return e; } primary_tail <- / '.' _ NAME { return pair(0, V0); } / genexp { return pair(1, V0); } / arguments { return pair(2, VS.size() ? V0 : any(vector{})); } / slices { return pair(3, V0); } slices <- '[' _ tlist(',', slice) _ ']' { return wrap_tuple(VS, LOC); } slice <- / slice_part _ ':' _ slice_part (_ ':' _ slice_part)? { return ast(LOC, ac_expr(V0), ac_expr(V1), VS.size() > 2 ? ac_expr(V2) : nullptr ); } / expression { return ac_expr(V0); } slice_part <- expression? { return VS.size() ? V0 : make_any(nullptr); } atom <- / STRING (SPACE STRING)* { return ast(LOC, VS.transform>()); } / id { return ac_expr(V0); } / 'True' { return ast(LOC, true); } / 'False' { return ast(LOC, false);} / 'None' { return ast(LOC); } / INT _ '...' _ INT { return ast(LOC, ast(LOC, ac(V0)), ast(LOC, ac(V1)) ); } / FLOAT { // Right now suffixes are _not_ supported return ast(LOC, ac(V0), ""); } / INT NAME? { return ast(LOC, ac(V0), VS.size() > 1 ? ac(V1) : ""); } / parentheses { return ac_expr(V0); } / '...' { return ast(LOC); } parentheses <- ( tuple / yield / named / genexp / listexpr / listcomp / dict / set / dictcomp / setcomp ) tuple <- / '(' _ ')' { return ast(LOC, VS.transform()); } / '(' _ tlist(',', star_named_expression) _ ')' { return wrap_tuple(VS, LOC); } yield <- '(' _ 'yield' _ ')' { return ast(LOC); } named <- '(' _ named_expression _ ')' genexp <- '(' _ named_expression SPACE for_if_clauses _ ')' { return ast(LOC, GeneratorExpr::Generator, ac_expr(V0), ac(V1).transform() ); } listexpr <- '[' _ tlist(',', star_named_expression)? _ ']' { return ast(LOC, VS.transform()); } listcomp <- '[' _ named_expression SPACE for_if_clauses _ ']' { return ast(LOC, GeneratorExpr::ListGenerator, ac_expr(V0), ac(V1).transform() ); } set <- '{' _ tlist(',', star_named_expression) _ '}' { return ast(LOC, VS.transform()); } setcomp <- '{' _ named_expression SPACE for_if_clauses _ '}' { return ast(LOC, GeneratorExpr::SetGenerator, ac_expr(V0), ac(V1).transform() ); } dict <- '{' _ tlist(',', double_starred_kvpair)? _ '}' { return ast(LOC, VS.transform()); } dictcomp <- '{' _ kvpair SPACE for_if_clauses _ '}' { auto p = ac(V0); return ast(LOC, p.key, p.value, ac(V1).transform() ); } double_starred_kvpair <- / '**' _ bitwise_or { return DictExpr::DictItem{ ast(LOC, ""), ast(LOC, ac_expr(V0)) }; } / kvpair { return ac(V0); } kvpair <- expression _ ':' _ expression { return DictExpr::DictItem{ac_expr(V0), ac_expr(V1)}; } for_if_clauses <- for_if_clause (SPACE for_if_clause)* { return VS; } for_if_clause <- 'for' SPACE star_targets SPACE 'in' SPACE disjunction (SPACE 'if' SPACE disjunction)* { return GeneratorBody{ac_expr(V0), ac_expr(V1), VS.transform(2)}; } star_targets <- tlist(',', star_target) { return wrap_tuple(VS, LOC); } star_target <- / '*' _ !'*' star_target { return ast(LOC, ac_expr(V0)); } / star_parens { return ac_expr(V0); } / primary { return ac_expr(V0); } star_parens <- / '(' _ tlist(',', star_target) _ ')' { return wrap_tuple(VS, LOC); } / '[' _ tlist(',', star_target) _ ']' { return wrap_tuple(VS, LOC); } star_expressions <- tlist(',', star_expression) { return wrap_tuple(VS, LOC); } star_expression <- / '*' _ bitwise_or { return ast(LOC, ac_expr(V0)); } / expression { return ac_expr(V0); } star_named_expression <- / '*' _ bitwise_or { return ast(LOC, ac_expr(V0)); } / named_expression { return ac_expr(V0); } named_expression <- / NAME _ ':=' _ ^ expression { return ast(LOC, ast(LOC, ac(V0)), ac_expr(V1)); } / expression !(_ ':=') { return ac_expr(V0); } arguments <- '(' _ tlist(',', args)? _ ')' { vector result; for (auto &v: VS) for (auto &i: ac>(v)) result.push_back(i); return result; } args <- (simple_args (_ ',' _ kwargs)? / kwargs) { auto args = ac>(V0); if (VS.size() > 1) { auto v = ac>(V1); args.insert(args.end(), v.begin(), v.end()); } return args; } simple_args <- list(',', (starred_expression / named_expression !(_ '='))) { return vmap(VS, [](auto &i) { return CallExpr::Arg{"", ac_expr(i)}; }); } starred_expression <- '*' _ expression { return ast(LOC, ac_expr(V0)); } kwargs <- / list(',', kwarg_or_starred) _ ',' _ list(',', kwarg_or_double_starred) { return VS.transform(); } / list(',', kwarg_or_starred) { return VS.transform(); } / list(',', kwarg_or_double_starred) { return VS.transform(); } kwarg_or_starred <- / NAME _ '=' _ expression { return CallExpr::Arg{ac(V0), ac_expr(V1)}; } / starred_expression { return CallExpr::Arg{"", ac_expr(V0)}; } kwarg_or_double_starred <- / NAME _ '=' _ expression { return CallExpr::Arg{ac(V0), ac_expr(V1)}; } / '**' _ expression { return CallExpr::Arg{"", ast(LOC, ac_expr(V0))}; } id <- NAME { return ast(LOC, ac(V0)); } INT <- (BININT / HEXINT / DECINT) { return string(VS.sv()); } BININT <- <'0' [bB] [0-1] ('_'* [0-1])*> HEXINT <- <'0' [xX] [0-9a-fA-F] ('_'? [0-9a-fA-F])*> DECINT <- <[0-9] ('_'? [0-9])*> FLOAT <- (EXPFLOAT / PTFLOAT) { return string(VS.sv()); } PTFLOAT <- DECINT? '.' DECINT / DECINT '.' EXPFLOAT <- (PTFLOAT / DECINT) [eE] <'+' / '-'>? DECINT NAME <- / keyword [a-zA-Z_0-9]+ { return string(VS.sv()); } / !keyword <[a-zA-Z_] [a-zA-Z_0-9]*> { return VS.token_to_string(); } STRING <- { auto p = pair( ac(VS.size() > 1 ? V1 : V0), VS.size() > 1 ? ac(V0) : "" ); if (p.second != "r" && p.second != "R") try { p.first = unescape(p.first); } catch (std::invalid_argument &e) { throw peg::parse_error("invalid code in a string"); } catch (std::out_of_range &) { throw peg::parse_error("invalid code in a string"); } else p.second = ""; return p; } STR <- < '"""' (!'"""' CHAR)* '"""' / '\'\'\'' (!'\'\'\'' CHAR)* '\'\'\'' / '"' (!('"' / EOL) CHAR)* '"' / '\'' (!('\'' / EOL) CHAR)* '\'' > { string s; s.reserve(VS.size()); for (auto &v: VS) s.append(ac(v)); return s; } CHAR <- ('\\' . / .) { return string(VS.sv()); } ~COMMENT <- <'#' (!EOL .)*> ~INDENT:NO_PACKRAT <- <[ \t]*> { if ((CTX.indent.empty() && VS.sv().size()) || (!CTX.indent.empty() && VS.sv().size() > CTX.indent.top())) CTX.indent.push(VS.sv().size()); else throw peg::parse_error("bad indent"); } ~SAMEDENT:NO_PACKRAT <- <[ \t]*> { if ((!CTX.indent.size() && VS.sv().size()) || (CTX.indent.size() && VS.sv().size() != CTX.indent.top())) throw peg::parse_error(); } ~DEDENT:NO_PACKRAT <- <[ \t]*> { if (CTX.indent.size() && VS.sv().size() < CTX.indent.top()) CTX.indent.pop(); else throw peg::parse_error("bad dedent"); } ~EXTERNDENT:NO_PACKRAT <- <[ \t]*> { if ((!CTX.indent.size() && VS.sv().size()) || (CTX.indent.size() && VS.sv().size() < CTX.indent.top())) throw peg::parse_error(); } ~EOL <- <[\r][\n] / [\r\n]> ~SPACE <- ([ \t]+ / COMMENT / NLP EOL) SPACE? ~_ <- SPACE? # TODO: add async / await ~keyword <- < 'False' / 'else' / 'import' / 'pass' / 'None' / 'break' / 'except' / 'in' / 'raise' / 'True' / 'class' / 'finally' / 'is' / 'return' / 'and' / 'continue' / 'for' / 'as' / 'lambda' / 'try' / 'def' / 'from' / 'while' 'assert' / 'del' / 'global' / 'not' / 'with' / 'elif' / 'if' / 'or' / 'yield' >