From cb906e739f27931e9798510cd83725131ed55209 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Thu, 13 Jul 2017 16:03:11 +0800 Subject: rewrite parsing codes with parserlib. --- MoonParser/main.cpp | 2121 ++++++++++++--------------------------------------- 1 file changed, 502 insertions(+), 1619 deletions(-) (limited to 'MoonParser/main.cpp') diff --git a/MoonParser/main.cpp b/MoonParser/main.cpp index e692732..cf7bc2d 100644 --- a/MoonParser/main.cpp +++ b/MoonParser/main.cpp @@ -1,1698 +1,581 @@ -// -// main.cpp -// PegtlStudy -// -// Created by Li Jin on 2017/6/16. -// Copyright © 2017年 Li Jin. All rights reserved. -// - #include +using std::cout; +#include +using std::string; #include -#include -#include +using std::unordered_set; #include -#include -#include "pegtl.hpp" -#include "pegtl/analyze.hpp" -#include "slice.h" -using namespace silly; - -using namespace tao::pegtl; - -namespace helloworld // with operator precedence climbing +using std::stack; +#include +#include +using std::stringstream; +#include "parserlib.hpp" +using namespace parserlib; + +#define p(expr) user(expr, [](const item_t& item) \ +{ \ + stringstream stream; \ + for (input_it i = item.begin; i != item.end; ++i) stream << static_cast(*i); \ + cout << #expr << ": [" << stream.str() << "]\n"; \ + return true; \ +}) + +struct State { - struct Stack + State() { - Stack() - { - pushStack(); - } - void pushValue(int value) - { - _values.back().push(value); - } - void pushOp(char op) - { - _ops.back().push(op); - } - void pushStack() - { - _values.emplace_back(); - _ops.emplace_back(); - } - int getPriority(char op) - { - switch (op) - { - case '+': return 1; - case '-': return 1; - case '*': return 2; - case '/': return 2; - } - return 0; - } - /* - def compute_expr(tokenizer, min_prec): - atom_lhs = tokenizer.get_next_token() - - while True: - cur = tokenizer.cur_token - if (cur is None or OPINFO_MAP[cur.value].prec < min_prec): - break - - op = cur.value - prec, assoc = OPINFO_MAP[op] - next_min_prec = prec + 1 if assoc == 'LEFT' else prec - - atom_rhs = compute_expr(tokenizer, next_min_prec) - - atom_lhs = compute_op(op, atom_lhs, atom_rhs) - - return atom_lhs - */ - int parseNext(int minPrecedence) - { - int lhs = _values.back().front(); - _values.back().pop(); - - while (true) - { - if (_ops.back().empty()) - { - break; - } - char op = _ops.back().front(); - if (getPriority(op) < minPrecedence) - { - break; - } - _ops.back().pop(); - int nextMinPrecedence = getPriority(op) + 1; - int rhs = parseNext(nextMinPrecedence); - switch (op) - { - case '+': - std::cout << lhs << " + " << rhs << " = " << lhs+rhs << '\n'; - lhs = lhs + rhs; - break; - case '-': - std::cout << lhs << " - " << rhs << " = " << lhs-rhs << '\n'; - lhs = lhs - rhs; - break; - case '*': - std::cout << lhs << " * " << rhs << " = " << lhs*rhs << '\n'; - lhs = lhs * rhs; - break; - case '/': - std::cout << lhs << " / " << rhs << " = " << lhs/rhs << '\n'; - lhs = lhs / rhs; - break; - } - } - return lhs; - } - void popStack() - { - int value = parseNext(0); - _values.pop_back(); - if (_values.empty()) - { - _values.emplace_back(); - } - _ops.pop_back(); - if (_ops.empty()) - { - _ops.emplace_back(); - } - pushValue(value); - } - int getValue() const - { - return _values.back().back(); - } - private: - std::vector> _ops; - std::vector> _values; + indents.push(0); + stringOpen = -1; + } + size_t stringOpen; + stack indents; + stack doStack; + unordered_set keywords = { + "and", "while", "else", "using", "continue", + "local", "not", "then", "return", "from", + "extends", "for", "do", "or", "export", + "class", "in", "unless", "when", "elseif", + "switch", "break", "if", "with", "import" }; - - struct number : seq>, plus> { }; - - struct expr; - - struct bracket : if_must, expr, one<')'>> { }; - - struct atomic : sor { }; - - struct op : one<'+', '-', '*', '/'> { }; - - struct expr : list { }; - - template - struct action : nothing { }; - - template<> - struct action +}; + +rule Any = any(); +rule White = *set(" \t\r\n"); +rule plain_space = *set(" \t"); +rule Break = nl(-expr('\r') >> '\n'); +rule Stop = Break | eof(); +rule Comment = "--" >> *(not_(set("\r\n")) >> Any) >> and_(Stop); +rule Indent = *set(" \t"); +rule Space = plain_space >> -Comment; +rule SomeSpace = +set(" \t") >> -Comment; +rule SpaceBreak = Space >> Break; +rule EmptyLine = SpaceBreak; +rule AlphaNum = range('a', 'z') | range('A', 'Z') | range('0', '9') | '_'; +rule _Name = (range('a', 'z') | range('A', 'Z') | '_') >> *AlphaNum; +rule SpaceName = Space >> _Name; +rule _Num = + ( + "0x" >> + +(range('0', '9') | range('a', 'f') | range('A', 'F')) >> + -(-set("uU") >> set("lL") >> set("lL")) + ) | ( + +range('0', '9') >> -set("uU") >> set("lL") >> set("lL") + ) | ( + ( + (+range('0', '9') >> -('.' >> +range('0', '9'))) | + ('.' >> +range('0', '9')) + ) >> -(set("eE") >> -expr('-') >> +range('0', '9')) + ); +rule Num = Space >> _Num; +rule Cut = false_(); +rule Nothing = true_(); + +#define sym(str) (Space >> str) +#define symx(str) expr(str) +#define ensure(patt, finally) (((patt) >> (finally)) | ((finally) >> (Cut))) +#define key(str) (Space >> str >> not_(AlphaNum)) +#define opWord(str) (Space >> str >> not_(AlphaNum)) +#define op(str) (Space >> str) + +rule Name = user(SpaceName, [](const item_t& item) +{ + stringstream stream; + for (input_it i = item.begin; i != item.end; ++i) stream << static_cast(*i); + string name; + stream >> name; + State* st = reinterpret_cast(item.user_data); + auto it = st->keywords.find(name); + return it == st->keywords.end(); +}); + +rule self = expr('@'); +rule self_name = '@' >> _Name; +rule self_class = expr("@@"); +rule self_class_name = "@@" >> _Name; + +rule SelfName = Space >> (self_class_name | self_class | self_name | self); +rule KeyName = SelfName | Space >> _Name; +rule VarArg = Space >> "..."; + +rule check_indent = user(Indent, [](const item_t& item) +{ + int indent = 0; + for (input_it i = item.begin; i != item.end; ++i) { - template - static void apply(const Input& in, Stack& stack) + switch (*i) { - stack.pushValue(std::stoi(in.string())); + case ' ': indent++; break; + case '\t': indent += 4; break; } - }; + } + State* st = reinterpret_cast(item.user_data); + return st->indents.top() == indent; +}); +rule CheckIndent = and_(check_indent); - template<> - struct action +rule advance = user(Indent, [](const item_t& item) +{ + int indent = 0; + for (input_it i = item.begin; i != item.end; ++i) { - template - static void apply(const Input& in, Stack& stack) + switch (*i) { - stack.pushOp(*in.begin()); + case ' ': indent++; break; + case '\t': indent += 4; break; } - }; - - template<> - struct action> + } + State* st = reinterpret_cast(item.user_data); + int top = st->indents.top(); + if (top != -1 && indent > top) { - static void apply0(Stack& stack) - { - stack.pushStack(); - } - }; + st->indents.push(indent); + return true; + } + return false; +}); +rule Advance = and_(advance); - template<> - struct action +rule push_indent = user(Indent, [](const item_t& item) +{ + int indent = 0; + for (input_it i = item.begin; i != item.end; ++i) { - template - static void apply(const Input& in, Stack& stack) + switch (*i) { - stack.popStack(); + case ' ': indent++; break; + case '\t': indent += 4; break; } - }; + } + State* st = reinterpret_cast(item.user_data); + st->indents.push(indent); + return true; +}); +rule PushIndent = and_(push_indent); -} // namespace hello +rule PreventIndent = user(true_(), [](const item_t& item) +{ + State* st = reinterpret_cast(item.user_data); + st->indents.push(-1); + return true; +}); -namespace moon +rule PopIndent = user(true_(), [](const item_t& item) { - int moonType = 0; + State* st = reinterpret_cast(item.user_data); + st->indents.pop(); + return true; +}); - template - int MoonType() - { - static int type = moonType++; - return type; - } +extern rule Block; - struct Node - { - virtual ~Node() {} - slice::Slice token; - }; +rule InBlock = Advance >> Block >> PopIndent; - struct State - { - State() - { - indents.push(0); - stringOpen = -1; - astStack.emplace_back(); - } - size_t stringOpen; - std::stack indents; - std::stack doStack; - std::unordered_set keywords = - { - "and", "while", "else", "using", "continue", - "local", "not", "then", "return", "from", - "extends", "for", "do", "or", "export", - "class", "in", "unless", "when", "elseif", - "switch", "break", "if", "with", "import" - }; - std::stack indexStack; - std::vector>> astStack; - }; +extern rule NameList; - struct White : star> {}; - struct plain_space : star> {}; - struct Break : seq>, one<'\n'>> {}; - struct Stop : sor {}; - struct Comment : seq, star>, any>, at> {}; - struct Indent : star> {}; - struct Space : seq> {}; - struct SomeSpace : seq, opt> {}; - struct SpaceBreak : seq {}; - typedef SpaceBreak EmptyLine; - struct AlphaNum : ranges<'a', 'z', 'A', 'Z', '0', '9', '_', '_'> {}; - struct _Name : seq, star> {}; - struct SpaceName : seq {}; - struct _Num : sor< - seq< - string<'0' ,'x'>, - plus>, - opt>, one<'l', 'L'>, one<'l', 'L'> - >> - >, - seq< - plus>, - seq< - opt>, one<'l', 'L'>, one<'l', 'L'> - > - >, - seq< - sor< - seq< - plus>, - opt, plus> - >> - >, - seq< - one<'.'>, - plus> - > - >, - opt, opt>, plus> - >> - > - > {}; - struct Num : seq {}; - - struct Cut : failure {}; - - template struct sym : seq> {}; - template struct symx : string {}; - - template - struct ensure : sor, seq> {}; - - template struct key : seq, not_at> {}; - template struct opWord : seq, not_at> {}; - template struct op : seq> {}; - - struct Name - { - using analyze_t = analysis::generic; +rule Local = key("local") >> (op('*') | op('^') | NameList); - template class Action, - template class Control, - typename Input> - static bool match(Input& in, State& st) - { - const char* current = in.current(); - memory_input<> memIn(current, in.end() - current, current); - if (SpaceName::match(memIn, st)) - { - auto name = slice::Slice(current, memIn.current() - current); - auto trimed = name; - trimed.trimSpace(); - auto it = st.keywords.find(trimed); - if (it == st.keywords.end()) - { - in.bump(name.size()); - return true; - } - } - return false; - } - }; +rule colon_import_name = sym('\\') >> Name; +rule ImportName = colon_import_name | Name; +rule ImportNameList = *SpaceBreak >> ImportName >> *((+SpaceBreak | sym(',') >> *SpaceBreak) >> ImportName); - struct self : one<'@'> {}; - struct self_name : seq, _Name> {}; - struct self_class : string<'@', '@'> {}; - struct self_class_name : seq, _Name> {}; +extern rule Exp; - struct SelfName : seq> {}; - struct KeyName : sor> {}; - struct VarArg : seq> {}; +rule Import = key("import") >> ImportNameList >> *SpaceBreak >> key("from") >> Exp; +rule BreakLoop = key("break") | key("continue"); - struct CheckIndentBump - { - using analyze_t = analysis::generic; +extern rule ExpListLow, ExpList, Assign; - template class Action, - template class Control, - typename Input> - static bool match(Input& in, State& st) - { - const char* current = in.current(); - if (Indent::match(in, st)) - { - int indent = 0; - for (const char* ch = current; ch < in.current(); ch++) - { - switch (*ch) - { - case ' ': indent++; break; - case '\t': indent += 4; break; - } - } - return st.indents.top() == indent; - } - return false; - } - }; - struct CheckIndent : at {}; +rule Return = key("return") >> (ExpListLow | Nothing); +rule WithExp = ExpList >> -Assign; - struct AdvanceBump - { - using analyze_t = analysis::generic; +extern rule DisableDo, PopDo, Body; - template class Action, - template class Control, - typename Input> - static bool match(Input& in, State& st) - { - const char* current = in.current(); - if (Indent::match(in, st)) - { - int indent = 0; - for (const char* ch = current; ch < in.current(); ch++) - { - switch (*ch) - { - case ' ': indent++; break; - case '\t': indent += 4; break; - } - } - int top = st.indents.top(); - if (top != -1 && indent > top) - { - st.indents.push(indent); - return true; - } - return false; - } - return false; - } - }; - struct Advance : at {}; +rule With = key("with") >> DisableDo >> ensure(WithExp, PopDo) >> -key("do") >> Body; +rule SwitchCase = key("when") >> ExpList >> -key("then") >> Body; +rule SwitchElse = key("else") >> Body; - struct PushIndentBump - { - using analyze_t = analysis::generic; +rule SwitchBlock = *EmptyLine >> + Advance >> + SwitchCase >> + *(+Break >> SwitchCase) >> + -(+Break >> SwitchElse) >> + PopIndent; - template class Action, - template class Control, - typename Input> - static bool match(Input& in, State& st) - { - const char* current = in.current(); - if (Indent::match(in, st)) - { - int indent = 0; - for (const char* ch = current; ch < in.current(); ch++) - { - switch (*ch) - { - case ' ': indent++; break; - case '\t': indent += 4; break; - } - } - st.indents.push(indent); - return true; - } - return false; - } - }; - struct PushIndent : at {}; +rule Switch = key("switch") >> + DisableDo >> ensure(Exp, PopDo) >> + -key("do") >> -Space >> Break >> SwitchBlock; - struct PreventIndentBump - { - using analyze_t = analysis::generic; +rule IfCond = Exp >> -Assign; +rule IfElseIf = -(Break >> *EmptyLine >> CheckIndent) >> key("elseif") >> IfCond >> -key("then") >> Body; +rule IfElse = -(Break >> *EmptyLine >> CheckIndent) >> key("else") >> Body; +rule If = key("if") >> IfCond >> -key("then") >> Body >> *IfElseIf >> -IfElse; +rule Unless = key("unless") >> IfCond >> -key("then") >> Body >> *IfElseIf >> -IfElse; - template class Action, - template class Control, - typename Input> - static bool match(Input& in, State& st) - { - st.indents.push(-1); - return true; - } - }; - struct PreventIndent : at {}; +rule While = key("while") >> DisableDo >> ensure(Exp, PopDo) >> -key("do") >> Body; - struct PopIndentBump - { - using analyze_t = analysis::generic; +rule for_args = Name >> sym('=') >> Exp >> sym(',') >> Exp >> (sym(',') >> Exp | Nothing); - template class Action, - template class Control, - typename Input> - static bool match(Input& in, State& st) - { - st.indents.pop(); - return true; - } - }; - struct PopIndent : at {}; - - struct Block; - - struct InBlock : seq {}; - - struct NameList; - - struct Local : seq< - key<'l', 'o', 'c', 'a', 'l'>, - sor< - sor, op<'^'>>, - NameList - > - > {}; - - struct colon_import_name : seq, Name> {}; - struct ImportName : sor {}; - struct ImportNameList : seq< - star, - ImportName, - star< - sor< - plus, - seq, star> - >, - ImportName - > - > {}; - - struct Exp; - - struct Import : seq, ImportNameList, star, key<'f', 'r', 'o', 'm'>, Exp> {}; - - struct BreakLoop : sor, key<'c', 'o', 'n', 't', 'i', 'n', 'u', 'e'>> {}; - - struct ExpListLow; - - struct ExpList; - struct Assign; - - struct Return : seq, sor> {}; - struct WithExp : seq> {}; - - struct DisableDo; - struct PopDo; - struct Body; - - struct With : seq, DisableDo, ensure, opt>, Body> {}; - - struct SwitchCase : seq, ExpList, opt>, Body> {}; - struct SwitchElse : seq, Body> {}; - struct SwitchBlock : seq< - star, - Advance, - seq< - SwitchCase, - star, SwitchCase>, - opt, SwitchElse> - >, - PopIndent - > {}; - struct Switch : seq, DisableDo, ensure, opt>, opt, Break, SwitchBlock> {}; - - struct IfCond : seq> {}; - - struct IfElse : seq< - opt, CheckIndent>, - key<'e', 'l', 's', 'e'>, Body - > {}; - - struct IfElseIf : seq< - opt, CheckIndent>, - key<'e', 'l', 's', 'e', 'i', 'f'>, IfCond, - opt>, Body - > {}; - - struct If : seq, IfCond, opt>, Body, star, opt> {}; - struct Unless : seq, IfCond, opt>, Body, star, opt> {}; - - struct While : seq, DisableDo, ensure, opt>, Body> {}; - struct For : seq, DisableDo, - ensure< - seq< - Name, sym<'='>, - seq, Exp, opt, Exp>> - >, - PopDo - >, - opt>, Body> {}; - - struct AssignableNameList; - - struct ForEach : seq< - key<'f', 'o', 'r'>, - AssignableNameList, - key<'i', 'n'>, - DisableDo, - ensure< - sor< - seq, Exp>, ExpList - >, - PopDo - >, - opt>, - Body - > {}; - - struct Do - { - using analyze_t = analysis::generic; +rule For = key("for") >> DisableDo >> + ensure(for_args, PopDo) >> + -key("do") >> Body; - template class Action, - template class Control, - typename Input> - static bool match(Input& in, State& st) - { - if (at, Body>>::match(in, st)) - { - if (st.doStack.empty() || st.doStack.top()) - { - return true; - } - } - return false; - } - }; +extern rule AssignableNameList; - struct DisableDo - { - using analyze_t = analysis::generic; +rule for_in = sym('*') >> Exp | ExpList; - template class Action, - template class Control, - typename Input> - static bool match(Input& in, State& st) - { - st.doStack.push(false); - return true; - } - }; +rule ForEach = key("for") >> AssignableNameList >> key("in") >> + DisableDo >> ensure(for_in, PopDo) >> + -key("do") >> Body; - struct PopDo - { - using analyze_t = analysis::generic; +rule Do = user(key("do") >> Body, [](const item_t& item) +{ + State* st = reinterpret_cast(item.user_data); + return st->doStack.empty() || st->doStack.top(); +}); - template class Action, - template class Control, - typename Input> - static bool match(Input& in, State& st) - { - st.doStack.pop(); - return true; - } - }; +rule DisableDo = user(true_(), [](const item_t& item) +{ + State* st = reinterpret_cast(item.user_data); + st->doStack.push(false); + return true; +}); - struct CompInner; - - struct Comprehension : seq, Exp, CompInner, sym<']'>> {}; - struct TblComprehension : seq, seq, Exp>>, CompInner, sym<'}'>> {}; - - struct CompForEach; - struct CompFor; - struct CompClause; - - struct CompInner : seq, star> {}; - struct CompForEach : seq< - key<'f', 'o', 'r'>, - AssignableNameList, - key<'i', 'n'>, - sor< - seq, Exp>, Exp - > - > {}; - struct CompFor : seq, Name, sym<'='>, seq, Exp, opt, Exp>>> {}; - struct CompClause : sor, Exp>> {}; - - struct TableBlock; - - struct Assign : seq, sor> {}; - - struct Update : seq', '>', '='>, - sym<'<', '<', '='> - >, Exp> {}; - - struct CharOperators : seq', '<', '|', '&'>> {}; - struct WordOperators : sor< - opWord<'o', 'r'>, - opWord<'a', 'n', 'd'>, - op<'<', '='>, - op<'>', '='>, - op<'~', '='>, - op<'!', '='>, - op<'=', '='>, - op<'.', '.'>, - op<'<', '<'>, - op<'>', '>'>, - op<'/', '/'>> {}; - struct BinaryOperator : seq, star> {}; - - struct Chain; - - struct Assignable : sor, Name, SelfName> {}; - - struct Value; - - struct Exp : seq> {}; - - struct Callable; - struct InvokeArgs; - - struct ChainValue : seq, opt> {}; - - struct KeyValueList; - struct String; - struct SimpleValue; - - struct Value : sor {}; - struct SliceValue : Exp {}; - - struct LuaString; - - struct single_string_inner : sor, string<'\\', '\\'>, not_one<'\''>> {}; - struct SingleString : seq, star, sym<'\''>> {}; - struct interp : seq, Exp, sym<'}'>> {}; - struct double_string_plain : sor, string<'\\', '\\'>, not_one<'\"'>> {}; - struct double_string_inner : plus, double_string_plain>> {}; - struct DoubleString : seq, star>, sym<'\"'>> {}; - struct String : sor, seq, LuaString> {}; - - struct lua_string_open : seq, star>, one<'['>> {}; - struct lua_string_close : seq, star>, one<']'>> {}; - - struct LuaStringOpen - { - using analyze_t = analysis::generic; +rule PopDo = user(true_(), [](const item_t& item) +{ + State* st = reinterpret_cast(item.user_data); + st->doStack.pop(); + return true; +}); - template class Action, - template class Control, - typename Input> - static bool match(Input& in, State& st) - { - const char* current = in.current(); - if (lua_string_open::match(in, st)) - { - st.stringOpen = in.current() - current + 1; - return true; - } - return false; - } - }; +extern rule CompInner; - struct LuaStringClose - { - using analyze_t = analysis::generic; +rule Comprehension = sym('[') >> Exp >> CompInner >> sym(']'); +rule TblComprehension = sym('{') >> (Exp >> -(sym(',') >> Exp)) >> CompInner >> sym('}'); - template class Action, - template class Control, - typename Input> - static bool match(Input& in, State& st) - { - const char* current = in.current(); - if (lua_string_close::match(in, st)) - { - return st.stringOpen == in.current() - current + 1; - } - return false; - } - }; +extern rule CompForEach, CompFor, CompClause; - struct LuaStringContent : star, any> {}; +rule CompInner = (CompForEach | CompFor) >> *CompClause; +rule CompForEach = key("for") >> AssignableNameList >> key("in") >> (sym('*') >> Exp | Exp); +rule CompFor = key("for") >> Name >> sym('=') >> Exp >> sym(',') >> Exp >> (sym(',') >> Exp | Nothing); +rule CompClause = CompFor | CompForEach | key("when") >> Exp; - struct LuaString - { - using analyze_t = analysis::generic; +extern rule TableBlock; - template class Action, - template class Control, - typename Input> - static bool match(Input& in, State& st) - { - bool result = seq, LuaStringContent, LuaStringClose>::match(in, st); - st.stringOpen = -1; - return result; - } - }; +rule Assign = sym('=') >> (With | If | Switch | TableBlock | ExpListLow); - struct Parens : seq, star, Exp, star, sym<')'>> {}; - struct Callable : sor {}; - - struct FnArgsExpList : seq< - Exp, - star< - sor>, - White, Exp - > - > {}; - - struct FnArgs : sor< - seq, star, opt, star, sym<')'>>, - seq, not_at>> - > {}; - - struct ChainItems; - struct DotChainItem; - struct ColonChain; - - struct Chain : sor< - seq< - sor>>, - ChainItems - >, - seq>, - ColonChain - > - > - > {}; - - struct ChainItem; - - struct ChainItems : sor< - seq, opt>, - ColonChain - > {}; - - struct Invoke; - struct Slice; - - struct ChainItem : sor< - Invoke, - DotChainItem, - Slice, - seq, Exp, sym<']'>> - > {}; - - struct DotChainItem : seq, _Name> {}; - struct ColonChainItem : seq, _Name> {}; - struct ColonChain : seq< - ColonChainItem, - opt> - > {}; - - struct SliceOne : success {}; - struct SliceTwo : success {}; - struct Slice : seq< - symx<'['>, sor, sym<','>, sor, opt, SliceValue>, sym<']'>> {}; - - struct Invoke : sor< - FnArgs, - SingleString, - DoubleString, - seq>, LuaString> - > {}; - - struct KeyValue; - struct TableValueList; - struct TableLitLine; - - struct TableValue : sor {}; - struct TableLit : seq< - sym<'{'>, - seq< - opt, opt>, - opt< - SpaceBreak, TableLitLine, - star>, SpaceBreak, TableLitLine>, - opt> - > - >, - White, sym<'}'> - > {}; - - struct TableValueList : seq, TableValue>> {}; - struct TableLitLine : sor< - seq, seq>>, - Space - > {}; - - struct KeyValueLine; - - struct TableBlockInner : seq, KeyValueLine>> {}; - struct TableBlock : seq, Advance, ensure> {}; - - struct Statement; - - struct ClassLine : seq< - CheckIndent, - seq< - sor, - opt> - > - > {}; - - struct ClassBlock : seq, Advance, ClassLine, star, ClassLine>, PopIndent> {}; - - struct class_no_derive : success {}; - struct class_no_extend : success {}; - struct class_no_body : success {}; - struct ClassDecl : seq< - string<'c', 'l', 'a', 's', 's'>, - not_at>, - sor, - opt, PreventIndent, ensure, class_no_extend>>, - sor - > {}; - - struct Export : seq< - string<'e', 'x', 'p', 'o', 'r', 't'>, - sor< - ClassDecl, - op<'*'>, - op<'^'>, - seq, not_at, Name>, - seq< - sor< - KeyName, - seq, Exp, sym<']'>>, - seq, - seq - >, - symx<':'>, - sor< - Exp, TableBlock, seq, Exp> - > - > - > {}; - - struct KeyValueList : seq, KeyValue>> {}; - struct KeyValueLine : seq>> {}; - - struct FnArgDef : seq, opt, Exp>> {}; - - struct FnArgDefList : sor< - seq< - FnArgDef, - star, Break>, White, FnArgDef>, - star, Break>, White, VarArg> - >, - VarArg - > {}; - - struct outer_value_shadow : seq, sor>>> {}; - struct outer_value_no_shadow : success {}; - struct without_args_def : success {}; - - struct FnArgsDef : sor< - seq, White, opt, - sor< - outer_value_shadow, - outer_value_no_shadow - >, - White, sym<')'> - >, - without_args_def - > {}; - - struct FunLit : seq< - FnArgsDef, - sor< - sym<'-', '>'>, - sym<'=', '>'> - >, - sor - > {}; - - struct NameList : seq, Name>> {}; - struct NameOrDestructure : sor {}; - struct AssignableNameList : seq, NameOrDestructure>> {}; - - struct ExpList : seq, Exp>> {}; - struct ExpListLow : seq, sym<';'>>, Exp>> {}; - - struct ArgLine : seq {}; - struct ArgBlock : seq, SpaceBreak, ArgLine>, PopIndent> {}; - - struct InvokeArgs : seq< - not_at>, - sor< - seq< - ExpList, - opt, - sor< - TableBlock, seq> - > - >, - TableBlock - >> - >, - TableBlock - > - > {}; - - struct SimpleValue : sor< - key<'n', 'i', 'l'>, - key<'t', 'r', 'u', 'e'>, - key<'f', 'a', 'l', 's', 'e'>, - If, Unless, Switch, With, ClassDecl, ForEach, For, While, Do, - seq, not_at, Exp>, - seq, Exp>, - seq, Exp>, - seq, Exp>, - TblComprehension, - TableLit, - Comprehension, - FunLit, - Num - > {}; - - struct Assignment : seq< - ExpList, - sor - > {}; - - struct Statement : seq< - sor< - Import, While, With, For, ForEach, - Switch, Return, Local, Export, BreakLoop, - Assignment, ExpList - >, - Space, - opt< - sor< - seq< - key<'i', 'f'>, Exp, - opt< - key<'e', 'l', 's', 'e'>, Exp - >, - Space - >, - seq, Exp>, - CompInner - >, - Space - > - > {}; - - struct Body : sor< - seq, Break, star, InBlock>, - Statement - > {}; - - struct Line : sor< - seq, - seq> - > {}; - - struct Block : seq, Line>> {}; - - struct BlockWithEnd : seq {}; - - template - struct NodeBase : Node - { - static int id; - }; +rule Update = +( + sym("..=") | + sym("+=") | + sym("-=") | + sym("*=") | + sym("/=") | + sym("%=") | + sym("or=") | + sym("and=") | + sym("&=") | + sym("|=") | + sym(">>=") | + sym("<<=") +) >> Exp; - template - int NodeBase::id = MoonType(); +rule CharOperators = Space >> set("+-*/%^><|&"); +rule WordOperators = + opWord("or") | + opWord("and") | + op("<=") | + op(">=") | + op("~=") | + op("!=") | + op("==") | + op("..") | + op("<<") | + op(">>") | + op("//"); - struct ImportNameNode : Node - { - }; +rule BinaryOperator = (WordOperators | CharOperators) >> *SpaceBreak; - struct ImportNameListNode : NodeBase - { - std::vector> names; - }; +extern rule Chain; - struct ImportNode : NodeBase - { - std::shared_ptr nameList; - std::shared_ptr exp; - }; +rule Assignable = Chain | Name | SelfName; - template - struct action : nothing {}; +extern rule Value; - template<> - struct action - { - template - static void apply(const Input& in, State& st) - { - auto node = std::make_shared(); - node->token = slice::Slice(in.begin(), in.end() - in.begin()); - node->token.trimSpace(); - st.astStack.pop_back(); - st.astStack.back().push_back(node); - } - }; +rule Exp = Value >> *(BinaryOperator >> Value); - template<> - struct action - { - template - static void apply(const Input& in, State& st) - { - auto node = std::make_shared(); - node->token = slice::Slice(in.begin(), in.end() - in.begin()); - node->token.trimSpace(); - st.astStack.pop_back(); - st.astStack.back().push_back(node); - } - }; +extern rule Callable, InvokeArgs; - template<> - struct action - { - template - static void apply(const Input& in, State& st) - { - auto node = std::make_shared(); - node->exp = st.astStack.back().back(); - st.astStack.back().pop_back(); - node->nameList = st.astStack.back().back(); - st.astStack.back().pop_back(); - st.astStack.pop_back(); - st.astStack.back().push_back(node); - } - }; +rule ChainValue = (Chain | Callable) >> (InvokeArgs | Nothing); - template<> - struct action - { - template - static void apply(const Input& in, State& st) - { - auto node = std::make_shared(); - node->names = std::move(st.astStack.back()); - st.astStack.pop_back(); - st.astStack.back().push_back(node); - } - }; +extern rule KeyValueList, String, SimpleValue; - template - struct control : normal {}; +rule Value = SimpleValue | KeyValueList | ChainValue | String; +rule SliceValue = Exp; - template<> - struct control : normal - { - template - static void start(Input& in, State& st) - { - st.astStack.emplace_back(); - } +extern rule LuaString; - template - static void failure(Input& /*unused*/, State& st) - { - st.astStack.pop_back(); - } +rule single_string_inner = expr("\\'") | "\\\\" | not_(expr('\'')) >> Any; +rule SingleString = symx('\'') >> *single_string_inner >> sym('\''); +rule interp = symx("#{") >> Exp >> sym('}'); +rule double_string_plain = expr("\\\"") | "\\\\" | not_(expr('"')) >> Any; +rule double_string_inner = +(not_(interp) >> double_string_plain); +rule DoubleString = symx('"') >> *(double_string_inner | interp) >> sym('"'); +rule String = Space >> (DoubleString | SingleString | LuaString); - template - static void success(Input& /*unused*/, State& st) - { - } - }; -} +rule lua_string_open = '[' >> *expr('=') >> '['; +rule lua_string_close = ']' >> *expr('=') >> ']'; -int main() +rule LuaStringOpen = user(lua_string_open, [](const item_t& item) { - analyze(); - moon::State state; - string_input<> inName(R"xoxox( - -Dorothy! -EditMenuView = require "View.Control.Operation.EditMenu" -MessageBox = require "Control.Basic.MessageBox" - --- [no signals] --- [no params] -Class EditMenuView, - __init:=> - {:width} = CCDirector.winSize - isHide = false - - @itemArea\setupMenuScroll @itemMenu - @itemArea.viewSize = @itemMenu\alignItems! - - for child in *@itemMenu.children - child.positionX = -35 - child.visible = false - child.displayed = false - @showItemButtons {"graphic","physics","logic","data"},true,true - - buttonNames = { - "sprite","model","body" - "effect","layer","world" - } + size_t count = std::distance(item.begin, item.end); + State* st = reinterpret_cast(item.user_data); + st->stringOpen = count; + return true; +}); + +rule LuaStringClose = user(lua_string_close, [](const item_t& item) +{ + size_t count = std::distance(item.begin, item.end); + State* st = reinterpret_cast(item.user_data); + return st->stringOpen == count; +}); + +rule LuaStringContent = *(not_(LuaStringClose) >> Any); - clearSelection = -> - for name in *buttonNames - with @[name.."Btn"] - if .selected - .selected = false - .color = ccColor3 0x00ffff - .scaleX = 0 - .scaleY = 0 - \perform oScale 0.3,1,1,oEase.OutBack - emit .event,nil - - for name in *buttonNames - with @[name.."Btn"] - .selected = false - upperName = name\sub(1,1)\upper!..name\sub(2,-1) - .event = "Scene."..upperName.."Selected" - @gslot .event,(item)-> - if item - .selected = true - .color = ccColor3 0xff0088 - .scaleX = 0 - .scaleY = 0 - \perform oScale 0.3,1,1,oEase.OutBack - \slot "Tapped",-> - if not .selected - emit "Scene.View"..upperName - clearSelection! - else - .selected = false - .color = ccColor3 0x00ffff - emit .event,nil - - @triggerBtn\slot "Tapped",-> - clearSelection! - if @pickPanel.visible - MessageBox text:"Pick An Item First",okOnly:true - else - emit "Scene.Trigger.Open" - - @actionBtn\slot "Tapped",-> - clearSelection! - if @pickPanel.visible - MessageBox text:"Pick An Item First",okOnly:true - else - emit "Scene.Action.Open" - - @aiBtn\slot "Tapped",-> - clearSelection! - if @pickPanel.visible - MessageBox text:"Pick An Item First",okOnly:true - else - emit "Scene.AITree.Open" - - @unitBtn\slot "Tapped",-> - clearSelection! - if @pickPanel.visible - MessageBox text:"Pick An Item First",okOnly:true - else - emit "Scene.Unit.Open" - - @delBtn\slot "Tapped",-> - clearSelection! - emit "Scene.EditMenu.Delete" - - mode = 0 - @zoomBtn\slot "Tapped",-> - scale = switch mode - when 0 then 2 - when 1 then 0.5 - when 2 then 1 - mode += 1 - mode %= 3 - @zoomBtn.text = string.format("%d%%",scale*100) - emit "Scene.ViewArea.ScaleTo",scale - - @originBtn\slot "Tapped",-> editor\moveTo oVec2.zero - - @progressUp.visible = false - @progressDown.visible = false - - with @upBtn - .visible = false - .enabled = false - \slot "TapBegan",-> - clearSelection! - \schedule once -> - sleep 0.4 - @progressUp.visible = true - @progressUp\play! - \slot "Tapped",-> - if @progressUp.visible - if @progressUp.done - emit "Scene.EditMenu.Top" - else - emit "Scene.EditMenu.Up" - \slot "TapEnded",-> - \unschedule! - if @progressUp.visible - @progressUp.visible = false - - with @downBtn - .visible = false - .enabled = false - \slot "TapBegan",-> - clearSelection! - \schedule once -> - sleep 0.4 - @progressDown.visible = true - @progressDown\play! - \slot "Tapped",-> - if @progressDown.visible - if @progressDown.done - emit "Scene.EditMenu.Bottom" - else - emit "Scene.EditMenu.Down" - \slot "TapEnded",-> - \unschedule! - if @progressDown.visible - @progressDown.visible = false - - with @foldBtn - .visible = false - .enabled = false - \slot "Tapped",-> - clearSelection! - emit "Scene.ViewPanel.Fold",editor.currentData - - with @editBtn - .visible = false - .enabled = false - \slot "Tapped",-> - emit "Scene.SettingPanel.Edit",nil - editor\editCurrentItemInPlace! - - with @menuBtn - .dirty = false - \slot "Tapped",-> - clearSelection! - if .dirty - editor\save! - emit "Scene.Dirty",false - else - ScenePanel = require "Control.Item.ScenePanel" - ScenePanel! - emit "Scene.SettingPanel.Edit",nil - - with @undoBtn - .visible = false - \slot "Tapped",-> - clearSelection! - editor.currentSceneFile = editor.currentSceneFile - emit "Scene.Dirty",false - - with @xFixBtn - .visible = false - \slot "Tapped",(button)-> - editor.xFix = not editor.xFix - if editor.yFix - editor.yFix = false - @yFixBtn.color = ccColor3 0x00ffff - button.color = ccColor3 editor.xFix and 0xff0088 or 0x00ffff - emit "Scene.FixChange" - - with @yFixBtn - .visible = false - \slot "Tapped",(button)-> - editor.yFix = not editor.yFix - if editor.xFix - editor.xFix = false - @xFixBtn.color = ccColor3 0x00ffff - button.color = ccColor3 editor.yFix and 0xff0088 or 0x00ffff - emit "Scene.FixChange" - - @iconCam.visible = false - - currentSubCam = nil - with @camBtn - .visible = false - .editing = false - \gslot "Scene.Camera.Select",(subCam)-> - currentSubCam = subCam - \slot "Tapped",-> - .editing = not .editing - if .editing - emit "Scene.Camera.Activate",currentSubCam - else - emit "Scene.Camera.Activate",nil - - with @zoomEditBtn - .visible = false - .editing = false - \slot "Tapped",-> - .editing = not .editing - if .editing and currentSubCam - emit "Scene.Edit.ShowRuler", {currentSubCam.zoom,0.5,10,1,(value)-> - emit "Scene.ViewArea.Scale",value - } - else - emit "Scene.Edit.ShowRuler",nil - - @playBtn\slot "Tapped",-> - settings = editor\getSettings! - sceneFile = if settings.StartupScene - editor.sceneFullPath..settings.StartupScene..".scene" - else - nil - if not sceneFile or not oContent\exist sceneFile - MessageBox text:"Startup Scene\nIs Required!",okOnly:true - return - @menuBtn\emit "Tapped" if @menuBtn.dirty - -- test codes below - Game = require "Lib.Game.Game" - game = Game editor.game,false - editorData = editor\getEditorData! - editorData.lastScene = editor.lastScene - emit "Scene.EditorData",editorData - editor\emit "Quit",game\loadScene! - - setupItemButton = (button,groupLine,subItems)-> - groupLine.data = button - with button - .showItem = false - \slot "Tapped",-> - return if .scheduled - .showItem = not .showItem - if .showItem - groupLine.visible = true - groupLine.opacity = 0 - groupLine\perform oOpacity 0.3,1 - groupLine.position = button.position-oVec2 25,25 - else - \schedule once -> - groupLine\perform oOpacity 0.3,0 - sleep 0.3 - groupLine.visible = false - @showItemButtons subItems,.showItem - setupItemButton @graphicBtn,@graphicLine,{"sprite","model","effect","layer"} - setupItemButton @physicsBtn,@physicsLine,{"body","world"} - setupItemButton @logicBtn,@logicLine,{"trigger","action","ai"} - setupItemButton @dataBtn,@dataLine,{"unit"} - - @gslot "Scene.ShowFix",(value)-> - editor.xFix = false - editor.yFix = false - emit "Scene.FixChange" - if value - with @xFixBtn - .visible = true - .color = ccColor3 0x00ffff - .scaleX = 0 - .scaleY = 0 - \perform oScale 0.5,1,1,oEase.OutBack - with @yFixBtn - .visible = true - .color = ccColor3 0x00ffff - .scaleX = 0 - .scaleY = 0 - \perform oScale 0.5,1,1,oEase.OutBack - else - @xFixBtn.visible = false - @yFixBtn.visible = false - - @gslot "Scene.Dirty",(dirty)-> - with @menuBtn - if .dirty ~= dirty - .dirty = dirty - if dirty - .text = "Save" - with @undoBtn - if not .visible - .enabled = true - .visible = true - .scaleX = 0 - .scaleY = 0 - \perform oScale 0.3,1,1,oEase.OutBack - else - .color = ccColor3 0x00ffff - .text = "Menu" - with @undoBtn - if .visible - .enabled = false - \perform CCSequence { - oScale 0.3,0,0,oEase.InBack - CCHide! - } - - itemChoosed = (itemData)-> - return if isHide - if @camBtn.visible or @iconCam.visible - @iconCam.visible = false - @camBtn.visible = false - emit "Scene.Camera.Activate",nil - emit "Scene.Camera.Select",nil - emit "Scene.ViewPanel.FoldState",{ - itemData:itemData - handler:(state)-> - if state ~= nil - @setButtonVisible @foldBtn,true - switch itemData.typeName - when "Body","Model","Effect" - @setButtonVisible @editBtn,true - else - @setButtonVisible @editBtn,false - text = @foldBtn.text - targetText = state and "Un\nFold" or "Fold" - if text ~= targetText - @foldBtn.text = targetText - if @foldBtn.scale.done - @setButtonVisible @foldBtn,true - else - @setButtonVisible @foldBtn,false - @setButtonVisible @upBtn,false - @setButtonVisible @downBtn,false - @setButtonVisible @editBtn,false - } - return unless itemData - switch itemData.typeName - when "Camera","PlatformWorld","UILayer" - @setButtonVisible @upBtn,false - @setButtonVisible @downBtn,false - {:x,:y} = @upBtn.position - @foldBtn\runAction oPos 0.3,x,y,oEase.OutQuad - if itemData.typeName == "Camera" - clearSelection! - with @iconCam - .visible = true - .scaleX = 0 - .scaleY = 0 - \perform oScale 0.3,0.5,0.5,oEase.OutBack - else - item = editor\getItem itemData - hasChildren = false - if itemData.typeName == "World" - hasChildren = #item.parent.parent.children > 1 - else - hasChildren = #item.parent.children > 1 - if item.parent.children and hasChildren - @setButtonVisible @upBtn,true - @setButtonVisible @downBtn,true - {:x,:y} = @downBtn.position - @foldBtn\runAction oPos 0.3,x,y-60,oEase.OutQuad - @editBtn\runAction oPos 0.3,x,y-120,oEase.OutQuad - else - @setButtonVisible @upBtn,false - @setButtonVisible @downBtn,false - {:x,:y} = @upBtn.position - @foldBtn\runAction oPos 0.3,x,y,oEase.OutQuad - @editBtn\runAction oPos 0.3,x,y-60,oEase.OutQuad - @gslot "Scene.ViewPanel.Pick",itemChoosed - @gslot "Scene.ViewPanel.Select",itemChoosed - - @gslot "Scene.ViewArea.Scale",(scale)-> - mode = 2 if scale ~= 1 - @zoomBtn.text = string.format("%d%%",scale*100) - @gslot "Scene.ViewArea.ScaleReset",-> - mode = 0 - @zoomBtn.text = "100%" - emit "Scene.ViewArea.ScaleTo",1 - - @gslot "Scene.Camera.Select",(subCam)-> - if subCam and not @camBtn.visible - @iconCam.opacity = 0 - with @camBtn - .visible = true - .scaleX = 0 - .scaleY = 0 - \perform oScale 0.3,1,1,oEase.OutBack - else - @camBtn.visible = false - with @iconCam - .opacity = 1 - .scaleX = 0 - .scaleY = 0 - \perform oScale 0.3,0.5,0.5,oEase.OutBack - - changeDisplay = (child)-> - if child.positionX < width/2 - child\perform oPos 0.5,-child.positionX,child.positionY,oEase.OutQuad - else - child\perform oPos 0.5,width*2-child.positionX,child.positionY,oEase.OutQuad - - @gslot "Scene.HideEditor",(args)-> - {hide,all} = args - return if isHide == hide - isHide = hide - @enabled = @camBtn.editing or not hide - for i = 1,#@children - child = @children[i] - switch child - when @camBtn - posX = @camBtn.editing and width-35 or width-345 - child\perform oPos 0.5,posX,child.positionY,oEase.OutQuad - when @menuBtn,@undoBtn,@zoomEditBtn,@iconCam - if all - changeDisplay child - else - continue - else - changeDisplay child - - @gslot "Scene.Camera.Activate",(subCam)-> - editor.isFixed = not @camBtn.editing - if subCam - with @zoomEditBtn - .scaleX = 0 - .scaleY = 0 - .visible = true - \perform CCSequence { - CCDelay 0.5 - oScale 0.3,1,1,oEase.OutBack - } - else - @zoomEditBtn.visible = false - @zoomEditBtn.editing = false - emit "Scene.Edit.ShowRuler",nil - - @gslot "Scene.EditMenu.ClearSelection",clearSelection - - setButtonVisible:(button,visible)=> - return if visible == button.enabled - button.enabled = visible - if visible - if not button.visible - button.visible = true - button.scaleX = 0 - button.scaleY = 0 - button\perform oScale 0.3,1,1,oEase.OutBack - else - button\perform CCSequence { - oScale 0.3,0,0,oEase.InBack - CCHide! - } - - showItemButtons:(names,visible,instant=false)=> - buttonSet = {@["#{name}Btn"],true for name in *names} - posX = 35 - posY = @itemMenu.height-25 - if visible - offset = @itemArea.offset - firstItem = nil - for child in *@itemMenu.children - isTarget = buttonSet[child] - firstItem = child if isTarget and not firstItem - if child.displayed or isTarget - offsetX = switch child - when @graphicBtn,@physicsBtn,@logicBtn,@dataBtn then 0 - else 20 - child.position = offset+oVec2(posX+offsetX,posY) - if isTarget - child.displayed = true - child.visible = true - if not instant - child.face.scaleY = 0 - child.face\perform oScale 0.3,1,1,oEase.OutBack - posY -= 60 - elseif child.data -- data is parentButton - child.position = child.data.position-oVec2(25,25) - @itemArea.viewSize = CCSize 70,@itemArea.height-posY-35 - @itemArea\scrollToPosY firstItem.positionY - else - @itemMenu\schedule once -> - if not instant - for child in *@itemMenu.children - if buttonSet[child] - child.face\perform oScale 0.3,1,0,oEase.OutQuad - sleep 0.3 - offset = @itemArea.offset - lastPosY = nil - for child in *@itemMenu.children - if buttonSet[child] - child.positionX = -35 - child.displayed = false - child.visible = false - lastPosY = child.positionY - elseif child.displayed - if lastPosY and child.positionY < lastPosY - child.face.scaleY = 0 - child.face\perform oScale 0.3,1,1,oEase.OutBack - offsetX = switch child - when @graphicBtn,@physicsBtn,@logicBtn,@dataBtn then 0 - else 20 - child.position = offset+oVec2(posX+offsetX,posY) - posY -= 60 - elseif lastPosY and child.data and child.positionY < lastPosY - child.opacity = 0 - child\perform oOpacity 0.3,1 - child.position = child.data.position-oVec2(25,25) - @itemArea.viewSize = CCSize 70,@itemArea.height-posY-35 - -)xoxox", "abc"); - - string_input<> in(R"PIG(import Path, Struct from require "utils")PIG", "bcd"); - try +rule LuaString = user(LuaStringOpen >> -Break >> LuaStringContent >> LuaStringClose, [](const item_t& item) +{ + State* st = reinterpret_cast(item.user_data); + st->stringOpen = -1; + return true; +}); + +rule Parens = sym('(') >> *SpaceBreak >> Exp >> *SpaceBreak >> sym(')'); +rule Callable = Name | SelfName | VarArg | Parens; +rule FnArgsExpList = Exp >> *((Break | sym(',')) >> White >> Exp); + +rule FnArgs = +( + symx('(') >> *SpaceBreak >> (FnArgsExpList | Nothing) >> *SpaceBreak >> sym(')') +) | ( + sym('!') >> not_(expr('=')) >> Nothing +); + +extern rule ChainItems, DotChainItem, ColonChain; + +rule chain_call = (Callable | String) >> ChainItems; +rule chain_item = not_(set(".\\")) >> ChainItems; +rule chain_dot_chain = DotChainItem >> (ChainItems | Nothing); + +rule Chain = + chain_call | + chain_item | + Space >> (chain_dot_chain | ColonChain); + +extern rule ChainItem; + +rule chain_items = +ChainItem >> (ColonChain | Nothing); +rule ChainItems = chain_items | ColonChain; + +extern rule Invoke, Slice; + +rule ChainItem = Invoke | DotChainItem | Slice | symx('[') >> Exp >> sym(']'); +rule DotChainItem = symx('.') >> _Name; +rule ColonChainItem = symx('\\') >> _Name; +rule ColonChain = ColonChainItem >> ((Invoke >> (ChainItems | Nothing)) | Nothing >> Nothing); + +rule Slice = + symx('[') >> + (SliceValue | Nothing) >> + sym(',') >> + (SliceValue | Nothing) >> + (sym(',') >> + SliceValue | Nothing) >> + sym(']'); + +rule Invoke = + FnArgs | + SingleString | + DoubleString | + and_(expr('[')) >> LuaString; + +extern rule KeyValue, TableValueList, TableLitLine; + +rule TableValue = KeyValue | Exp; + +rule table_lit_lines = SpaceBreak >> TableLitLine >> *(-sym(',') >> SpaceBreak >> TableLitLine) >> -sym(','); + +rule TableLit = + sym('{') >> + (TableValueList | Nothing) >> + -sym(',') >> + (table_lit_lines | Nothing) >> + White >> sym('}'); + +rule TableValueList = TableValue >> *(sym(',') >> TableValue); + +rule TableLitLine = +( + PushIndent >> (TableValueList >> PopIndent | PopIndent) +) | ( + Space >> Nothing +); + +extern rule KeyValueLine; + +rule TableBlockInner = KeyValueLine >> *(+(SpaceBreak) >> KeyValueLine); +rule TableBlock = +(SpaceBreak) >> Advance >> ensure(TableBlockInner, PopIndent); + +extern rule Statement; + +rule ClassLine = CheckIndent >> (KeyValueList | Statement | Exp) >> -sym(','); +rule ClassBlock = +(SpaceBreak) >> Advance >> ClassLine >> *(+(SpaceBreak) >> ClassLine) >> PopIndent; + +rule ClassDecl = + key("class") >> not_(expr(':')) >> + (Assignable | Nothing) >> + (key("extends") >> PreventIndent >> ensure(Exp, PopIndent) | Nothing) >> + (ClassBlock | Nothing); + +rule export_values = sym('=') >> ExpListLow; +rule Export = key("export") >> (ClassDecl | op('*') | op('^') | NameList >> (export_values | Nothing)); + +rule KeyValue = +( + sym(':') >> not_(SomeSpace) >> Name +) | ( + (KeyName | + sym('[') >> Exp >> sym(']') | + Space >> DoubleString | + Space >> SingleString + ) >> + symx(':') >> + (Exp | TableBlock | +(SpaceBreak) >> Exp) +); + +rule KeyValueList = KeyValue >> *(sym(',') >> KeyValue); +rule KeyValueLine = CheckIndent >> KeyValueList >> -sym(','); + +rule FnArgDef = (Name | SelfName) >> (sym('=') >> Exp | Nothing); + +rule FnArgDefList = +( + FnArgDef >> + *((sym(',') | Break) >> White >> FnArgDef) >> + ((sym(',') | Break) >> White >> VarArg | Nothing) +) | ( + VarArg +); + +rule outer_value_shadow = key("using") >> (NameList | Space >> expr("nil")); + +rule normal_fn_args_def = + sym('(') >> White >> (FnArgDefList | Nothing) >> (outer_value_shadow | Nothing) >> White >> sym(')'); + +rule FnArgsDef = normal_fn_args_def | Nothing; +rule fn_arrow = sym("->"); +rule fat_arrow = sym("=>"); +rule FunLit = FnArgsDef >> (fn_arrow | fat_arrow) >> (Body | Nothing); + +rule NameList = Name >> *(sym(',') >> Name); +rule NameOrDestructure = Name | TableLit; +rule AssignableNameList = NameOrDestructure >> *(sym(',') >> NameOrDestructure); + +rule ExpList = Exp >> *(sym(',') >> Exp); +rule ExpListLow = Exp >> *((sym(',') | sym(';')) >> Exp); + +rule ArgLine = CheckIndent >> ExpList; +rule ArgBlock = ArgLine >> *(sym(',') >> SpaceBreak >> ArgLine) >> PopIndent; + +rule invoke_args_with_table = + sym(',') >> + ( + TableBlock >> Nothing | + SpaceBreak>> Advance >> ArgBlock >> (TableBlock | Nothing) + ); + +rule InvokeArgs = + not_(expr('-')) >> + ( + ExpList >> (invoke_args_with_table | TableBlock | Nothing) | + TableBlock >> Nothing + ); + +rule SimpleValue = + key("nil") | key("true") | key("false") | + If | Unless | Switch | With | ClassDecl | ForEach | For | While | Do | + sym('-') >> not_(SomeSpace) >> Exp | + sym('#') >> Exp | + sym('~') >> Exp | + key("not") >> Exp | + TblComprehension | TableLit | Comprehension | FunLit | Num; + +rule Assignment = ExpList >> (Update | Assign); + +rule if_else_line = key("if") >> Exp >> (key("else") >> Exp | Nothing); +rule unless_line = key("unless") >> Exp; + +rule Statement = +( + Import | While | With | For | ForEach | + Switch | Return | Local | Export | BreakLoop | + Assignment | ExpList +) >> Space >> +( + (if_else_line | unless_line | CompInner) >> Space | Nothing +); + +rule Body = -Space >> Break >> *EmptyLine >> InBlock | Statement; + +rule empty_line_stop = Space >> and_(Stop); +rule Line = CheckIndent >> Statement | empty_line_stop; +rule Block = Line >> *(+Break >> Line); +rule BlockWithEnd = Block >> eof(); + +class AstNode : public ast_container +{ +public: + virtual void construct(ast_stack& st) { - if (parse, moon::action, moon::control>(in, state)) + stringstream stream; + for (input::iterator it = m_begin.m_it; it != m_end.m_it; ++it) { - std::cout << "matched.\n"; - } - else - { - std::cout << "not matched.\n"; + stream << (char)*it; } + _value = stream.str(); } - catch (parse_error e) + void print() { - std::cout << "not matched.\n"; - std::cout << e.what() << '\n'; + cout << _value << '\n'; } -/* - analyze(); - const char* text = "1 + 2 + 3 * 4 / 2"; - string_input<> in(text, "abc"); - try +private: + string _value; +}; + +rule ExprEnd = Block >> eof(); + +ast testNode(ExprEnd); + +int main() +{ + string s = R"baddog()baddog"; + input i(s.begin(), s.end()); + + error_list el; + AstNode* root = nullptr; + State st; + if (parse(i, ExprEnd, el, root, &st)) { - hello::Stack stack; - if (parse(in, stack)) - { - std::cout << text << " = " << stack.getValue() << '\n'; - } - return 0; + cout << "matched!\n"; } - catch (parse_error e) + else { - std::cout << e.what() << '\n'; - return 1; + cout << "not matched!\n"; + for (error_list::iterator it = el.begin(); it != el.end(); ++it) + { + const error& err = *it; + cout << "line " << err.m_begin.m_line << ", col " << err.m_begin.m_col << ": syntax error\n"; + } } -*/ + system("pause"); return 0; } -- cgit v1.2.3-55-g6feb