aboutsummaryrefslogtreecommitdiff
path: root/src/MoonP/moon_parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/MoonP/moon_parser.cpp')
-rw-r--r--src/MoonP/moon_parser.cpp972
1 files changed, 510 insertions, 462 deletions
diff --git a/src/MoonP/moon_parser.cpp b/src/MoonP/moon_parser.cpp
index baea9bf..60096af 100644
--- a/src/MoonP/moon_parser.cpp
+++ b/src/MoonP/moon_parser.cpp
@@ -12,7 +12,7 @@ namespace pl = parserlib;
12 12
13namespace MoonP { 13namespace MoonP {
14 14
15std::unordered_set<std::string> State::luaKeywords = { 15std::unordered_set<std::string> LuaKeywords = {
16 "and", "break", "do", "else", "elseif", 16 "and", "break", "do", "else", "elseif",
17 "end", "false", "for", "function", "if", 17 "end", "false", "for", "function", "if",
18 "in", "local", "nil", "not", "or", 18 "in", "local", "nil", "not", "or",
@@ -20,7 +20,7 @@ std::unordered_set<std::string> State::luaKeywords = {
20 "while" 20 "while"
21}; 21};
22 22
23std::unordered_set<std::string> State::keywords = { 23std::unordered_set<std::string> Keywords = {
24 "and", "break", "do", "else", "elseif", 24 "and", "break", "do", "else", "elseif",
25 "end", "false", "for", "function", "if", 25 "end", "false", "for", "function", "if",
26 "in", "local", "nil", "not", "or", 26 "in", "local", "nil", "not", "or",
@@ -31,513 +31,561 @@ std::unordered_set<std::string> State::keywords = {
31 "when", "with" // Moon keywords 31 "when", "with" // Moon keywords
32}; 32};
33 33
34rule plain_space = *set(" \t"); 34MoonParser::MoonParser() {
35rule Break = nl(-expr('\r') >> '\n'); 35 plain_space = *set(" \t");
36rule Any = Break | any(); 36 Break = nl(-expr('\r') >> '\n');
37rule White = *(set(" \t") | Break); 37 Any = Break | any();
38rule Stop = Break | eof(); 38 White = *(set(" \t") | Break);
39rule Comment = "--" >> *(not_(set("\r\n")) >> Any) >> and_(Stop); 39 Stop = Break | eof();
40rule multi_line_open = expr("--[["); 40 Comment = "--" >> *(not_(set("\r\n")) >> Any) >> and_(Stop);
41rule multi_line_close = expr("]]"); 41 multi_line_open = expr("--[[");
42rule multi_line_content = *(not_(multi_line_close) >> Any); 42 multi_line_close = expr("]]");
43rule MultiLineComment = multi_line_open >> multi_line_content >> multi_line_close; 43 multi_line_content = *(not_(multi_line_close) >> Any);
44rule Indent = plain_space; 44 MultiLineComment = multi_line_open >> multi_line_content >> multi_line_close;
45rule EscapeNewLine = expr('\\') >> plain_space >> -Comment >> Break; 45 Indent = plain_space;
46rule Space = *(set(" \t") | MultiLineComment | EscapeNewLine) >> -Comment; 46 EscapeNewLine = expr('\\') >> plain_space >> -Comment >> Break;
47rule SomeSpace = +set(" \t") >> -Comment; 47 Space = *(set(" \t") | MultiLineComment | EscapeNewLine) >> -Comment;
48rule SpaceBreak = Space >> Break; 48 SomeSpace = +set(" \t") >> -Comment;
49rule EmptyLine = SpaceBreak; 49 SpaceBreak = Space >> Break;
50rule AlphaNum = range('a', 'z') | range('A', 'Z') | range('0', '9') | '_'; 50 EmptyLine = SpaceBreak;
51rule Name = (range('a', 'z') | range('A', 'Z') | '_') >> *AlphaNum; 51 AlphaNum = range('a', 'z') | range('A', 'Z') | range('0', '9') | '_';
52rule Num = 52 Name = (range('a', 'z') | range('A', 'Z') | '_') >> *AlphaNum;
53( 53 Num =
54 "0x" >>
55 +(range('0', '9') | range('a', 'f') | range('A', 'F')) >>
56 -(-set("uU") >> set("lL") >> set("lL"))
57) | (
58 +range('0', '9') >> -set("uU") >> set("lL") >> set("lL")
59) | (
60 ( 54 (
61 (+range('0', '9') >> -('.' >> +range('0', '9'))) | 55 "0x" >>
62 ('.' >> +range('0', '9')) 56 +(range('0', '9') | range('a', 'f') | range('A', 'F')) >>
63 ) >> -(set("eE") >> -expr('-') >> +range('0', '9')) 57 -(-set("uU") >> set("lL") >> set("lL"))
64); 58 ) | (
65rule Cut = false_(); 59 +range('0', '9') >> -set("uU") >> set("lL") >> set("lL")
66rule Seperator = true_(); 60 ) | (
67 61 (
68#define sym(str) (Space >> str) 62 (+range('0', '9') >> -('.' >> +range('0', '9'))) |
69#define symx(str) expr(str) 63 ('.' >> +range('0', '9'))
70#define ensure(patt, finally) (((patt) >> (finally)) | ((finally) >> (Cut))) 64 ) >> -(set("eE") >> -expr('-') >> +range('0', '9'))
71#define key(str) (Space >> str >> not_(AlphaNum)) 65 );
72 66 Cut = false_();
73rule Variable = pl::user(Name, [](const item_t& item) { 67 Seperator = true_();
74 State* st = reinterpret_cast<State*>(item.user_data); 68
75 for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it); 69 #define sym(str) (Space >> str)
76 auto it = State::keywords.find(st->buffer); 70 #define symx(str) expr(str)
77 st->buffer.clear(); 71 #define ensure(patt, finally) (((patt) >> (finally)) | ((finally) >> (Cut)))
78 return it == State::keywords.end(); 72 #define key(str) (Space >> str >> not_(AlphaNum))
79}); 73
80 74 Variable = pl::user(Name, [](const item_t& item) {
81rule LuaKeyword = pl::user(Name, [](const item_t& item) { 75 State* st = reinterpret_cast<State*>(item.user_data);
82 State* st = reinterpret_cast<State*>(item.user_data); 76 for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it);
83 for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it); 77 auto it = Keywords.find(st->buffer);
84 auto it = State::luaKeywords.find(st->buffer); 78 st->buffer.clear();
85 st->buffer.clear(); 79 return it == Keywords.end();
86 return it != State::luaKeywords.end(); 80 });
87}); 81
88 82 LuaKeyword = pl::user(Name, [](const item_t& item) {
89rule self = expr('@'); 83 State* st = reinterpret_cast<State*>(item.user_data);
90rule self_name = '@' >> Name; 84 for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it);
91rule self_class = expr("@@"); 85 auto it = LuaKeywords.find(st->buffer);
92rule self_class_name = "@@" >> Name; 86 st->buffer.clear();
93 87 return it != LuaKeywords.end();
94rule SelfName = Space >> (self_class_name | self_class | self_name | self); 88 });
95rule KeyName = SelfName | Space >> Name; 89
96rule VarArg = Space >> "..."; 90 self = expr('@');
97 91 self_name = '@' >> Name;
98rule check_indent = pl::user(Indent, [](const item_t& item) { 92 self_class = expr("@@");
99 int indent = 0; 93 self_class_name = "@@" >> Name;
100 for (input_it i = item.begin; i != item.end; ++i) { 94
101 switch (*i) { 95 SelfName = Space >> (self_class_name | self_class | self_name | self);
102 case ' ': indent++; break; 96 KeyName = SelfName | Space >> Name;
103 case '\t': indent += 4; break; 97 VarArg = Space >> "...";
98
99 check_indent = pl::user(Indent, [](const item_t& item) {
100 int indent = 0;
101 for (input_it i = item.begin; i != item.end; ++i) {
102 switch (*i) {
103 case ' ': indent++; break;
104 case '\t': indent += 4; break;
105 }
104 } 106 }
105 } 107 State* st = reinterpret_cast<State*>(item.user_data);
106 State* st = reinterpret_cast<State*>(item.user_data); 108 return st->indents.top() == indent;
107 return st->indents.top() == indent; 109 });
108}); 110 CheckIndent = and_(check_indent);
109rule CheckIndent = and_(check_indent); 111
110 112 advance = pl::user(Indent, [](const item_t& item) {
111rule advance = pl::user(Indent, [](const item_t& item) { 113 int indent = 0;
112 int indent = 0; 114 for (input_it i = item.begin; i != item.end; ++i) {
113 for (input_it i = item.begin; i != item.end; ++i) { 115 switch (*i) {
114 switch (*i) { 116 case ' ': indent++; break;
115 case ' ': indent++; break; 117 case '\t': indent += 4; break;
116 case '\t': indent += 4; break; 118 }
117 } 119 }
118 } 120 State* st = reinterpret_cast<State*>(item.user_data);
119 State* st = reinterpret_cast<State*>(item.user_data); 121 int top = st->indents.top();
120 int top = st->indents.top(); 122 if (top != -1 && indent > top) {
121 if (top != -1 && indent > top) { 123 st->indents.push(indent);
124 return true;
125 }
126 return false;
127 });
128 Advance = and_(advance);
129
130 push_indent = pl::user(Indent, [](const item_t& item) {
131 int indent = 0;
132 for (input_it i = item.begin; i != item.end; ++i) {
133 switch (*i) {
134 case ' ': indent++; break;
135 case '\t': indent += 4; break;
136 }
137 }
138 State* st = reinterpret_cast<State*>(item.user_data);
122 st->indents.push(indent); 139 st->indents.push(indent);
123 return true; 140 return true;
124 } 141 });
125 return false; 142 PushIndent = and_(push_indent);
126});
127rule Advance = and_(advance);
128
129rule push_indent = pl::user(Indent, [](const item_t& item) {
130 int indent = 0;
131 for (input_it i = item.begin; i != item.end; ++i) {
132 switch (*i) {
133 case ' ': indent++; break;
134 case '\t': indent += 4; break;
135 }
136 }
137 State* st = reinterpret_cast<State*>(item.user_data);
138 st->indents.push(indent);
139 return true;
140});
141rule PushIndent = and_(push_indent);
142
143rule PreventIndent = pl::user(true_(), [](const item_t& item) {
144 State* st = reinterpret_cast<State*>(item.user_data);
145 st->indents.push(-1);
146 return true;
147});
148
149rule PopIndent = pl::user(true_(), [](const item_t& item) {
150 State* st = reinterpret_cast<State*>(item.user_data);
151 st->indents.pop();
152 return true;
153});
154
155extern rule Block;
156
157rule InBlock = Advance >> Block >> PopIndent;
158
159extern rule NameList;
160
161rule local_flag = expr('*') | expr('^');
162rule Local = key("local") >> ((Space >> local_flag) | NameList);
163
164rule colon_import_name = sym('\\') >> Space >> Variable;
165rule ImportName = colon_import_name | Space >> Variable;
166rule ImportNameList = Seperator >> *SpaceBreak >> ImportName >> *((+SpaceBreak | sym(',') >> *SpaceBreak) >> ImportName);
167
168extern rule Exp, TableLit;
169
170rule import_literal_inner = (range('a', 'z') | range('A', 'Z') | set("_-")) >> *(AlphaNum | '-');
171rule import_literal_chain = Seperator >> import_literal_inner >> *(expr('.') >> import_literal_inner);
172rule ImportLiteral = sym('\'') >> import_literal_chain >> symx('\'') | sym('"') >> import_literal_chain >> symx('"');
173
174rule ImportFrom = ImportNameList >> *SpaceBreak >> key("from") >> Exp;
175rule ImportAs = ImportLiteral >> -(key("as") >> (Space >> Variable | TableLit));
176
177rule Import = key("import") >> (ImportAs | ImportFrom);
178rule BreakLoop = (expr("break") | expr("continue")) >> not_(AlphaNum);
179
180extern rule ExpListLow, ExpList, Assign;
181
182rule Return = key("return") >> -ExpListLow;
183rule WithExp = ExpList >> -Assign;
184
185extern rule DisableDo, PopDo, Body;
186
187rule With = key("with") >> DisableDo >> ensure(WithExp, PopDo) >> -key("do") >> Body;
188rule SwitchCase = key("when") >> ExpList >> -key("then") >> Body;
189rule SwitchElse = key("else") >> Body;
190
191rule SwitchBlock = *EmptyLine >>
192 Advance >> Seperator >>
193 SwitchCase >>
194 *(+SpaceBreak >> SwitchCase) >>
195 -(+SpaceBreak >> SwitchElse) >>
196 PopIndent;
197
198rule Switch = key("switch") >>
199 DisableDo >> ensure(Exp, PopDo) >>
200 -key("do") >> -Space >> Break >> SwitchBlock;
201
202rule IfCond = Exp >> -Assign;
203rule IfElseIf = -(Break >> *EmptyLine >> CheckIndent) >> key("elseif") >> IfCond >> -key("then") >> Body;
204rule IfElse = -(Break >> *EmptyLine >> CheckIndent) >> key("else") >> Body;
205rule If = key("if") >> Seperator >> IfCond >> -key("then") >> Body >> *IfElseIf >> -IfElse;
206rule Unless = key("unless") >> Seperator >> IfCond >> -key("then") >> Body >> *IfElseIf >> -IfElse;
207
208rule While = key("while") >> DisableDo >> ensure(Exp, PopDo) >> -key("do") >> Body;
209
210rule for_step_value = sym(',') >> Exp;
211rule for_args = Space >> Variable >> sym('=') >> Exp >> sym(',') >> Exp >> -for_step_value;
212
213rule For = key("for") >> DisableDo >>
214 ensure(for_args, PopDo) >>
215 -key("do") >> Body;
216
217extern rule AssignableNameList;
218 143
219extern rule star_exp; 144 PreventIndent = pl::user(true_(), [](const item_t& item) {
220 145 State* st = reinterpret_cast<State*>(item.user_data);
221rule for_in = star_exp | ExpList; 146 st->indents.push(-1);
222 147 return true;
223rule ForEach = key("for") >> AssignableNameList >> key("in") >> 148 });
224 DisableDo >> ensure(for_in, PopDo) >>
225 -key("do") >> Body;
226
227rule Do = pl::user(key("do") >> Body, [](const item_t& item)
228{
229 State* st = reinterpret_cast<State*>(item.user_data);
230 return st->doStack.empty() || st->doStack.top();
231});
232
233rule DisableDo = pl::user(true_(), [](const item_t& item)
234{
235 State* st = reinterpret_cast<State*>(item.user_data);
236 st->doStack.push(false);
237 return true;
238});
239 149
240rule PopDo = pl::user(true_(), [](const item_t& item) 150 PopIndent = pl::user(true_(), [](const item_t& item) {
241{ 151 State* st = reinterpret_cast<State*>(item.user_data);
242 State* st = reinterpret_cast<State*>(item.user_data); 152 st->indents.pop();
243 st->doStack.pop(); 153 return true;
244 return true; 154 });
245});
246 155
247extern rule CompInner; 156 InBlock = Advance >> Block >> PopIndent;
248 157
249rule Comprehension = sym('[') >> Exp >> CompInner >> sym(']'); 158 local_flag = expr('*') | expr('^');
250rule comp_value = sym(',') >> Exp; 159 Local = key("local") >> ((Space >> local_flag) | NameList);
251rule TblComprehension = sym('{') >> (Exp >> -comp_value) >> CompInner >> sym('}');
252 160
253extern rule CompForEach, CompFor, CompClause; 161 colon_import_name = sym('\\') >> Space >> Variable;
162 ImportName = colon_import_name | Space >> Variable;
163 ImportNameList = Seperator >> *SpaceBreak >> ImportName >> *((+SpaceBreak | sym(',') >> *SpaceBreak) >> ImportName);
254 164
255rule CompInner = Seperator >> (CompForEach | CompFor) >> *CompClause; 165 import_literal_inner = (range('a', 'z') | range('A', 'Z') | set("_-")) >> *(AlphaNum | '-');
256rule star_exp = sym('*') >> Exp; 166 import_literal_chain = Seperator >> import_literal_inner >> *(expr('.') >> import_literal_inner);
257rule CompForEach = key("for") >> AssignableNameList >> key("in") >> (star_exp | Exp); 167 ImportLiteral = sym('\'') >> import_literal_chain >> symx('\'') | sym('"') >> import_literal_chain >> symx('"');
258rule CompFor = key("for") >> Space >> Variable >> sym('=') >> Exp >> sym(',') >> Exp >> -for_step_value;
259rule CompClause = CompFor | CompForEach | key("when") >> Exp;
260 168
261extern rule TableBlock; 169 ImportFrom = ImportNameList >> *SpaceBreak >> key("from") >> Exp;
170 ImportAs = ImportLiteral >> -(key("as") >> (Space >> Variable | TableLit));
262 171
263rule Assign = sym('=') >> Seperator >> (With | If | Switch | TableBlock | Exp >> *((sym(',') | sym(';')) >> Exp)); 172 Import = key("import") >> (ImportAs | ImportFrom);
173 BreakLoop = (expr("break") | expr("continue")) >> not_(AlphaNum);
264 174
265rule update_op = 175 Return = key("return") >> -ExpListLow;
266 expr("..") | 176 WithExp = ExpList >> -Assign;
267 expr("+") |
268 expr("-") |
269 expr("*") |
270 expr("/") |
271 expr("%") |
272 expr("or") |
273 expr("and") |
274 expr("&") |
275 expr("|") |
276 expr(">>") |
277 expr("<<");
278 177
279rule Update = Space >> update_op >> expr("=") >> Exp; 178 With = key("with") >> DisableDo >> ensure(WithExp, PopDo) >> -key("do") >> Body;
179 SwitchCase = key("when") >> ExpList >> -key("then") >> Body;
180 SwitchElse = key("else") >> Body;
280 181
281rule BinaryOperator = 182 SwitchBlock = *EmptyLine >>
282 (expr("or") >> not_(AlphaNum)) | 183 Advance >> Seperator >>
283 (expr("and") >> not_(AlphaNum)) | 184 SwitchCase >>
284 expr("<=") | 185 *(+SpaceBreak >> SwitchCase) >>
285 expr(">=") | 186 -(+SpaceBreak >> SwitchElse) >>
286 expr("~=") | 187 PopIndent;
287 expr("!=") |
288 expr("==") |
289 expr("..") |
290 expr("<<") |
291 expr(">>") |
292 expr("//") |
293 set("+-*/%^><|&");
294
295rule BackcallOperator = expr("|>");
296
297extern rule AssignableChain;
298
299rule Assignable = AssignableChain | Space >> Variable | SelfName;
300
301extern rule Value;
302
303rule exp_op_value = Space >> (BackcallOperator | BinaryOperator) >> *SpaceBreak >> Value;
304rule Exp = Value >> *exp_op_value;
305 188
306extern rule Chain, Callable, InvokeArgs, existential_op; 189 Switch = key("switch") >>
190 DisableDo >> ensure(Exp, PopDo) >>
191 -key("do") >> -Space >> Break >> SwitchBlock;
307 192
308rule ChainValue = Seperator >> (Chain | Callable) >> -existential_op >> -InvokeArgs; 193 IfCond = Exp >> -Assign;
194 IfElseIf = -(Break >> *EmptyLine >> CheckIndent) >> key("elseif") >> IfCond >> -key("then") >> Body;
195 IfElse = -(Break >> *EmptyLine >> CheckIndent) >> key("else") >> Body;
196 If = key("if") >> Seperator >> IfCond >> -key("then") >> Body >> *IfElseIf >> -IfElse;
197 Unless = key("unless") >> Seperator >> IfCond >> -key("then") >> Body >> *IfElseIf >> -IfElse;
309 198
310extern rule KeyValue, String, SimpleValue; 199 While = key("while") >> DisableDo >> ensure(Exp, PopDo) >> -key("do") >> Body;
311
312rule simple_table = Seperator >> KeyValue >> *(sym(',') >> KeyValue);
313rule Value = SimpleValue | simple_table | ChainValue | String;
314
315extern rule LuaString;
316 200
317rule single_string_inner = expr("\\'") | "\\\\" | not_(expr('\'')) >> Any; 201 for_step_value = sym(',') >> Exp;
318rule SingleString = symx('\'') >> *single_string_inner >> symx('\''); 202 for_args = Space >> Variable >> sym('=') >> Exp >> sym(',') >> Exp >> -for_step_value;
319rule interp = symx("#{") >> Exp >> sym('}');
320rule double_string_plain = expr("\\\"") | "\\\\" | not_(expr('"')) >> Any;
321rule double_string_inner = +(not_(interp) >> double_string_plain);
322rule double_string_content = double_string_inner | interp;
323rule DoubleString = symx('"') >> Seperator >> *double_string_content >> symx('"');
324rule String = Space >> (DoubleString | SingleString | LuaString);
325
326rule lua_string_open = '[' >> *expr('=') >> '[';
327rule lua_string_close = ']' >> *expr('=') >> ']';
328
329rule LuaStringOpen = pl::user(lua_string_open, [](const item_t& item)
330{
331 size_t count = std::distance(item.begin, item.end);
332 State* st = reinterpret_cast<State*>(item.user_data);
333 st->stringOpen = count;
334 return true;
335});
336
337rule LuaStringClose = pl::user(lua_string_close, [](const item_t& item)
338{
339 size_t count = std::distance(item.begin, item.end);
340 State* st = reinterpret_cast<State*>(item.user_data);
341 return st->stringOpen == count;
342});
343 203
344rule LuaStringContent = *(not_(LuaStringClose) >> Any); 204 For = key("for") >> DisableDo >>
205 ensure(for_args, PopDo) >>
206 -key("do") >> Body;
345 207
346rule LuaString = pl::user(LuaStringOpen >> -Break >> LuaStringContent >> LuaStringClose, [](const item_t& item) 208 for_in = star_exp | ExpList;
347{
348 State* st = reinterpret_cast<State*>(item.user_data);
349 st->stringOpen = -1;
350 return true;
351});
352
353rule Parens = sym('(') >> *SpaceBreak >> Exp >> *SpaceBreak >> sym(')');
354rule Callable = Space >> Variable | SelfName | VarArg | Parens;
355rule FnArgsExpList = Exp >> *((Break | sym(',')) >> White >> Exp);
356
357rule FnArgs = (symx('(') >> *SpaceBreak >> -FnArgsExpList >> *SpaceBreak >> sym(')')) |
358 (sym('!') >> not_(expr('=')));
359
360extern rule ChainItems, DotChainItem, ColonChain;
361
362rule existential_op = expr('?');
363rule chain_call = (Callable | String) >> -existential_op >> ChainItems;
364rule chain_item = and_(set(".\\")) >> ChainItems;
365rule chain_dot_chain = DotChainItem >> -existential_op >> -ChainItems;
366
367rule Chain = chain_call | chain_item |
368 Space >> (chain_dot_chain | ColonChain);
369
370rule AssignableChain = Seperator >> Chain;
371 209
372extern rule ChainItem; 210 ForEach = key("for") >> AssignableNameList >> key("in") >>
211 DisableDo >> ensure(for_in, PopDo) >>
212 -key("do") >> Body;
373 213
374rule chain_with_colon = +ChainItem >> -ColonChain; 214 Do = pl::user(key("do") >> Body, [](const item_t& item)
375rule ChainItems = chain_with_colon | ColonChain; 215 {
216 State* st = reinterpret_cast<State*>(item.user_data);
217 return st->doStack.empty() || st->doStack.top();
218 });
376 219
377extern rule Invoke, Slice; 220 DisableDo = pl::user(true_(), [](const item_t& item)
221 {
222 State* st = reinterpret_cast<State*>(item.user_data);
223 st->doStack.push(false);
224 return true;
225 });
378 226
379rule Index = symx('[') >> Exp >> sym(']'); 227 PopDo = pl::user(true_(), [](const item_t& item)
380rule ChainItem = Invoke >> -existential_op | DotChainItem >> -existential_op | Slice | Index >> -existential_op; 228 {
381rule DotChainItem = symx('.') >> Name; 229 State* st = reinterpret_cast<State*>(item.user_data);
382rule ColonChainItem = symx('\\') >> (LuaKeyword | Name); 230 st->doStack.pop();
383rule invoke_chain = Invoke >> -existential_op >> -ChainItems; 231 return true;
384rule ColonChain = ColonChainItem >> -existential_op >> -invoke_chain; 232 });
233
234 Comprehension = sym('[') >> Exp >> CompInner >> sym(']');
235 comp_value = sym(',') >> Exp;
236 TblComprehension = sym('{') >> (Exp >> -comp_value) >> CompInner >> sym('}');
237
238 CompInner = Seperator >> (CompForEach | CompFor) >> *CompClause;
239 star_exp = sym('*') >> Exp;
240 CompForEach = key("for") >> AssignableNameList >> key("in") >> (star_exp | Exp);
241 CompFor = key("for") >> Space >> Variable >> sym('=') >> Exp >> sym(',') >> Exp >> -for_step_value;
242 CompClause = CompFor | CompForEach | key("when") >> Exp;
243
244 Assign = sym('=') >> Seperator >> (With | If | Switch | TableBlock | Exp >> *((sym(',') | sym(';')) >> Exp));
245
246 update_op =
247 expr("..") |
248 expr("+") |
249 expr("-") |
250 expr("*") |
251 expr("/") |
252 expr("%") |
253 expr("or") |
254 expr("and") |
255 expr("&") |
256 expr("|") |
257 expr(">>") |
258 expr("<<");
259
260 Update = Space >> update_op >> expr("=") >> Exp;
261
262 BinaryOperator =
263 (expr("or") >> not_(AlphaNum)) |
264 (expr("and") >> not_(AlphaNum)) |
265 expr("<=") |
266 expr(">=") |
267 expr("~=") |
268 expr("!=") |
269 expr("==") |
270 expr("..") |
271 expr("<<") |
272 expr(">>") |
273 expr("//") |
274 set("+-*/%^><|&");
275
276 BackcallOperator = expr("|>");
277
278 Assignable = AssignableChain | Space >> Variable | SelfName;
279
280 exp_op_value = Space >> (BackcallOperator | BinaryOperator) >> *SpaceBreak >> Value;
281 Exp = Value >> *exp_op_value;
282
283 ChainValue = Seperator >> (Chain | Callable) >> -existential_op >> -InvokeArgs;
284
285 simple_table = Seperator >> KeyValue >> *(sym(',') >> KeyValue);
286 Value = SimpleValue | simple_table | ChainValue | String;
287
288 single_string_inner = expr("\\'") | "\\\\" | not_(expr('\'')) >> Any;
289 SingleString = symx('\'') >> *single_string_inner >> symx('\'');
290 interp = symx("#{") >> Exp >> sym('}');
291 double_string_plain = expr("\\\"") | "\\\\" | not_(expr('"')) >> Any;
292 double_string_inner = +(not_(interp) >> double_string_plain);
293 double_string_content = double_string_inner | interp;
294 DoubleString = symx('"') >> Seperator >> *double_string_content >> symx('"');
295 String = Space >> (DoubleString | SingleString | LuaString);
296
297 lua_string_open = '[' >> *expr('=') >> '[';
298 lua_string_close = ']' >> *expr('=') >> ']';
299
300 LuaStringOpen = pl::user(lua_string_open, [](const item_t& item) {
301 size_t count = std::distance(item.begin, item.end);
302 State* st = reinterpret_cast<State*>(item.user_data);
303 st->stringOpen = count;
304 return true;
305 });
385 306
386rule default_value = true_(); 307 LuaStringClose = pl::user(lua_string_close, [](const item_t& item) {
387rule Slice = 308 size_t count = std::distance(item.begin, item.end);
388 symx('[') >> 309 State* st = reinterpret_cast<State*>(item.user_data);
389 (Exp | default_value) >> 310 return st->stringOpen == count;
390 sym(',') >> 311 });
391 (Exp | default_value) >>
392 (sym(',') >> Exp | default_value) >>
393 sym(']');
394 312
395rule Invoke = Seperator >> ( 313 LuaStringContent = *(not_(LuaStringClose) >> Any);
396 FnArgs |
397 SingleString |
398 DoubleString |
399 and_(expr('[')) >> LuaString);
400 314
401extern rule TableValueList, TableLitLine; 315 LuaString = pl::user(LuaStringOpen >> -Break >> LuaStringContent >> LuaStringClose, [](const item_t& item) {
316 State* st = reinterpret_cast<State*>(item.user_data);
317 st->stringOpen = -1;
318 return true;
319 });
402 320
403rule TableValue = KeyValue | Exp; 321 Parens = sym('(') >> *SpaceBreak >> Exp >> *SpaceBreak >> sym(')');
322 Callable = Space >> Variable | SelfName | VarArg | Parens;
323 FnArgsExpList = Exp >> *((Break | sym(',')) >> White >> Exp);
404 324
405rule table_lit_lines = SpaceBreak >> TableLitLine >> *(-sym(',') >> SpaceBreak >> TableLitLine) >> -sym(','); 325 FnArgs = (symx('(') >> *SpaceBreak >> -FnArgsExpList >> *SpaceBreak >> sym(')')) |
326 (sym('!') >> not_(expr('=')));
406 327
407rule TableLit = 328 existential_op = expr('?');
408 sym('{') >> Seperator >> 329 chain_call = (Callable | String) >> -existential_op >> ChainItems;
409 -TableValueList >> 330 chain_item = and_(set(".\\")) >> ChainItems;
410 -sym(',') >> 331 chain_dot_chain = DotChainItem >> -existential_op >> -ChainItems;
411 -table_lit_lines >>
412 White >> sym('}');
413
414rule TableValueList = TableValue >> *(sym(',') >> TableValue);
415
416rule TableLitLine =
417(
418 PushIndent >> (TableValueList >> PopIndent | PopIndent)
419) | (
420 Space
421);
422 332
423extern rule KeyValueLine; 333 Chain = chain_call | chain_item |
334 Space >> (chain_dot_chain | ColonChain);
424 335
425rule TableBlockInner = Seperator >> KeyValueLine >> *(+(SpaceBreak) >> KeyValueLine); 336 AssignableChain = Seperator >> Chain;
426rule TableBlock = +(SpaceBreak) >> Advance >> ensure(TableBlockInner, PopIndent);
427 337
428extern rule Statement; 338 chain_with_colon = +ChainItem >> -ColonChain;
429 339 ChainItems = chain_with_colon | ColonChain;
430rule class_member_list = Seperator >> KeyValue >> *(sym(',') >> KeyValue);
431rule ClassLine = CheckIndent >> (class_member_list | Statement) >> -sym(',');
432rule ClassBlock = +(SpaceBreak) >> Advance >>Seperator >> ClassLine >> *(+(SpaceBreak) >> ClassLine) >> PopIndent;
433 340
434rule ClassDecl = 341 Index = symx('[') >> Exp >> sym(']');
435 key("class") >> not_(expr(':')) >> 342 ChainItem = Invoke >> -existential_op | DotChainItem >> -existential_op | Slice | Index >> -existential_op;
436 -Assignable >> 343 DotChainItem = symx('.') >> Name;
437 -(key("extends") >> PreventIndent >> ensure(Exp, PopIndent)) >> 344 ColonChainItem = symx('\\') >> (LuaKeyword | Name);
438 -ClassBlock; 345 invoke_chain = Invoke >> -existential_op >> -ChainItems;
346 ColonChain = ColonChainItem >> -existential_op >> -invoke_chain;
439 347
440rule export_values = NameList >> -(sym('=') >> ExpListLow); 348 default_value = true_();
441rule export_op = expr('*') | expr('^'); 349 Slice =
442rule Export = key("export") >> (ClassDecl | (Space >> export_op) | export_values); 350 symx('[') >>
351 (Exp | default_value) >>
352 sym(',') >>
353 (Exp | default_value) >>
354 (sym(',') >> Exp | default_value) >>
355 sym(']');
443 356
444rule variable_pair = sym(':') >> not_(SomeSpace) >> Space >> Variable; 357 Invoke = Seperator >> (
358 FnArgs |
359 SingleString |
360 DoubleString |
361 and_(expr('[')) >> LuaString);
445 362
446rule normal_pair = 363 TableValue = KeyValue | Exp;
447(
448 KeyName |
449 sym('[') >> Exp >> sym(']') |
450 Space >> DoubleString |
451 Space >> SingleString
452) >>
453symx(':') >>
454(Exp | TableBlock | +(SpaceBreak) >> Exp);
455 364
456rule KeyValue = variable_pair | normal_pair; 365 table_lit_lines = SpaceBreak >> TableLitLine >> *(-sym(',') >> SpaceBreak >> TableLitLine) >> -sym(',');
457 366
458rule KeyValueList = KeyValue >> *(sym(',') >> KeyValue); 367 TableLit =
459rule KeyValueLine = CheckIndent >> KeyValueList >> -sym(','); 368 sym('{') >> Seperator >>
369 -TableValueList >>
370 -sym(',') >>
371 -table_lit_lines >>
372 White >> sym('}');
460 373
461rule FnArgDef = (Space >> Variable | SelfName) >> -(sym('=') >> Exp); 374 TableValueList = TableValue >> *(sym(',') >> TableValue);
462 375
463rule FnArgDefList = Seperator >> 376 TableLitLine = (
464( 377 PushIndent >> (TableValueList >> PopIndent | PopIndent)
465 (
466 FnArgDef >>
467 *((sym(',') | Break) >> White >> FnArgDef) >>
468 -((sym(',') | Break) >> White >> VarArg)
469 ) | ( 378 ) | (
470 VarArg 379 Space
471 )
472);
473
474rule outer_var_shadow = key("using") >> (NameList | Space >> expr("nil"));
475
476rule FnArgsDef = sym('(') >> White >> -FnArgDefList >> -outer_var_shadow >> White >> sym(')');
477rule fn_arrow = expr("->") | expr("=>");
478rule FunLit = -FnArgsDef >> Space >> fn_arrow >> -Body;
479
480rule NameList = Seperator >> Space >> Variable >> *(sym(',') >> Space >> Variable);
481rule NameOrDestructure = Space >> Variable | TableLit;
482rule AssignableNameList = Seperator >> NameOrDestructure >> *(sym(',') >> NameOrDestructure);
483
484rule Backcall = -FnArgsDef >> Space >> symx("<-") >> Space >> ChainValue;
485
486rule ExpList = Seperator >> Exp >> *(sym(',') >> Exp);
487rule ExpListLow = Seperator >> Exp >> *((sym(',') | sym(';')) >> Exp);
488
489rule ArgLine = CheckIndent >> Exp >> *(sym(',') >> Exp);
490rule ArgBlock = ArgLine >> *(sym(',') >> SpaceBreak >> ArgLine) >> PopIndent;
491
492rule invoke_args_with_table =
493 sym(',') >>
494 (
495 TableBlock |
496 SpaceBreak >> Advance >> ArgBlock >> -TableBlock
497 ); 380 );
498 381
499rule InvokeArgs = 382 TableBlockInner = Seperator >> KeyValueLine >> *(+(SpaceBreak) >> KeyValueLine);
500 not_(expr('-')) >> Seperator >> 383 TableBlock = +(SpaceBreak) >> Advance >> ensure(TableBlockInner, PopIndent);
501 ( 384
502 Exp >> *(sym(',') >> Exp) >> -(invoke_args_with_table | TableBlock) | 385 class_member_list = Seperator >> KeyValue >> *(sym(',') >> KeyValue);
503 TableBlock 386 ClassLine = CheckIndent >> (class_member_list | Statement) >> -sym(',');
387 ClassBlock = +(SpaceBreak) >> Advance >>Seperator >> ClassLine >> *(+(SpaceBreak) >> ClassLine) >> PopIndent;
388
389 ClassDecl =
390 key("class") >> not_(expr(':')) >>
391 -Assignable >>
392 -(key("extends") >> PreventIndent >> ensure(Exp, PopIndent)) >>
393 -ClassBlock;
394
395 export_values = NameList >> -(sym('=') >> ExpListLow);
396 export_op = expr('*') | expr('^');
397 Export = key("export") >> (ClassDecl | (Space >> export_op) | export_values);
398
399 variable_pair = sym(':') >> not_(SomeSpace) >> Space >> Variable;
400
401 normal_pair = (
402 KeyName |
403 sym('[') >> Exp >> sym(']') |
404 Space >> DoubleString |
405 Space >> SingleString
406 ) >>
407 symx(':') >>
408 (Exp | TableBlock | +(SpaceBreak) >> Exp);
409
410 KeyValue = variable_pair | normal_pair;
411
412 KeyValueList = KeyValue >> *(sym(',') >> KeyValue);
413 KeyValueLine = CheckIndent >> KeyValueList >> -sym(',');
414
415 FnArgDef = (Space >> Variable | SelfName) >> -(sym('=') >> Exp);
416
417 FnArgDefList = Seperator >> (
418 (
419 FnArgDef >>
420 *((sym(',') | Break) >> White >> FnArgDef) >>
421 -((sym(',') | Break) >> White >> VarArg)
422 ) | (
423 VarArg
424 )
504 ); 425 );
505 426
506rule const_value = (expr("nil") | expr("true") | expr("false")) >> not_(AlphaNum); 427 outer_var_shadow = key("using") >> (NameList | Space >> expr("nil"));
507rule minus_exp = expr('-') >> not_(SomeSpace) >> Exp; 428
508rule sharp_exp = expr('#') >> Exp; 429 FnArgsDef = sym('(') >> White >> -FnArgDefList >> -outer_var_shadow >> White >> sym(')');
509rule tilde_exp = expr('~') >> Exp; 430 fn_arrow = expr("->") | expr("=>");
510rule not_exp = expr("not") >> not_(AlphaNum) >> Exp; 431 FunLit = -FnArgsDef >> Space >> fn_arrow >> -Body;
511rule unary_exp = minus_exp | sharp_exp | tilde_exp | not_exp; 432
512 433 NameList = Seperator >> Space >> Variable >> *(sym(',') >> Space >> Variable);
513rule SimpleValue = 434 NameOrDestructure = Space >> Variable | TableLit;
514 (Space >> const_value) | 435 AssignableNameList = Seperator >> NameOrDestructure >> *(sym(',') >> NameOrDestructure);
515 If | Unless | Switch | With | ClassDecl | ForEach | For | While | Do | 436
516 (Space >> unary_exp) | 437 Backcall = -FnArgsDef >> Space >> symx("<-") >> Space >> ChainValue;
517 TblComprehension | TableLit | Comprehension | FunLit | 438
518 (Space >> Num); 439 ExpList = Seperator >> Exp >> *(sym(',') >> Exp);
519 440 ExpListLow = Seperator >> Exp >> *((sym(',') | sym(';')) >> Exp);
520rule ExpListAssign = ExpList >> -(Update | Assign); 441
521 442 ArgLine = CheckIndent >> Exp >> *(sym(',') >> Exp);
522rule if_else_line = key("if") >> Exp >> -Assign >> (key("else") >> Exp | default_value); 443 ArgBlock = ArgLine >> *(sym(',') >> SpaceBreak >> ArgLine) >> PopIndent;
523rule unless_line = key("unless") >> Exp; 444
524 445 invoke_args_with_table =
525rule statement_appendix = (if_else_line | unless_line | CompInner) >> Space; 446 sym(',') >>
526rule Statement = 447 (
527( 448 TableBlock |
528 Import | While | For | ForEach | 449 SpaceBreak >> Advance >> ArgBlock >> -TableBlock
529 Return | Local | Export | Space >> BreakLoop | 450 );
530 Backcall | ExpListAssign 451
531) >> Space >> 452 InvokeArgs =
532-statement_appendix; 453 not_(expr('-')) >> Seperator >>
533 454 (
534rule Body = -Space >> Break >> *EmptyLine >> InBlock | Statement; 455 Exp >> *(sym(',') >> Exp) >> -(invoke_args_with_table | TableBlock) |
535 456 TableBlock
536rule empty_line_stop = Space >> and_(Stop); 457 );
537rule Line = CheckIndent >> Statement | empty_line_stop; 458
538rule Block = Seperator >> Line >> *(+Break >> Line); 459 const_value = (expr("nil") | expr("true") | expr("false")) >> not_(AlphaNum);
539 460 minus_exp = expr('-') >> not_(SomeSpace) >> Exp;
540rule Shebang = expr("#!") >> *(not_(Stop) >> Any); 461 sharp_exp = expr('#') >> Exp;
541rule File = White >> -Shebang >> Block >> eof(); 462 tilde_exp = expr('~') >> Exp;
463 not_exp = expr("not") >> not_(AlphaNum) >> Exp;
464 unary_exp = minus_exp | sharp_exp | tilde_exp | not_exp;
465
466 SimpleValue =
467 (Space >> const_value) |
468 If | Unless | Switch | With | ClassDecl | ForEach | For | While | Do |
469 (Space >> unary_exp) |
470 TblComprehension | TableLit | Comprehension | FunLit |
471 (Space >> Num);
472
473 ExpListAssign = ExpList >> -(Update | Assign);
474
475 if_else_line = key("if") >> Exp >> -Assign >> (key("else") >> Exp | default_value);
476 unless_line = key("unless") >> Exp;
477
478 statement_appendix = (if_else_line | unless_line | CompInner) >> Space;
479 Statement = (
480 Import | While | For | ForEach |
481 Return | Local | Export | Space >> BreakLoop |
482 Backcall | ExpListAssign
483 ) >> Space >>
484 -statement_appendix;
485
486 Body = -Space >> Break >> *EmptyLine >> InBlock | Statement;
487
488 empty_line_stop = Space >> and_(Stop);
489 Line = CheckIndent >> Statement | empty_line_stop;
490 Block = Seperator >> Line >> *(+Break >> Line);
491
492 Shebang = expr("#!") >> *(not_(Stop) >> Any);
493 File = White >> -Shebang >> Block >> eof();
494}
495
496ParseInfo MoonParser::parse(const std::string& codes, rule& r) {
497 ParseInfo res;
498 try {
499 res.input = std::make_unique<input>();
500 *(res.input) = _converter.from_bytes(codes);
501 } catch (const std::range_error&) {
502 res.error = "Invalid text encoding."sv;
503 return res;
504 }
505 error_list errors;
506 try {
507 State state;
508 res.node.set(pl::parse(*(res.input), r, errors, &state));
509 } catch (const std::logic_error& err) {
510 res.error = err.what();
511 return res;
512 }
513 if (!errors.empty()) {
514 std::ostringstream buf;
515 for (error_list::iterator it = errors.begin(); it != errors.end(); ++it) {
516 const error& err = *it;
517 switch (err.m_type) {
518 case ERROR_TYPE::ERROR_SYNTAX_ERROR:
519 buf << res.errorMessage("Syntax error."sv, &err);
520 break;
521 case ERROR_TYPE::ERROR_INVALID_EOF:
522 buf << res.errorMessage("Invalid EOF."sv, &err);
523 break;
524 }
525 }
526 res.error = buf.str();
527 }
528 return res;
529}
530
531std::string MoonParser::toString(ast_node* node) {
532 return _converter.to_bytes(std::wstring(node->m_begin.m_it, node->m_end.m_it));
533}
534
535std::string MoonParser::toString(input::iterator begin, input::iterator end) {
536 return _converter.to_bytes(std::wstring(begin, end));
537}
538
539input MoonParser::encode(std::string_view input) {
540 return _converter.from_bytes(std::string(input));
541}
542
543std::string MoonParser::decode(const input& input) {
544 return _converter.to_bytes(input);
545}
546
547namespace Utils {
548 void replace(std::string& str, std::string_view from, std::string_view to) {
549 size_t start_pos = 0;
550 while((start_pos = str.find(from, start_pos)) != std::string::npos) {
551 str.replace(start_pos, from.size(), to);
552 start_pos += to.size();
553 }
554 }
555}
556
557std::string ParseInfo::errorMessage(std::string_view msg, const input_range* loc) const {
558 const int ASCII = 255;
559 int length = loc->m_begin.m_line;
560 auto begin = input->begin();
561 auto end = input->end();
562 int count = 0;
563 for (auto it = input->begin(); it != input->end(); ++it) {
564 if (*it == '\n') {
565 if (count + 1 == length) {
566 end = it;
567 break;
568 } else {
569 begin = it + 1;
570 }
571 count++;
572 }
573 }
574 auto line = Converter{}.to_bytes(std::wstring(begin, end));
575 int oldCol = loc->m_begin.m_col;
576 int col = std::max(0, oldCol - 1);
577 auto it = begin;
578 for (int i = 0; i < oldCol; ++i) {
579 if (*it > ASCII) {
580 ++col;
581 }
582 ++it;
583 }
584 Utils::replace(line, "\t"sv, " "sv);
585 std::ostringstream buf;
586 buf << loc->m_begin.m_line << ": "sv << msg <<
587 '\n' << line << '\n' << std::string(col, ' ') << "^"sv;
588 return buf.str();
589}
542 590
543} // namespace MoonP 591} // namespace MoonP