aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/MoonP/ast.cpp132
-rw-r--r--src/MoonP/ast.hpp565
-rw-r--r--src/MoonP/moon_ast.cpp113
-rw-r--r--src/MoonP/moon_ast.h587
-rw-r--r--src/MoonP/moon_compiler.cpp3865
-rw-r--r--src/MoonP/moon_compiler.h39
-rw-r--r--src/MoonP/moon_parser.cpp526
-rw-r--r--src/MoonP/moon_parser.h35
-rw-r--r--src/MoonP/parser.cpp1439
-rw-r--r--src/MoonP/parser.hpp435
-rw-r--r--src/moonc.cpp178
11 files changed, 7914 insertions, 0 deletions
diff --git a/src/MoonP/ast.cpp b/src/MoonP/ast.cpp
new file mode 100644
index 0000000..cda2339
--- /dev/null
+++ b/src/MoonP/ast.cpp
@@ -0,0 +1,132 @@
1/* Copyright (c) 2012, Achilleas Margaritis, modified by Jin Li
2All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
6 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
9THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
10
11#include <cassert>
12#include "MoonP/ast.hpp"
13
14
15namespace parserlib {
16
17int ast_type_id = 0;
18
19traversal ast_node::traverse(const std::function<traversal (ast_node*)>& func) {
20 return func(this);
21}
22
23ast_node* ast_node::getByTypeIds(int* begin, int* end) {
24 ast_node* current = this;
25 auto it = begin;
26 while (it != end) {
27 ast_node* findNode = nullptr;
28 int type = *it;
29 current->visitChild([&](ast_node* node) {
30 if (node->get_type() == type) {
31 findNode = node;
32 return true;
33 }
34 return false;
35 });
36 if (findNode) {
37 current = findNode;
38 } else {
39 current = nullptr;
40 break;
41 }
42 ++it;
43 }
44 return current;
45}
46
47bool ast_node::visitChild(const std::function<bool (ast_node*)>&) {
48 return false;
49}
50
51
52/** Asks all members to construct themselves from the stack.
53 The members are asked to construct themselves in reverse order.
54 from a node stack.
55 @param st stack.
56 */
57void ast_container::construct(ast_stack &st) {
58 for(ast_member_vector::reverse_iterator it = m_members.rbegin();
59 it != m_members.rend();
60 ++it)
61 {
62 ast_member* member = *it;
63 member->construct(st);
64 }
65}
66
67traversal ast_container::traverse(const std::function<traversal (ast_node*)>& func) {
68 traversal action = func(this);
69 switch (action) {
70 case traversal::Stop: return traversal::Stop;
71 case traversal::Return: return traversal::Continue;
72 default: break;
73 }
74 const auto& members = this->members();
75 for (auto member : members) {
76 if (_ast_ptr* ptr = ast_cast<_ast_ptr>(member)) {
77 if (ptr->get() && ptr->get()->traverse(func) == traversal::Stop) {
78 return traversal::Stop;
79 }
80 } else if (_ast_list* list = ast_cast<_ast_list>(member)) {
81 for (auto obj : list->objects()) {
82 if (obj->traverse(func) == traversal::Stop) {
83 return traversal::Stop;
84 }
85 }
86 }
87 }
88 return traversal::Continue;
89}
90
91bool ast_container::visitChild(const std::function<bool (ast_node*)>& func) {
92 const auto& members = this->members();
93 for (auto member : members) {
94 if (_ast_ptr* ptr = ast_cast<_ast_ptr>(member)) {
95 if (ptr->get()) {
96 if (func(ptr->get())) return true;
97 }
98 } else if (_ast_list* list = ast_cast<_ast_list>(member)) {
99 for (auto obj : list->objects()) {
100 if (obj) {
101 if (func(obj)) return true;
102 }
103 }
104 }
105 }
106 return false;
107}
108
109
110/** parses the given input.
111 @param i input.
112 @param g root rule of grammar.
113 @param el list of errors.
114 @param ud user data, passed to the parse procedures.
115 @return pointer to ast node created, or null if there was an error.
116 The return object must be deleted by the caller.
117 */
118ast_node* _parse(input &i, rule &g, error_list &el, void* ud) {
119 ast_stack st;
120 if (!parse(i, g, el, &st, ud)) {
121 for (auto node : st) {
122 delete node;
123 }
124 st.clear();
125 return nullptr;
126 }
127 assert(st.size() == 1);
128 return st.front();
129}
130
131
132} //namespace parserlib
diff --git a/src/MoonP/ast.hpp b/src/MoonP/ast.hpp
new file mode 100644
index 0000000..f2ef76c
--- /dev/null
+++ b/src/MoonP/ast.hpp
@@ -0,0 +1,565 @@
1/* Copyright (c) 2012, Achilleas Margaritis, modified by Jin Li
2All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
6 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
9THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
10
11#pragma once
12
13
14#include <cassert>
15#include <list>
16#include <stdexcept>
17#include <type_traits>
18#include "MoonP/parser.hpp"
19
20
21namespace parserlib {
22
23
24class ast_node;
25template <bool Required, class T> class ast_ptr;
26template <bool Required, class T> class ast_list;
27template <class T> class ast;
28
29
30/** type of AST node stack.
31 */
32typedef std::vector<ast_node*> ast_stack;
33typedef std::list<ast_node*> node_container;
34
35extern int ast_type_id;
36
37template<class T>
38int ast_type() {
39 static int type = ast_type_id++;
40 return type;
41}
42
43enum class traversal {
44 Continue,
45 Return,
46 Stop
47};
48
49/** Base class for AST nodes.
50 */
51class ast_node : public input_range {
52public:
53 ast_node() : _ref(0) {}
54
55 void retain() {
56 ++_ref;
57 }
58
59 void release() {
60 --_ref;
61 if (_ref == 0) {
62 delete this;
63 }
64 }
65
66 /** interface for filling the contents of the node
67 from a node stack.
68 @param st stack.
69 */
70 virtual void construct(ast_stack&) {}
71
72 /** interface for visiting AST tree use.
73 */
74 virtual traversal traverse(const std::function<traversal (ast_node*)>& func);
75
76 template <typename... Ts>
77 struct select_last {
78 using type = typename decltype((std::enable_if<true,Ts>{}, ...))::type;
79 };
80 template <typename... Ts>
81 using select_last_t = typename select_last<Ts...>::type;
82
83 template <class ...Args>
84 select_last_t<Args...>* getByPath() {
85 int types[] = {ast_type<Args>()...};
86 return static_cast<select_last_t<Args...>*>(getByTypeIds(std::begin(types), std::end(types)));
87 }
88
89 virtual bool visitChild(const std::function<bool (ast_node*)>& func);
90
91 virtual size_t getId() const = 0;
92
93 virtual int get_type() = 0;
94
95 template<class T>
96 inline ast_ptr<false, T> new_ptr() {
97 auto item = new T;
98 item->m_begin.m_line = m_begin.m_line;
99 item->m_end.m_line = m_begin.m_line;
100 return ast_ptr<false, T>(item);
101 }
102private:
103 int _ref;
104 ast_node* getByTypeIds(int* begin, int* end);
105};
106
107template<class T>
108T* ast_cast(ast_node* node) {
109 return node && ast_type<T>() == node->get_type() ? static_cast<T*>(node) : nullptr;
110}
111
112template<class T>
113T* ast_to(ast_node* node) {
114 assert(node->get_type() == ast_type<T>());
115 return static_cast<T*>(node);
116}
117
118template <class ...Args>
119bool ast_is(ast_node* node) {
120 if (!node) return false;
121 bool result = false;
122 int type = node->get_type();
123 using swallow = bool[];
124 (void)swallow{result || (result = ast_type<Args>() == type)...};
125 return result;
126}
127
128class ast_member;
129
130/** type of ast member vector.
131 */
132typedef std::vector<ast_member*> ast_member_vector;
133
134
135/** base class for AST nodes with children.
136 */
137class ast_container : public ast_node {
138public:
139 void add_members(std::initializer_list<ast_member*> members) {
140 for (auto member : members) {
141 m_members.push_back(member);
142 }
143 }
144
145 /** returns the vector of AST members.
146 @return the vector of AST members.
147 */
148 const ast_member_vector& members() const {
149 return m_members;
150 }
151
152 /** Asks all members to construct themselves from the stack.
153 The members are asked to construct themselves in reverse order.
154 from a node stack.
155 @param st stack.
156 */
157 virtual void construct(ast_stack& st) override;
158
159 virtual traversal traverse(const std::function<traversal (ast_node*)>& func) override;
160
161 virtual bool visitChild(const std::function<bool (ast_node*)>& func) override;
162private:
163 ast_member_vector m_members;
164
165 friend class ast_member;
166};
167
168
169/** Base class for children of ast_container.
170 */
171class ast_member {
172public:
173 virtual ~ast_member() {}
174
175 /** interface for filling the the member from a node stack.
176 @param st stack.
177 */
178 virtual void construct(ast_stack& st) = 0;
179
180 virtual bool accept(ast_node* node) = 0;
181
182 virtual int get_type() { return ast_type<ast_member>(); }
183};
184
185template<class T>
186T* ast_cast(ast_member* member) {
187 return member && ast_type<T>() == member->get_type() ? static_cast<T*>(member) : nullptr;
188}
189
190class _ast_ptr : public ast_member {
191public:
192 _ast_ptr(ast_node* node) : m_ptr(node) {
193 if (node) node->retain();
194 }
195
196 virtual ~_ast_ptr() {
197 if (m_ptr) {
198 m_ptr->release();
199 m_ptr = nullptr;
200 }
201 }
202
203 ast_node* get() const {
204 return m_ptr;
205 }
206
207 template <class T>
208 T* as() const {
209 return ast_cast<T>(m_ptr);
210 }
211
212 template <class T>
213 T* to() const {
214 assert(m_ptr && m_ptr->get_type() == ast_type<T>());
215 return static_cast<T*>(m_ptr);
216 }
217
218 template <class T>
219 bool is() const {
220 return m_ptr && m_ptr->get_type() == ast_type<T>();
221 }
222
223 void set(ast_node* node) {
224 if (node == m_ptr) {
225 return;
226 } else if (!node) {
227 if (m_ptr) m_ptr->release();
228 m_ptr = nullptr;
229 } else {
230 assert(accept(node));
231 if (m_ptr) m_ptr->release();
232 m_ptr = node;
233 node->retain();
234 }
235 }
236
237 virtual int get_type() override {
238 return ast_type<_ast_ptr>();
239 }
240protected:
241 ast_node* m_ptr;
242};
243
244/** pointer to an AST object.
245 It assumes ownership of the object.
246 It pops an object of the given type from the stack.
247 @tparam Required if true, the object is required.
248 @tparam T type of object to control.
249 */
250template <bool Required, class T> class ast_ptr : public _ast_ptr {
251public:
252 ast_ptr(T* node = nullptr) : _ast_ptr(node) {}
253
254 ast_ptr(const ast_ptr& other) : _ast_ptr(other.get()) {}
255
256 ast_ptr& operator=(const ast_ptr& other) {
257 set(other.get());
258 return *this;
259 }
260
261 /** gets the underlying ptr value.
262 @return the underlying ptr value.
263 */
264 T* get() const {
265 return static_cast<T*>(m_ptr);
266 }
267
268 /** auto conversion to the underlying object ptr.
269 @return the underlying ptr value.
270 */
271 operator T*() const {
272 return static_cast<T*>(m_ptr);
273 }
274
275 /** member access.
276 @return the underlying ptr value.
277 */
278 T* operator->() const {
279 assert(m_ptr);
280 return static_cast<T*>(m_ptr);
281 }
282
283 /** Pops a node from the stack.
284 @param st stack.
285 @exception std::logic_error thrown if the node is not of the appropriate type;
286 thrown only if Required == true or if the stack is empty.
287 */
288 virtual void construct(ast_stack& st) override {
289 // check the stack node
290 if (st.empty()) {
291 if (!Required) return;
292 throw std::logic_error("Invalid AST stack.");
293 }
294 ast_node* node = st.back();
295 if (!ast_ptr::accept(node)) {
296 // if the object is not required, simply return
297 if (!Required) return;
298 // else if the object is mandatory, throw an exception
299 throw std::logic_error("Invalid AST node.");
300 }
301 st.pop_back();
302 m_ptr = node;
303 node->retain();
304 }
305private:
306 virtual bool accept(ast_node* node) override {
307 return node && (std::is_same<ast_node,T>() || ast_type<T>() == node->get_type());
308 }
309};
310
311template <bool Required, class ...Args> class ast_sel : public _ast_ptr {
312public:
313 ast_sel() : _ast_ptr(nullptr) {}
314
315 ast_sel(const ast_sel& other) : _ast_ptr(other.get()) {}
316
317 ast_sel& operator=(const ast_sel& other) {
318 set(other.get());
319 return *this;
320 }
321
322 operator ast_node*() const {
323 return m_ptr;
324 }
325
326 ast_node* operator->() const {
327 assert(m_ptr);
328 return m_ptr;
329 }
330
331 virtual void construct(ast_stack& st) override {
332 if (st.empty()) {
333 if (!Required) return;
334 throw std::logic_error("Invalid AST stack.");
335 }
336 ast_node* node = st.back();
337 if (!ast_sel::accept(node)) {
338 if (!Required) return;
339 throw std::logic_error("Invalid AST node.");
340 }
341 st.pop_back();
342 m_ptr = node;
343 node->retain();
344 }
345private:
346 virtual bool accept(ast_node* node) override {
347 if (!node) return false;
348 using swallow = bool[];
349 bool result = false;
350 (void)swallow{result || (result = ast_type<Args>() == node->get_type())...};
351 return result;
352 }
353};
354
355class _ast_list : public ast_member {
356public:
357 ~_ast_list() {
358 clear();
359 }
360
361 inline ast_node* back() const {
362 return m_objects.back();
363 }
364
365 inline ast_node* front() const {
366 return m_objects.front();
367 }
368
369 inline size_t size() const {
370 return m_objects.size();
371 }
372
373 inline bool empty() const {
374 return m_objects.empty();
375 }
376
377 void push_back(ast_node* node) {
378 assert(node && accept(node));
379 m_objects.push_back(node);
380 node->retain();
381 }
382
383 void push_front(ast_node* node) {
384 assert(node && accept(node));
385 m_objects.push_front(node);
386 node->retain();
387 }
388
389 void pop_front() {
390 auto node = m_objects.front();
391 m_objects.pop_front();
392 node->release();
393 }
394
395 const node_container& objects() const {
396 return m_objects;
397 }
398
399 void clear() {
400 for(ast_node* obj : m_objects) {
401 if (obj) obj->release();
402 }
403 m_objects.clear();
404 }
405
406 void dup(const _ast_list& src) {
407 for(ast_node* obj : src.m_objects) {
408 m_objects.push_back(obj);
409 obj->retain();
410 }
411 }
412
413 virtual int get_type() override { return ast_type<_ast_list>(); }
414protected:
415 node_container m_objects;
416};
417
418/** A list of objects.
419 It pops objects of the given type from the ast stack, until no more objects can be popped.
420 It assumes ownership of objects.
421 @tparam Required if true, the object is required.
422 @tparam T type of object to control.
423 */
424template <bool Required, class T> class ast_list : public _ast_list {
425public:
426 ast_list() { }
427
428 ast_list(const ast_list& other) {
429 dup(other);
430 }
431
432 ast_list& operator=(const ast_list& other) {
433 clear();
434 dup(other);
435 return *this;
436 }
437
438 /** Pops objects of type T from the stack until no more objects can be popped.
439 @param st stack.
440 */
441 virtual void construct(ast_stack &st) override {
442 while (!st.empty()) {
443 ast_node* node = st.back();
444 // if the object was not not of the appropriate type,
445 // end the list parsing
446 if (!ast_list::accept(node)) {
447 if (Required && m_objects.empty()) {
448 throw std::logic_error("Invalid AST node.");
449 }
450 return;
451 }
452 st.pop_back();
453 // insert the object in the list, in reverse order
454 m_objects.push_front(node);
455 node->retain();
456 }
457 if (Required && m_objects.empty()) {
458 throw std::logic_error("Invalid AST stack.");
459 }
460 }
461private:
462 virtual bool accept(ast_node* node) override {
463 return node && (std::is_same<ast_node,T>() || ast_type<T>() == node->get_type());
464 }
465};
466
467template <bool Required, class ...Args> class ast_sel_list : public _ast_list {
468public:
469 ast_sel_list() { }
470
471 ast_sel_list(const ast_sel_list& other) {
472 dup(other);
473 }
474
475 ast_sel_list& operator=(const ast_sel_list& other) {
476 clear();
477 dup(other);
478 return *this;
479 }
480
481 virtual void construct(ast_stack &st) override {
482 while (!st.empty()) {
483 ast_node* node = st.back();
484 if (!ast_sel_list::accept(node)) {
485 if (Required && m_objects.empty()) {
486 throw std::logic_error("Invalid AST node.");
487 }
488 return;
489 }
490 st.pop_back();
491 m_objects.push_front(node);
492 node->retain();
493 }
494 if (Required && m_objects.empty()) {
495 throw std::logic_error("Invalid AST stack.");
496 }
497 }
498private:
499 virtual bool accept(ast_node* node) override {
500 if (!node) return false;
501 using swallow = bool[];
502 bool result = false;
503 (void)swallow{result || (result = ast_type<Args>() == node->get_type())...};
504 return result;
505 }
506};
507
508/** AST function which creates an object of type T
509 and pushes it to the node stack.
510 */
511template <class T> class ast {
512public:
513 /** constructor.
514 @param r rule to attach the AST function to.
515 */
516 ast(rule& r) {
517 r.set_parse_proc(&_parse_proc);
518 }
519
520private:
521 //parse proc
522 static void _parse_proc(const pos& b, const pos& e, void* d) {
523 ast_stack* st = reinterpret_cast<ast_stack*>(d);
524 T* obj = new T;
525 obj->m_begin = b;
526 obj->m_end = e;
527 obj->construct(*st);
528 st->push_back(obj);
529 }
530};
531
532
533/** parses the given input.
534 @param i input.
535 @param g root rule of grammar.
536 @param el list of errors.
537 @param ud user data, passed to the parse procedures.
538 @return pointer to ast node created, or null if there was an error.
539 The return object must be deleted by the caller.
540 */
541ast_node* _parse(input& i, rule& g, error_list& el, void* ud);
542
543
544/** parses the given input.
545 @param i input.
546 @param g root rule of grammar.
547 @param el list of errors.
548 @param ud user data, passed to the parse procedures.
549 @return ast nodes.
550 */
551template <class T> ast_ptr<false, T> parse(input& i, rule& g, error_list& el, void* ud = nullptr) {
552 ast_node* node = _parse(i, g, el, ud);
553 T* ast = ast_cast<T>(node);
554 ast_ptr<false, T> ptr;
555 if (ast) {
556 ast_stack st{node};
557 ptr.construct(st);
558 } else if (node) {
559 delete node;
560 }
561 return ptr;
562}
563
564
565} //namespace parserlib
diff --git a/src/MoonP/moon_ast.cpp b/src/MoonP/moon_ast.cpp
new file mode 100644
index 0000000..0ccd0ed
--- /dev/null
+++ b/src/MoonP/moon_ast.cpp
@@ -0,0 +1,113 @@
1/* Copyright (c) 2020 Jin Li, http://www.luvfight.me
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
5The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
7THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
8
9#include "MoonP/moon_ast.h"
10
11namespace MoonP {
12
13#define AST_IMPL(type) \
14 ast<type##_t> __##type##_t(type);
15
16AST_IMPL(Num)
17AST_IMPL(Name)
18AST_IMPL(Variable)
19AST_IMPL(LuaKeyword)
20AST_IMPL(self)
21AST_IMPL(self_name)
22AST_IMPL(self_class)
23AST_IMPL(self_class_name)
24AST_IMPL(SelfName)
25AST_IMPL(KeyName)
26AST_IMPL(VarArg)
27AST_IMPL(local_flag)
28AST_IMPL(Seperator)
29AST_IMPL(NameList)
30AST_IMPL(Local)
31AST_IMPL(colon_import_name)
32AST_IMPL(Import)
33AST_IMPL(ExpListLow)
34AST_IMPL(ExpList)
35AST_IMPL(Return)
36AST_IMPL(With)
37AST_IMPL(SwitchCase)
38AST_IMPL(Switch)
39AST_IMPL(IfCond)
40AST_IMPL(If)
41AST_IMPL(Unless)
42AST_IMPL(While)
43AST_IMPL(for_step_value)
44AST_IMPL(For)
45AST_IMPL(ForEach)
46AST_IMPL(Do)
47AST_IMPL(Comprehension)
48AST_IMPL(comp_value)
49AST_IMPL(TblComprehension)
50AST_IMPL(star_exp)
51AST_IMPL(CompForEach)
52AST_IMPL(CompFor)
53AST_IMPL(CompInner)
54AST_IMPL(Assign)
55AST_IMPL(update_op)
56AST_IMPL(Update)
57AST_IMPL(BinaryOperator)
58AST_IMPL(Assignable)
59AST_IMPL(AssignableChain)
60AST_IMPL(exp_op_value)
61AST_IMPL(Exp)
62AST_IMPL(Callable)
63AST_IMPL(ChainValue)
64AST_IMPL(simple_table)
65AST_IMPL(SimpleValue)
66AST_IMPL(Value)
67AST_IMPL(LuaStringOpen);
68AST_IMPL(LuaStringContent);
69AST_IMPL(LuaStringClose);
70AST_IMPL(LuaString)
71AST_IMPL(SingleString)
72AST_IMPL(double_string_inner)
73AST_IMPL(double_string_content)
74AST_IMPL(DoubleString)
75AST_IMPL(String)
76AST_IMPL(Parens)
77AST_IMPL(DotChainItem)
78AST_IMPL(ColonChainItem)
79AST_IMPL(default_value)
80AST_IMPL(Slice)
81AST_IMPL(Invoke)
82AST_IMPL(TableLit)
83AST_IMPL(TableBlock)
84AST_IMPL(class_member_list)
85AST_IMPL(ClassBlock)
86AST_IMPL(ClassDecl)
87AST_IMPL(export_values)
88AST_IMPL(export_op)
89AST_IMPL(Export)
90AST_IMPL(variable_pair)
91AST_IMPL(normal_pair)
92AST_IMPL(FnArgDef)
93AST_IMPL(FnArgDefList)
94AST_IMPL(outer_var_shadow)
95AST_IMPL(FnArgsDef)
96AST_IMPL(fn_arrow)
97AST_IMPL(FunLit)
98AST_IMPL(NameOrDestructure)
99AST_IMPL(AssignableNameList)
100AST_IMPL(InvokeArgs)
101AST_IMPL(const_value)
102AST_IMPL(unary_exp)
103AST_IMPL(ExpListAssign)
104AST_IMPL(if_else_line)
105AST_IMPL(unless_line)
106AST_IMPL(statement_appendix)
107AST_IMPL(BreakLoop)
108AST_IMPL(Statement)
109AST_IMPL(Body)
110AST_IMPL(Block)
111AST_IMPL(File)
112
113} // namespace MoonP
diff --git a/src/MoonP/moon_ast.h b/src/MoonP/moon_ast.h
new file mode 100644
index 0000000..a614465
--- /dev/null
+++ b/src/MoonP/moon_ast.h
@@ -0,0 +1,587 @@
1/* Copyright (c) 2020 Jin Li, http://www.luvfight.me
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
5The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
7THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
8
9#pragma once
10
11#include "MoonP/moon_parser.h"
12
13namespace MoonP {
14
15#define AST_LEAF(type, id) \
16extern rule type; \
17class type##_t : public ast_node \
18{ \
19public: \
20 virtual int get_type() override { return ast_type<type##_t>(); } \
21 virtual size_t getId() const override { return id; } \
22
23#define AST_NODE(type, id) \
24extern rule type; \
25class type##_t : public ast_container \
26{ \
27public: \
28 virtual int get_type() override { return ast_type<type##_t>(); } \
29 virtual size_t getId() const override { return id; } \
30
31#define AST_MEMBER(type, ...) \
32 type##_t() { \
33 add_members({__VA_ARGS__}); \
34 }
35
36#define AST_END(type) \
37};
38
39AST_LEAF(Num, "Num"_id)
40AST_END(Num)
41
42AST_LEAF(Name, "Name"_id)
43AST_END(Name)
44
45AST_NODE(Variable, "Variable"_id)
46 ast_ptr<true, Name_t> name;
47 AST_MEMBER(Variable, &name)
48AST_END(Variable)
49
50AST_NODE(LuaKeyword, "LuaKeyword"_id)
51 ast_ptr<true, Name_t> name;
52 AST_MEMBER(LuaKeyword, &name)
53AST_END(LuaKeyword)
54
55AST_LEAF(self, "self"_id)
56AST_END(self)
57
58AST_NODE(self_name, "self_name"_id)
59 ast_ptr<true, Name_t> name;
60 AST_MEMBER(self_name, &name)
61AST_END(self_name)
62
63AST_LEAF(self_class, "self_class"_id)
64AST_END(self_class)
65
66AST_NODE(self_class_name, "self_class_name"_id)
67 ast_ptr<true, Name_t> name;
68 AST_MEMBER(self_class_name, &name)
69AST_END(self_class_name)
70
71AST_NODE(SelfName, "SelfName"_id)
72 ast_sel<true, self_class_name_t, self_class_t, self_name_t, self_t> name;
73 AST_MEMBER(SelfName, &name)
74AST_END(SelfName)
75
76AST_NODE(KeyName, "KeyName"_id)
77 ast_sel<true, SelfName_t, Name_t> name;
78 AST_MEMBER(KeyName, &name)
79AST_END(KeyName)
80
81AST_LEAF(VarArg, "VarArg"_id)
82AST_END(VarArg)
83
84AST_LEAF(local_flag, "local_flag"_id)
85AST_END(local_flag)
86
87AST_LEAF(Seperator, "Seperator"_id)
88AST_END(Seperator)
89
90AST_NODE(NameList, "NameList"_id)
91 ast_ptr<true, Seperator_t> sep;
92 ast_list<true, Variable_t> names;
93 AST_MEMBER(NameList, &sep, &names)
94AST_END(NameList)
95
96AST_NODE(Local, "Local"_id)
97 ast_sel<true, local_flag_t, NameList_t> name;
98 std::list<std::string> forceDecls;
99 std::list<std::string> decls;
100 AST_MEMBER(Local, &name)
101AST_END(Local)
102
103AST_NODE(colon_import_name, "colon_import_name"_id)
104 ast_ptr<true, Variable_t> name;
105 AST_MEMBER(colon_import_name, &name)
106AST_END(colon_import_name)
107
108class Exp_t;
109
110AST_NODE(Import, "Import"_id)
111 ast_ptr<true, Seperator_t> sep;
112 ast_sel_list<true, colon_import_name_t, Variable_t> names;
113 ast_ptr<true, Exp_t> exp;
114 AST_MEMBER(Import, &sep, &names, &exp)
115AST_END(Import)
116
117AST_NODE(ExpListLow, "ExpListLow"_id)
118 ast_ptr<true, Seperator_t> sep;
119 ast_list<true, Exp_t> exprs;
120 AST_MEMBER(ExpListLow, &sep, &exprs)
121AST_END(ExpListLow)
122
123AST_NODE(ExpList, "ExpList"_id)
124 ast_ptr<true, Seperator_t> sep;
125 ast_list<true, Exp_t> exprs;
126 AST_MEMBER(ExpList, &sep, &exprs)
127AST_END(ExpList)
128
129AST_NODE(Return, "Return"_id)
130 ast_ptr<false, ExpListLow_t> valueList;
131 AST_MEMBER(Return, &valueList)
132AST_END(Return)
133
134class Assign_t;
135class Body_t;
136
137AST_NODE(With, "With"_id)
138 ast_ptr<true, ExpList_t> valueList;
139 ast_ptr<false, Assign_t> assigns;
140 ast_ptr<true, Body_t> body;
141 AST_MEMBER(With, &valueList, &assigns, &body)
142AST_END(With)
143
144AST_NODE(SwitchCase, "SwitchCase"_id)
145 ast_ptr<true, ExpList_t> valueList;
146 ast_ptr<true, Body_t> body;
147 AST_MEMBER(SwitchCase, &valueList, &body)
148AST_END(SwitchCase)
149
150AST_NODE(Switch, "Switch"_id)
151 ast_ptr<true, Exp_t> target;
152 ast_ptr<true, Seperator_t> sep;
153 ast_list<true, SwitchCase_t> branches;
154 ast_ptr<false, Body_t> lastBranch;
155 AST_MEMBER(Switch, &target, &sep, &branches, &lastBranch)
156AST_END(Switch)
157
158AST_NODE(IfCond, "IfCond"_id)
159 ast_ptr<true, Exp_t> condition;
160 ast_ptr<false, Assign_t> assign;
161 AST_MEMBER(IfCond, &condition, &assign)
162AST_END(IfCond)
163
164AST_NODE(If, "If"_id)
165 ast_ptr<true, Seperator_t> sep;
166 ast_sel_list<true, IfCond_t, Body_t> nodes;
167 AST_MEMBER(If, &sep, &nodes)
168AST_END(If)
169
170AST_NODE(Unless, "Unless"_id)
171 ast_ptr<true, Seperator_t> sep;
172 ast_sel_list<true, IfCond_t, Body_t> nodes;
173 AST_MEMBER(Unless, &sep, &nodes)
174AST_END(Unless)
175
176AST_NODE(While, "While"_id)
177 ast_ptr<true, Exp_t> condition;
178 ast_ptr<true, Body_t> body;
179 AST_MEMBER(While, &condition, &body)
180AST_END(While)
181
182AST_NODE(for_step_value, "for_step_value"_id)
183 ast_ptr<true, Exp_t> value;
184 AST_MEMBER(for_step_value, &value)
185AST_END(for_step_value)
186
187AST_NODE(For, "For"_id)
188 ast_ptr<true, Variable_t> varName;
189 ast_ptr<true, Exp_t> startValue;
190 ast_ptr<true, Exp_t> stopValue;
191 ast_ptr<false, for_step_value_t> stepValue;
192 ast_ptr<true, Body_t> body;
193 AST_MEMBER(For, &varName, &startValue, &stopValue, &stepValue, &body)
194AST_END(For)
195
196class AssignableNameList_t;
197class star_exp_t;
198
199AST_NODE(ForEach, "ForEach"_id)
200 ast_ptr<true, AssignableNameList_t> nameList;
201 ast_sel<true, star_exp_t, ExpList_t> loopValue;
202 ast_ptr<true, Body_t> body;
203 AST_MEMBER(ForEach, &nameList, &loopValue, &body)
204AST_END(ForEach)
205
206AST_NODE(Do, "Do"_id)
207 ast_ptr<true, Body_t> body;
208 AST_MEMBER(Do, &body)
209AST_END(Do)
210
211class CompInner_t;
212class Statement_t;
213
214AST_NODE(Comprehension, "Comprehension"_id)
215 ast_sel<true, Exp_t, Statement_t> value;
216 ast_ptr<true, CompInner_t> forLoop;
217 AST_MEMBER(Comprehension, &value, &forLoop)
218AST_END(Comprehension)
219
220AST_NODE(comp_value, "comp_value"_id)
221 ast_ptr<true, Exp_t> value;
222 AST_MEMBER(comp_value, &value)
223AST_END(comp_value)
224
225AST_NODE(TblComprehension, "TblComprehension"_id)
226 ast_ptr<true, Exp_t> key;
227 ast_ptr<false, comp_value_t> value;
228 ast_ptr<true, CompInner_t> forLoop;
229 AST_MEMBER(TblComprehension, &key, &value, &forLoop)
230AST_END(TblComprehension)
231
232AST_NODE(star_exp, "star_exp"_id)
233 ast_ptr<true, Exp_t> value;
234 AST_MEMBER(star_exp, &value)
235AST_END(star_exp)
236
237AST_NODE(CompForEach, "CompForEach"_id)
238 ast_ptr<true, AssignableNameList_t> nameList;
239 ast_sel<true, star_exp_t, Exp_t> loopValue;
240 AST_MEMBER(CompForEach, &nameList, &loopValue)
241AST_END(CompForEach)
242
243AST_NODE(CompFor, "CompFor"_id)
244 ast_ptr<true, Variable_t> varName;
245 ast_ptr<true, Exp_t> startValue;
246 ast_ptr<true, Exp_t> stopValue;
247 ast_ptr<false, for_step_value_t> stepValue;
248 AST_MEMBER(CompFor, &varName, &startValue, &stopValue, &stepValue)
249AST_END(CompFor)
250
251AST_NODE(CompInner, "CompInner"_id)
252 ast_ptr<true, Seperator_t> sep;
253 ast_sel_list<true, CompFor_t, CompForEach_t, Exp_t> items;
254 AST_MEMBER(CompInner, &sep, &items)
255AST_END(CompInner)
256
257class TableBlock_t;
258
259AST_NODE(Assign, "Assign"_id)
260 ast_ptr<true, Seperator_t> sep;
261 ast_sel_list<true, With_t, If_t, Switch_t, TableBlock_t, Exp_t> values;
262 AST_MEMBER(Assign, &sep, &values)
263AST_END(Assign)
264
265AST_LEAF(update_op, "update_op"_id)
266AST_END(update_op)
267
268AST_NODE(Update, "Update"_id)
269 ast_ptr<true, update_op_t> op;
270 ast_ptr<true, Exp_t> value;
271 AST_MEMBER(Update, &op, &value)
272AST_END(Update)
273
274AST_LEAF(BinaryOperator, "BinaryOperator"_id)
275AST_END(BinaryOperator)
276
277class AssignableChain_t;
278
279AST_NODE(Assignable, "Assignable"_id)
280 ast_sel<true, AssignableChain_t, Variable_t, SelfName_t> item;
281 AST_MEMBER(Assignable, &item)
282AST_END(Assignable)
283
284class Value_t;
285
286AST_NODE(exp_op_value, "exp_op_value"_id)
287 ast_ptr<true, BinaryOperator_t> op;
288 ast_ptr<true, Value_t> value;
289 AST_MEMBER(exp_op_value, &op, &value)
290AST_END(exp_op_value)
291
292AST_NODE(Exp, "Exp"_id)
293 ast_ptr<true, Value_t> value;
294 ast_list<false, exp_op_value_t> opValues;
295 AST_MEMBER(Exp, &value, &opValues)
296AST_END(Exp)
297
298class Parens_t;
299
300AST_NODE(Callable, "Callable"_id)
301 ast_sel<true, Variable_t, SelfName_t, VarArg_t, Parens_t> item;
302 AST_MEMBER(Callable, &item)
303AST_END(Callable)
304
305AST_NODE(variable_pair, "variable_pair"_id)
306 ast_ptr<true, Variable_t> name;
307 AST_MEMBER(variable_pair, &name)
308AST_END(variable_pair)
309
310class DoubleString_t;
311class SingleString_t;
312
313AST_NODE(normal_pair, "normal_pair"_id)
314 ast_sel<true, KeyName_t, Exp_t, DoubleString_t, SingleString_t> key;
315 ast_sel<true, Exp_t, TableBlock_t> value;
316 AST_MEMBER(normal_pair, &key, &value)
317AST_END(normal_pair)
318
319AST_NODE(simple_table, "simple_table"_id)
320 ast_ptr<true, Seperator_t> sep;
321 ast_sel_list<true, variable_pair_t, normal_pair_t> pairs;
322 AST_MEMBER(simple_table, &sep, &pairs)
323AST_END(simple_table)
324
325class String_t;
326class const_value_t;
327class ClassDecl_t;
328class unary_exp_t;
329class TableLit_t;
330class FunLit_t;
331
332AST_NODE(SimpleValue, "SimpleValue"_id)
333 ast_sel<true, const_value_t,
334 If_t, Unless_t, Switch_t, With_t, ClassDecl_t,
335 ForEach_t, For_t, While_t, Do_t, unary_exp_t,
336 TblComprehension_t, TableLit_t, Comprehension_t,
337 FunLit_t, Num_t> value;
338 AST_MEMBER(SimpleValue, &value)
339AST_END(SimpleValue)
340
341AST_LEAF(LuaStringOpen, "LuaStringOpen"_id)
342AST_END(LuaStringOpen)
343
344AST_LEAF(LuaStringContent, "LuaStringContent"_id)
345AST_END(LuaStringContent)
346
347AST_LEAF(LuaStringClose, "LuaStringClose"_id)
348AST_END(LuaStringClose)
349
350AST_NODE(LuaString, "LuaString"_id)
351 ast_ptr<true, LuaStringOpen_t> open;
352 ast_ptr<true, LuaStringContent_t> content;
353 ast_ptr<true, LuaStringClose_t> close;
354 AST_MEMBER(LuaString, &open, &content, &close)
355AST_END(LuaString)
356
357AST_LEAF(SingleString, "SingleString"_id)
358AST_END(SingleString)
359
360AST_LEAF(double_string_inner, "double_string_inner"_id)
361AST_END(double_string_inner)
362
363AST_NODE(double_string_content, "double_string_content"_id)
364 ast_sel<true, double_string_inner_t, Exp_t> content;
365 AST_MEMBER(double_string_content, &content)
366AST_END(double_string_content)
367
368AST_NODE(DoubleString, "DoubleString"_id)
369 ast_ptr<true, Seperator_t> sep;
370 ast_list<false, double_string_content_t> segments;
371 AST_MEMBER(DoubleString, &sep, &segments)
372AST_END(DoubleString)
373
374AST_NODE(String, "String"_id)
375 ast_sel<true, DoubleString_t, SingleString_t, LuaString_t> str;
376 AST_MEMBER(String, &str)
377AST_END(String)
378
379AST_NODE(DotChainItem, "DotChainItem"_id)
380 ast_ptr<true, Name_t> name;
381 AST_MEMBER(DotChainItem, &name)
382AST_END(DotChainItem)
383
384AST_NODE(ColonChainItem, "ColonChainItem"_id)
385 ast_sel<true, LuaKeyword_t, Name_t> name;
386 bool switchToDot = false;
387 AST_MEMBER(ColonChainItem, &name)
388AST_END(ColonChainItem)
389
390class default_value_t;
391
392AST_NODE(Slice, "Slice"_id)
393 ast_sel<true, Exp_t, default_value_t> startValue;
394 ast_sel<true, Exp_t, default_value_t> stopValue;
395 ast_sel<true, Exp_t, default_value_t> stepValue;
396 AST_MEMBER(Slice, &startValue, &stopValue, &stepValue)
397AST_END(Slice)
398
399AST_NODE(Parens, "Parens"_id)
400 ast_ptr<true, Exp_t> expr;
401 AST_MEMBER(Parens, &expr)
402AST_END(Parens)
403
404AST_NODE(Invoke, "Invoke"_id)
405 ast_ptr<true, Seperator_t> sep;
406 ast_sel_list<false, Exp_t, SingleString_t, DoubleString_t, LuaString_t> args;
407 AST_MEMBER(Invoke, &sep, &args)
408AST_END(Invoke)
409
410class InvokeArgs_t;
411
412AST_NODE(ChainValue, "ChainValue"_id)
413 ast_ptr<true, Seperator_t> sep;
414 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t> items;
415 AST_MEMBER(ChainValue, &sep, &items)
416AST_END(ChainValue)
417
418AST_NODE(AssignableChain, "AssignableChain"_id)
419 ast_ptr<true, Seperator_t> sep;
420 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Exp_t, String_t> items;
421 AST_MEMBER(AssignableChain, &sep, &items)
422AST_END(AssignableChain)
423
424AST_NODE(Value, "Value"_id)
425 ast_sel<true, SimpleValue_t, simple_table_t, ChainValue_t, String_t> item;
426 AST_MEMBER(Value, &item)
427AST_END(Value)
428
429AST_LEAF(default_value, "default_value"_id)
430AST_END(default_value)
431
432AST_NODE(TableLit, "TableLit"_id)
433 ast_ptr<true, Seperator_t> sep;
434 ast_sel_list<false, variable_pair_t, normal_pair_t, Exp_t> values;
435 AST_MEMBER(TableLit, &sep, &values)
436AST_END(TableLit)
437
438AST_NODE(TableBlock, "TableBlock"_id)
439 ast_ptr<true, Seperator_t> sep;
440 ast_sel_list<false, variable_pair_t, normal_pair_t> values;
441 AST_MEMBER(TableBlock, &sep, &values)
442AST_END(TableBlock)
443
444AST_NODE(class_member_list, "class_member_list"_id)
445 ast_ptr<true, Seperator_t> sep;
446 ast_sel_list<true, variable_pair_t, normal_pair_t> values;
447 AST_MEMBER(class_member_list, &sep, &values)
448AST_END(class_member_list)
449
450AST_NODE(ClassBlock, "ClassBlock"_id)
451 ast_ptr<true, Seperator_t> sep;
452 ast_sel_list<true, class_member_list_t, Statement_t> contents;
453 AST_MEMBER(ClassBlock, &sep, &contents)
454AST_END(ClassBlock)
455
456AST_NODE(ClassDecl, "ClassDecl"_id)
457 ast_ptr<false, Assignable_t> name;
458 ast_ptr<false, Exp_t> extend;
459 ast_ptr<false, ClassBlock_t> body;
460 AST_MEMBER(ClassDecl, &name, &extend, &body)
461AST_END(ClassDecl)
462
463AST_NODE(export_values, "export_values"_id)
464 ast_ptr<true, NameList_t> nameList;
465 ast_ptr<false, ExpListLow_t> valueList;
466 AST_MEMBER(export_values, &nameList, &valueList)
467AST_END(export_values)
468
469AST_LEAF(export_op, "export_op"_id)
470AST_END(export_op)
471
472AST_NODE(Export, "Export"_id)
473 ast_sel<true, ClassDecl_t, export_op_t, export_values_t> item;
474 AST_MEMBER(Export, &item)
475AST_END(Export)
476
477AST_NODE(FnArgDef, "FnArgDef"_id)
478 ast_sel<true, Variable_t, SelfName_t> name;
479 ast_ptr<false, Exp_t> defaultValue;
480 AST_MEMBER(FnArgDef, &name, &defaultValue)
481AST_END(FnArgDef)
482
483AST_NODE(FnArgDefList, "FnArgDefList"_id)
484 ast_ptr<true, Seperator_t> sep;
485 ast_list<false, FnArgDef_t> definitions;
486 ast_ptr<false, VarArg_t> varArg;
487 AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg)
488AST_END(FnArgDefList)
489
490AST_NODE(outer_var_shadow, "outer_var_shadow"_id)
491 ast_ptr<false, NameList_t> varList;
492 AST_MEMBER(outer_var_shadow, &varList)
493AST_END(outer_var_shadow)
494
495AST_NODE(FnArgsDef, "FnArgsDef"_id)
496 ast_ptr<false, FnArgDefList_t> defList;
497 ast_ptr<false, outer_var_shadow_t> shadowOption;
498 AST_MEMBER(FnArgsDef, &defList, &shadowOption)
499AST_END(FnArgsDef)
500
501AST_LEAF(fn_arrow, "fn_arrow"_id)
502AST_END(fn_arrow)
503
504AST_NODE(FunLit, "FunLit"_id)
505 ast_ptr<false, FnArgsDef_t> argsDef;
506 ast_ptr<true, fn_arrow_t> arrow;
507 ast_ptr<false, Body_t> body;
508 AST_MEMBER(FunLit, &argsDef, &arrow, &body)
509AST_END(FunLit)
510
511AST_NODE(NameOrDestructure, "NameOrDestructure"_id)
512 ast_sel<true, Variable_t, TableLit_t> item;
513 AST_MEMBER(NameOrDestructure, &item)
514AST_END(NameOrDestructure)
515
516AST_NODE(AssignableNameList, "AssignableNameList"_id)
517 ast_ptr<true, Seperator_t> sep;
518 ast_list<true, NameOrDestructure_t> items;
519 AST_MEMBER(AssignableNameList, &sep, &items)
520AST_END(AssignableNameList)
521
522AST_NODE(InvokeArgs, "InvokeArgs"_id)
523 ast_ptr<true, Seperator_t> sep;
524 ast_sel_list<true, Exp_t, TableBlock_t> args;
525 AST_MEMBER(InvokeArgs, &sep, &args)
526AST_END(InvokeArgs)
527
528AST_LEAF(const_value, "const_value"_id)
529AST_END(const_value)
530
531AST_NODE(unary_exp, "unary_exp"_id)
532 ast_ptr<true, Exp_t> item;
533 AST_MEMBER(unary_exp, &item)
534AST_END(unary_exp)
535
536AST_NODE(ExpListAssign, "ExpListAssign"_id)
537 ast_ptr<true, ExpList_t> expList;
538 ast_sel<false, Update_t, Assign_t> action;
539 AST_MEMBER(ExpListAssign, &expList, &action)
540AST_END(ExpListAssign)
541
542AST_NODE(if_else_line, "if_else_line"_id)
543 ast_ptr<true, Exp_t> condition;
544 ast_sel<false, Exp_t, default_value_t> elseExpr;
545 AST_MEMBER(if_else_line, &condition, &elseExpr)
546AST_END(if_else_line)
547
548AST_NODE(unless_line, "unless_line"_id)
549 ast_ptr<true, Exp_t> condition;
550 AST_MEMBER(unless_line, &condition)
551AST_END(unless_line)
552
553AST_NODE(statement_appendix, "statement_appendix"_id)
554 ast_sel<true, if_else_line_t, unless_line_t, CompInner_t> item;
555 AST_MEMBER(statement_appendix, &item)
556AST_END(statement_appendix)
557
558AST_LEAF(BreakLoop, "BreakLoop"_id)
559AST_END(BreakLoop)
560
561AST_NODE(Statement, "Statement"_id)
562 ast_sel<true, Import_t, While_t, For_t, ForEach_t,
563 Return_t, Local_t, Export_t, BreakLoop_t,
564 ExpListAssign_t> content;
565 ast_ptr<false, statement_appendix_t> appendix;
566 AST_MEMBER(Statement, &content, &appendix)
567AST_END(Statement)
568
569class Block_t;
570
571AST_NODE(Body, "Body"_id)
572 ast_sel<true, Block_t, Statement_t> content;
573 AST_MEMBER(Body, &content)
574AST_END(Body)
575
576AST_NODE(Block, "Block"_id)
577 ast_ptr<true, Seperator_t> sep;
578 ast_list<false, Statement_t> statements;
579 AST_MEMBER(Block, &sep, &statements)
580AST_END(Block)
581
582AST_NODE(File, "File"_id)
583 ast_ptr<true, Block_t> block;
584 AST_MEMBER(File, &block)
585AST_END(File)
586
587} // namespace MoonP
diff --git a/src/MoonP/moon_compiler.cpp b/src/MoonP/moon_compiler.cpp
new file mode 100644
index 0000000..f9a86a6
--- /dev/null
+++ b/src/MoonP/moon_compiler.cpp
@@ -0,0 +1,3865 @@
1/* Copyright (c) 2020 Jin Li, http://www.luvfight.me
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
5The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
7THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
8
9#include <string>
10#include <unordered_set>
11#include <unordered_map>
12#include <stack>
13#include <vector>
14#include <numeric>
15#include <memory>
16#include <sstream>
17#include <string_view>
18using namespace std::string_view_literals;
19#include "MoonP/parser.hpp"
20#include "MoonP/moon_ast.h"
21#include "MoonP/moon_compiler.h"
22
23namespace MoonP {
24
25#define BLOCK_START do {
26#define BLOCK_END } while (false);
27#define BREAK_IF(cond) if (cond) break
28
29typedef std::list<std::string> str_list;
30
31inline std::string s(std::string_view sv) {
32 return std::string(sv);
33}
34
35const char* moonScriptVersion() {
36 return "0.5.0";
37}
38
39class MoonCompliler {
40public:
41 std::pair<std::string,std::string> complile(const std::string& codes, const MoonConfig& config) {
42 _config = config;
43 try {
44 _input = _converter.from_bytes(codes);
45 } catch (const std::range_error&) {
46 return {Empty, "Invalid text encoding."};
47 }
48 error_list el;
49 State st;
50 ast_ptr<false, File_t> root;
51 try {
52 root = parse<File_t>(_input, File, el, &st);
53 } catch (const std::logic_error& error) {
54 clear();
55 return {Empty, error.what()};
56 }
57 if (root) {
58 try {
59 str_list out;
60 pushScope();
61 transformBlock(root->block, out, config.implicitReturnRoot);
62 popScope();
63 return {std::move(out.back()), Empty};
64 } catch (const std::logic_error& error) {
65 clear();
66 return {Empty, error.what()};
67 }
68 } else {
69 clearBuf();
70 for (error_list::iterator it = el.begin(); it != el.end(); ++it) {
71 const error& err = *it;
72 _buf << debugInfo("Syntax error."sv, &err);
73 }
74 std::pair<std::string,std::string> result{Empty, clearBuf()};
75 clear();
76 return result;
77 }
78 }
79
80 const std::unordered_map<std::string,std::pair<int,int>>& getGlobals() const {
81 return _globals;
82 }
83
84 void clear() {
85 _indentOffset = 0;
86 _scopes.clear();
87 _codeCache.clear();
88 std::stack<std::string> emptyWith;
89 _withVars.swap(emptyWith);
90 std::stack<std::string> emptyContinue;
91 _continueVars.swap(emptyContinue);
92 _buf.str("");
93 _buf.clear();
94 _joinBuf.str("");
95 _joinBuf.clear();
96 _globals.clear();
97 _input.clear();
98 }
99private:
100 MoonConfig _config;
101 int _indentOffset = 0;
102 Converter _converter;
103 input _input;
104 std::list<input> _codeCache;
105 std::stack<std::string> _withVars;
106 std::stack<std::string> _continueVars;
107 std::unordered_map<std::string,std::pair<int,int>> _globals;
108 std::ostringstream _buf;
109 std::ostringstream _joinBuf;
110 std::string _newLine = "\n";
111 enum class LocalMode {
112 None = 0,
113 Capital = 1,
114 Any = 2
115 };
116 enum class ExportMode {
117 None = 0,
118 Capital = 1,
119 Any = 2
120 };
121 struct Scope {
122 ExportMode mode = ExportMode::None;
123 std::unique_ptr<std::unordered_set<std::string>> vars;
124 std::unique_ptr<std::unordered_set<std::string>> allows;
125 std::unique_ptr<std::unordered_set<std::string>> exports;
126 };
127 std::list<Scope> _scopes;
128 static const std::string Empty;
129
130 enum class MemType {
131 Builtin,
132 Common,
133 Property
134 };
135
136 struct ClassMember {
137 std::string item;
138 MemType type;
139 ast_node* node;
140 };
141
142 struct DestructItem {
143 bool isVariable = false;
144 std::string name;
145 std::string structure;
146 };
147
148 struct Destructure {
149 std::string value;
150 std::list<DestructItem> items;
151 };
152
153 enum class ExpUsage {
154 Return,
155 Assignment,
156 Common,
157 Closure
158 };
159
160 void pushScope() {
161 _scopes.emplace_back();
162 _scopes.back().vars = std::make_unique<std::unordered_set<std::string>>();
163 }
164
165 void popScope() {
166 _scopes.pop_back();
167 }
168
169 bool isDefined(const std::string& name) {
170 bool isDefined = false;
171 int mode = int(std::isupper(name[0]) ? ExportMode::Capital : ExportMode::Any);
172 const auto& current = _scopes.back();
173 if (int(current.mode) >= mode) {
174 if (current.exports) {
175 if (current.exports->find(name) != current.exports->end()) {
176 isDefined = true;
177 current.vars->insert(name);
178 }
179 } else {
180 isDefined = true;
181 current.vars->insert(name);
182 }
183 }
184 decltype(_scopes.back().allows.get()) allows = nullptr;
185 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
186 if (it->allows) allows = it->allows.get();
187 }
188 bool checkShadowScopeOnly = false;
189 if (allows) {
190 checkShadowScopeOnly = allows->find(name) == allows->end();
191 }
192 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
193 auto vars = it->vars.get();
194 if (vars->find(name) != vars->end()) {
195 isDefined = true;
196 break;
197 }
198 if (checkShadowScopeOnly && it->allows) break;
199 }
200 return isDefined;
201 }
202
203 bool isSolidDefined(const std::string& name) {
204 bool isDefined = false;
205 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
206 auto vars = it->vars.get();
207 if (vars->find(name) != vars->end()) {
208 isDefined = true;
209 break;
210 }
211 }
212 return isDefined;
213 }
214
215 void markVarShadowed() {
216 auto& scope = _scopes.back();
217 scope.allows = std::make_unique<std::unordered_set<std::string>>();
218 }
219
220 void markVarExported(ExportMode mode, bool specified) {
221 auto& scope = _scopes.back();
222 scope.mode = mode;
223 if (specified && !scope.exports) {
224 scope.exports = std::make_unique<std::unordered_set<std::string>>();
225 }
226 }
227
228 void addExportedVar(const std::string& name) {
229 auto& scope = _scopes.back();
230 scope.exports->insert(name);
231 }
232
233 void addToAllowList(const std::string& name) {
234 auto& scope = _scopes.back();
235 scope.allows->insert(name);
236 }
237
238 void forceAddToScope(const std::string& name) {
239 auto& scope = _scopes.back();
240 scope.vars->insert(name);
241 }
242
243 Scope& currentScope() {
244 return _scopes.back();
245 }
246
247 bool addToScope(const std::string& name) {
248 bool defined = isDefined(name);
249 if (!defined) {
250 auto& scope = currentScope();
251 scope.vars->insert(name);
252 }
253 return !defined;
254 }
255
256 std::string getUnusedName(std::string_view name) {
257 int index = 0;
258 std::string newName;
259 do {
260 newName = s(name) + std::to_string(index);
261 index++;
262 } while (isSolidDefined(newName));
263 return newName;
264 }
265
266 const std::string nll(ast_node* node) {
267 if (_config.reserveLineNumber) {
268 return s(" -- "sv) + std::to_string(node->m_begin.m_line) + _newLine;
269 } else {
270 return _newLine;
271 }
272 }
273
274 const std::string nlr(ast_node* node) {
275 if (_config.reserveLineNumber) {
276 return s(" -- "sv) + std::to_string(node->m_end.m_line) + _newLine;
277 } else {
278 return _newLine;
279 }
280 }
281
282 void incIndentOffset() {
283 _indentOffset++;
284 }
285
286 void decIndentOffset() {
287 _indentOffset--;
288 }
289
290 std::string indent() {
291 return _config.spaceOverTab ? std::string((_scopes.size() - 1 + _indentOffset) * 2, ' ') : std::string(_scopes.size() - 1 + _indentOffset, '\t');
292 }
293
294 std::string indent(int offset) {
295 return _config.spaceOverTab ? std::string((_scopes.size() - 1 + _indentOffset + offset) * 2, ' ') : std::string(_scopes.size() - 1 + _indentOffset + offset, '\t');
296 }
297
298 std::string clearBuf() {
299 std::string str = _buf.str();
300 _buf.str("");
301 _buf.clear();
302 return str;
303 }
304
305 std::string join(const str_list& items) {
306 if (items.empty()) return Empty;
307 else if (items.size() == 1) return items.front();
308 for (const auto& item : items) {
309 _joinBuf << item;
310 }
311 auto result = _joinBuf.str();
312 _joinBuf.str("");
313 _joinBuf.clear();
314 return result;
315 }
316
317 std::string join(const str_list& items, std::string_view sep) {
318 if (items.empty()) return Empty;
319 else if (items.size() == 1) return items.front();
320 std::string sepStr = s(sep);
321 auto begin = ++items.begin();
322 _joinBuf << items.front();
323 for (auto it = begin; it != items.end(); ++it) {
324 _joinBuf << sepStr << *it;
325 }
326 auto result = _joinBuf.str();
327 _joinBuf.str("");
328 _joinBuf.clear();
329 return result;
330 }
331
332 std::string toString(ast_node* node) {
333 return _converter.to_bytes(std::wstring(node->m_begin.m_it, node->m_end.m_it));
334 }
335
336 std::string toString(input::iterator begin, input::iterator end) {
337 return _converter.to_bytes(std::wstring(begin, end));
338 }
339
340 Value_t* singleValueFrom(ast_node* item) {
341 Exp_t* exp = nullptr;
342 switch (item->getId()) {
343 case "Exp"_id:
344 exp = static_cast<Exp_t*>(item);
345 break;
346 case "ExpList"_id: {
347 auto expList = static_cast<ExpList_t*>(item);
348 if (expList->exprs.size() == 1) {
349 exp = static_cast<Exp_t*>(expList->exprs.front());
350 }
351 break;
352 }
353 case "ExpListLow"_id: {
354 auto expList = static_cast<ExpListLow_t*>(item);
355 if (expList->exprs.size() == 1) {
356 exp = static_cast<Exp_t*>(expList->exprs.front());
357 }
358 break;
359 }
360 }
361 if (!exp) return nullptr;
362 if (exp->opValues.empty()) {
363 return exp->value.get();
364 }
365 return nullptr;
366 }
367
368 SimpleValue_t* simpleSingleValueFrom(ast_node* expList) {
369 auto value = singleValueFrom(expList);
370 if (value && value->item.is<SimpleValue_t>()) {
371 return static_cast<SimpleValue_t*>(value->item.get());
372 }
373 return nullptr;
374 }
375
376 Value_t* firstValueFrom(ast_node* item) {
377 Exp_t* exp = nullptr;
378 if (auto expList = ast_cast<ExpList_t>(item)) {
379 if (!expList->exprs.empty()) {
380 exp = static_cast<Exp_t*>(expList->exprs.front());
381 }
382 } else {
383 exp = ast_cast<Exp_t>(item);
384 }
385 return exp->value.get();
386 }
387
388 Statement_t* lastStatementFrom(Body_t* body) {
389 if (auto stmt = body->content.as<Statement_t>()) {
390 return stmt;
391 } else {
392 auto node = body->content.to<Block_t>()->statements.objects().back();
393 return static_cast<Statement_t*>(node);
394 }
395 }
396
397 Statement_t* lastStatementFrom(Block_t* block) {
398 auto node = block->statements.objects().back();
399 return static_cast<Statement_t*>(node);
400 }
401
402 template <class T>
403 ast_ptr<false, T> toAst(std::string_view codes, rule& r, ast_node* parent) {
404 _codeCache.push_back(_converter.from_bytes(s(codes)));
405 error_list el;
406 State st;
407 auto ptr = parse<T>(_codeCache.back(), r, el, &st);
408 ptr->traverse([&](ast_node* node) {
409 node->m_begin.m_line = parent->m_begin.m_line;
410 node->m_end.m_line = parent->m_begin.m_line;
411 return traversal::Continue;
412 });
413 return ptr;
414 }
415
416 bool matchAst(rule& r, std::string_view codes) {
417 error_list el;
418 State st;
419 input i = _converter.from_bytes(s(codes));
420 auto rEnd = rule(r >> eof());
421 ast_ptr<false, ast_node> result(_parse(i, rEnd, el, &st));
422 return result;
423 }
424
425 bool isChainValueCall(ChainValue_t* chainValue) {
426 return ast_is<InvokeArgs_t, Invoke_t>(chainValue->items.back());
427 }
428
429 std::string singleVariableFrom(ast_node* expList) {
430 if (!ast_is<Exp_t, ExpList_t>(expList)) return Empty;
431 BLOCK_START
432 auto value = singleValueFrom(expList);
433 BREAK_IF(!value);
434 auto chainValue = value->getByPath<ChainValue_t>();
435 BREAK_IF(!chainValue);
436 BREAK_IF(chainValue->items.size() != 1);
437 auto callable = ast_cast<Callable_t>(chainValue->items.front());
438 BREAK_IF(!callable || !callable->item.is<Variable_t>());
439 str_list tmp;
440 transformCallable(callable, tmp, false);
441 return tmp.back();
442 BLOCK_END
443 return Empty;
444 }
445
446 bool isColonChain(ChainValue_t* chainValue) {
447 return ast_is<ColonChainItem_t>(chainValue->items.back());
448 }
449
450 bool hasKeywordColonChainItem(ChainValue_t* chainValue) {
451 const auto& chainList = chainValue->items.objects();
452 for (auto it = chainList.begin(); it != chainList.end(); ++it) {
453 if (auto colonItem = ast_cast<ColonChainItem_t>(*it)) {
454 if (colonItem->name.is<LuaKeyword_t>()) {
455 return true;
456 }
457 }
458 }
459 return false;
460 }
461
462 bool isAssignable(const node_container& chainItems) {
463 if (chainItems.size() == 1) {
464 auto firstItem = chainItems.back();
465 if (auto callable = ast_cast<Callable_t>(firstItem)) {
466 switch (callable->item->getId()) {
467 case "Variable"_id:
468 case "SelfName"_id:
469 return true;
470 }
471 } else if (firstItem->getId() == "DotChainItem"_id) {
472 return true;
473 }
474 } else {
475 auto lastItem = chainItems.back();
476 switch (lastItem->getId()) {
477 case "DotChainItem"_id:
478 case "Exp"_id:
479 return true;
480 }
481 }
482 return false;
483 }
484
485 bool isAssignable(Exp_t* exp) {
486 if (auto value = singleValueFrom(exp)) {
487 auto item = value->item.get();
488 switch (item->getId()) {
489 case "simple_table"_id:
490 return true;
491 case "SimpleValue"_id: {
492 auto simpleValue = static_cast<SimpleValue_t*>(item);
493 if (simpleValue->value.is<TableLit_t>()) {
494 return true;
495 }
496 return false;
497 }
498 case "ChainValue"_id: {
499 auto chainValue = static_cast<ChainValue_t*>(item);
500 return isAssignable(chainValue->items.objects());
501 }
502 }
503 }
504 return false;
505 }
506
507 bool isAssignable(Assignable_t* assignable) {
508 if (auto assignableChain = ast_cast<AssignableChain_t>(assignable->item)) {
509 return isAssignable(assignableChain->items.objects());
510 }
511 return true;
512 }
513
514 void checkAssignable(ExpList_t* expList) {
515 for (auto exp_ : expList->exprs.objects()) {
516 Exp_t* exp = static_cast<Exp_t*>(exp_);
517 if (!isAssignable(exp)) {
518 throw std::logic_error(debugInfo("Left hand expression is not assignable."sv, exp));
519 }
520 }
521 }
522
523 std::string debugInfo(std::string_view msg, const input_range* loc) {
524 const int ASCII = 255;
525 int length = loc->m_begin.m_line;
526 auto begin = _input.begin();
527 auto end = _input.end();
528 int count = 0;
529 for (auto it = _input.begin(); it != _input.end(); ++it) {
530 if (*it == '\n') {
531 if (count + 1 == length) {
532 end = it;
533 break;
534 } else {
535 begin = it + 1;
536 }
537 count++;
538 }
539 }
540 auto line = _converter.to_bytes(std::wstring(begin, end));
541 int oldCol = loc->m_begin.m_col;
542 int col = loc->m_begin.m_col - 1;
543 auto it = begin;
544 for (int i = 0; i < oldCol; ++i) {
545 if (*it > ASCII) {
546 ++col;
547 }
548 ++it;
549 }
550 replace(line, "\t"sv, " "sv);
551 std::ostringstream buf;
552 buf << loc->m_begin.m_line << ": "sv << msg <<
553 '\n' << line << '\n' << std::string(col, ' ') << "^"sv;
554 return buf.str();
555 }
556
557 void transformStatement(Statement_t* statement, str_list& out) {
558 auto x = statement;
559 if (statement->appendix) {
560 if (auto assignment = assignmentFrom(statement)) {
561 auto preDefine = getPredefine(transformAssignDefs(assignment->expList));
562 if (!preDefine.empty()) out.push_back(preDefine + nll(statement));
563 }
564 auto appendix = statement->appendix.get();
565 switch (appendix->item->getId()) {
566 case "if_else_line"_id: {
567 auto if_else_line = appendix->item.to<if_else_line_t>();
568 auto ifNode = x->new_ptr<If_t>();
569
570 auto ifCond = x->new_ptr<IfCond_t>();
571 ifCond->condition.set(if_else_line->condition);
572 ifNode->nodes.push_back(ifCond);
573
574 auto stmt = x->new_ptr<Statement_t>();
575 stmt->content.set(statement->content);
576 auto body = x->new_ptr<Body_t>();
577 body->content.set(stmt);
578 ifNode->nodes.push_back(body);
579
580 if (!ast_is<default_value_t>(if_else_line->elseExpr)) {
581 auto expList = x->new_ptr<ExpList_t>();
582 expList->exprs.push_back(if_else_line->elseExpr);
583 auto expListAssign = x->new_ptr<ExpListAssign_t>();
584 expListAssign->expList.set(expList);
585 auto stmt = x->new_ptr<Statement_t>();
586 stmt->content.set(expListAssign);
587 auto body = x->new_ptr<Body_t>();
588 body->content.set(stmt);
589 ifNode->nodes.push_back(body);
590 }
591
592 statement->appendix.set(nullptr);
593 auto simpleValue = x->new_ptr<SimpleValue_t>();
594 simpleValue->value.set(ifNode);
595 auto value = x->new_ptr<Value_t>();
596 value->item.set(simpleValue);
597 auto exp = x->new_ptr<Exp_t>();
598 exp->value.set(value);
599 auto expList = x->new_ptr<ExpList_t>();
600 expList->exprs.push_back(exp);
601 auto expListAssign = x->new_ptr<ExpListAssign_t>();
602 expListAssign->expList.set(expList);
603 statement->content.set(expListAssign);
604 break;
605 }
606 case "unless_line"_id: {
607 auto unless_line = appendix->item.to<unless_line_t>();
608 auto unless = x->new_ptr<Unless_t>();
609
610 auto ifCond = x->new_ptr<IfCond_t>();
611 ifCond->condition.set(unless_line->condition);
612 unless->nodes.push_back(ifCond);
613
614 auto stmt = x->new_ptr<Statement_t>();
615 stmt->content.set(statement->content);
616 auto body = x->new_ptr<Body_t>();
617 body->content.set(stmt);
618 unless->nodes.push_back(body);
619
620 statement->appendix.set(nullptr);
621 auto simpleValue = x->new_ptr<SimpleValue_t>();
622 simpleValue->value.set(unless);
623 auto value = x->new_ptr<Value_t>();
624 value->item.set(simpleValue);
625 auto exp = x->new_ptr<Exp_t>();
626 exp->value.set(value);
627 auto exprList = x->new_ptr<ExpList_t>();
628 exprList->exprs.push_back(exp);
629 auto expListAssign = x->new_ptr<ExpListAssign_t>();
630 expListAssign->expList.set(exprList);
631 statement->content.set(expListAssign);
632 break;
633 }
634 case "CompInner"_id: {
635 auto compInner = appendix->item.to<CompInner_t>();
636 auto comp = x->new_ptr<Comprehension_t>();
637 comp->forLoop.set(compInner);
638 auto stmt = x->new_ptr<Statement_t>();
639 stmt->content.set(statement->content);
640 comp->value.set(stmt);
641 auto simpleValue = x->new_ptr<SimpleValue_t>();
642 simpleValue->value.set(comp);
643 auto value = x->new_ptr<Value_t>();
644 value->item.set(simpleValue);
645 auto exp = x->new_ptr<Exp_t>();
646 exp->value.set(value);
647 auto expList = x->new_ptr<ExpList_t>();
648 expList->exprs.push_back(exp);
649 auto expListAssign = x->new_ptr<ExpListAssign_t>();
650 expListAssign->expList.set(expList);
651 statement->content.set(expListAssign);
652 statement->appendix.set(nullptr);
653 break;
654 }
655 default: break;
656 }
657 }
658 auto content = statement->content.get();
659 if (!content) {
660 out.push_back(Empty);
661 return;
662 }
663 switch (content->getId()) {
664 case "Import"_id: transformImport(static_cast<Import_t*>(content), out); break;
665 case "While"_id: transformWhile(static_cast<While_t*>(content), out); break;
666 case "For"_id: transformFor(static_cast<For_t*>(content), out); break;
667 case "ForEach"_id: transformForEach(static_cast<ForEach_t*>(content), out); break;
668 case "Return"_id: transformReturn(static_cast<Return_t*>(content), out); break;
669 case "Local"_id: transformLocal(static_cast<Local_t*>(content), out); break;
670 case "Export"_id: transformExport(static_cast<Export_t*>(content), out); break;
671 case "BreakLoop"_id: transformBreakLoop(static_cast<BreakLoop_t*>(content), out); break;
672 case "ExpListAssign"_id: {
673 auto expListAssign = static_cast<ExpListAssign_t*>(content);
674 if (expListAssign->action) {
675 transformAssignment(expListAssign, out);
676 } else {
677 auto expList = expListAssign->expList.get();
678 if (expList->exprs.objects().empty()) {
679 out.push_back(Empty);
680 break;
681 }
682 if (auto singleValue = singleValueFrom(expList)) {
683 if (auto simpleValue = singleValue->item.as<SimpleValue_t>()) {
684 auto value = simpleValue->value.get();
685 bool specialSingleValue = true;
686 switch (value->getId()) {
687 case "If"_id: transformIf(static_cast<If_t*>(value), out); break;
688 case "ClassDecl"_id: transformClassDecl(static_cast<ClassDecl_t*>(value), out); break;
689 case "Unless"_id: transformUnless(static_cast<Unless_t*>(value), out); break;
690 case "Switch"_id: transformSwitch(static_cast<Switch_t*>(value), out); break;
691 case "With"_id: transformWith(static_cast<With_t*>(value), out); break;
692 case "ForEach"_id: transformForEach(static_cast<ForEach_t*>(value), out); break;
693 case "For"_id: transformFor(static_cast<For_t*>(value), out); break;
694 case "While"_id: transformWhile(static_cast<While_t*>(value), out); break;
695 case "Do"_id: transformDo(static_cast<Do_t*>(value), out); break;
696 case "Comprehension"_id: transformCompCommon(static_cast<Comprehension_t*>(value), out); break;
697 default: specialSingleValue = false; break;
698 }
699 if (specialSingleValue) {
700 break;
701 }
702 }
703 if (auto chainValue = singleValue->item.as<ChainValue_t>()) {
704 if (isChainValueCall(chainValue)) {
705 transformChainValue(chainValue, out, ExpUsage::Common);
706 break;
707 }
708 }
709 }
710 if (_config.allowExprNotInTheEndOfBody) {
711 auto assign = x->new_ptr<Assign_t>();
712 assign->values.dup(expList->exprs);
713 auto assignment = x->new_ptr<ExpListAssign_t>();
714 assignment->expList.set(toAst<ExpList_t>("_", ExpList, x));
715 assignment->action.set(assign);
716 transformAssignment(assignment, out);
717 } else {
718 throw std::logic_error(debugInfo("Expression list must appear at the end of body block."sv, expList));
719 }
720 }
721 break;
722 }
723 default: break;
724 }
725 }
726
727 str_list getAssignVars(ExpListAssign_t* assignment) {
728 str_list vars;
729 if (!assignment->action.is<Assign_t>()) return vars;
730 for (auto exp : assignment->expList->exprs.objects()) {
731 auto var = singleVariableFrom(exp);
732 vars.push_back(var.empty() ? Empty : var);
733 }
734 return vars;
735 }
736
737 str_list getAssignVars(With_t* with) {
738 str_list vars;
739 for (auto exp : with->valueList->exprs.objects()) {
740 auto var = singleVariableFrom(exp);
741 vars.push_back(var.empty() ? Empty : var);
742 }
743 return vars;
744 }
745
746 str_list getAssignDefs(ExpList_t* expList) {
747 str_list preDefs;
748 for (auto exp_ : expList->exprs.objects()) {
749 auto exp = static_cast<Exp_t*>(exp_);
750 if (auto value = singleValueFrom(exp)) {
751 if (auto chain = value->item.as<ChainValue_t>()) {
752 BLOCK_START
753 BREAK_IF(chain->items.size() != 1);
754 auto callable = ast_cast<Callable_t>(chain->items.front());
755 BREAK_IF(!callable);
756 auto var = callable->item.as<Variable_t>();
757 BREAK_IF(!var);
758 auto name = toString(var);
759 if (!isDefined(name)) {
760 preDefs.push_back(name);
761 }
762 BLOCK_END
763 }
764 } else {
765 throw std::logic_error(debugInfo("Left hand expression is not assignable."sv, exp));
766 }
767 }
768 return preDefs;
769 }
770
771 str_list transformAssignDefs(ExpList_t* expList) {
772 str_list preDefs;
773 for (auto exp_ : expList->exprs.objects()) {
774 auto exp = static_cast<Exp_t*>(exp_);
775 if (auto value = singleValueFrom(exp)) {
776 if (auto chain = value->item.as<ChainValue_t>()) {
777 BLOCK_START
778 BREAK_IF(chain->items.size() != 1);
779 auto callable = ast_cast<Callable_t>(chain->items.front());
780 BREAK_IF(!callable);
781 auto var = callable->item.as<Variable_t>();
782 BREAK_IF(!var);
783 auto name = toString(var);
784 if (addToScope(name)) {
785 preDefs.push_back(name);
786 }
787 BLOCK_END
788 }
789 } else {
790 throw std::logic_error(debugInfo("Left hand expression is not assignable."sv, exp));
791 }
792 }
793 return preDefs;
794 }
795
796 std::string getPredefine(const str_list& defs) {
797 if (defs.empty()) return Empty;
798 return indent() + s("local "sv) + join(defs, ", "sv);
799 }
800
801 std::string getDestrucureDefine(ExpListAssign_t* assignment) {
802 auto info = extractDestructureInfo(assignment);
803 if (!info.first.empty()) {
804 for (const auto& destruct : info.first) {
805 str_list defs;
806 for (const auto& item : destruct.items) {
807 if (item.isVariable && addToScope(item.name)) {
808 defs.push_back(item.name);
809 }
810 }
811 if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv);
812 }
813 }
814 return clearBuf();
815 }
816
817 std::string getPredefine(ExpListAssign_t* assignment) {
818 auto preDefine = getDestrucureDefine(assignment);
819 if (preDefine.empty()) {
820 preDefine = getPredefine(transformAssignDefs(assignment->expList));
821 }
822 return preDefine.empty() ? preDefine : preDefine + nll(assignment);
823 }
824
825 ExpList_t* expListFrom(Statement_t* statement) {
826 if (auto expListAssign = statement->content.as<ExpListAssign_t>()) {
827 if (!expListAssign->action) {
828 return expListAssign->expList.get();
829 }
830 }
831 return nullptr;
832 }
833
834 ExpListAssign_t* assignmentFrom(Statement_t* statement) {
835 if (auto expListAssign = statement->content.as<ExpListAssign_t>()) {
836 if (expListAssign->action) {
837 return expListAssign;
838 }
839 }
840 return nullptr;
841 }
842
843 void assignLastExplist(ExpList_t* expList, Body_t* body) {
844 auto last = lastStatementFrom(body);
845 if (!last) return;
846 bool lastAssignable = expListFrom(last) || ast_is<For_t, ForEach_t, While_t>(last->content);
847 if (lastAssignable) {
848 auto x = last;
849 auto newAssignment = x->new_ptr<ExpListAssign_t>();
850 newAssignment->expList.set(expList);
851 auto assign = x->new_ptr<Assign_t>();
852 if (auto valueList = last->content.as<ExpListAssign_t>()) {
853 assign->values.dup(valueList->expList->exprs);
854 } else {
855 auto simpleValue = x->new_ptr<SimpleValue_t>();
856 simpleValue->value.set(last->content);
857 auto value = x->new_ptr<Value_t>();
858 value->item.set(simpleValue);
859 auto exp = x->new_ptr<Exp_t>();
860 exp->value.set(value);
861 assign->values.push_back(exp);
862 }
863 newAssignment->action.set(assign);
864 last->content.set(newAssignment);
865 }
866 }
867
868 void transformAssignment(ExpListAssign_t* assignment, str_list& out) {
869 checkAssignable(assignment->expList);
870 BLOCK_START
871 auto assign = ast_cast<Assign_t>(assignment->action);
872 BREAK_IF(!assign || assign->values.objects().size() != 1);
873 auto value = assign->values.objects().front();
874 if (ast_is<Exp_t>(value)) {
875 if (auto val = simpleSingleValueFrom(value)) {
876 value = val->value.get();
877 }
878 }
879 switch (value->getId()) {
880 case "If"_id:
881 case "Unless"_id: {
882 auto expList = assignment->expList.get();
883 str_list temp;
884 auto defs = transformAssignDefs(expList);
885 if (!defs.empty()) temp.push_back(getPredefine(defs) + nll(expList));
886 value->traverse([&](ast_node* node) {
887 switch (node->getId()) {
888 case "IfCond"_id: return traversal::Return;
889 case "Body"_id: {
890 auto body = static_cast<Body_t*>(node);
891 assignLastExplist(expList, body);
892 return traversal::Return;
893 }
894 default: return traversal::Continue;
895 }
896 });
897 switch (value->getId()) {
898 case "If"_id: transformIf(static_cast<If_t*>(value), temp); break;
899 case "Unless"_id: transformUnless(static_cast<Unless_t*>(value), temp); break;
900 }
901 out.push_back(join(temp));
902 return;
903 }
904 case "Switch"_id: {
905 auto switchNode = static_cast<Switch_t*>(value);
906 auto expList = assignment->expList.get();
907 for (auto branch_ : switchNode->branches.objects()) {
908 auto branch = static_cast<SwitchCase_t*>(branch_);
909 assignLastExplist(expList, branch->body);
910 }
911 if (switchNode->lastBranch) {
912 assignLastExplist(expList, switchNode->lastBranch);
913 }
914 std::string preDefine = getPredefine(assignment);
915 transformSwitch(switchNode, out);
916 out.back() = preDefine + out.back();
917 return;
918 }
919 case "With"_id: {
920 auto withNode = static_cast<With_t*>(value);
921 str_list temp;
922 auto expList = assignment->expList.get();
923 std::string preDefine = getPredefine(assignment);
924 transformWith(withNode, temp, expList);
925 out.push_back(preDefine + temp.back());
926 return;
927 }
928 case "Do"_id: {
929 auto doNode = static_cast<Do_t*>(value);
930 auto expList = assignment->expList.get();
931 assignLastExplist(expList, doNode->body);
932 std::string preDefine = getPredefine(assignment);
933 transformDo(doNode, out);
934 out.back() = preDefine + out.back();
935 return;
936 }
937 case "Comprehension"_id: {
938 auto expList = assignment->expList.get();
939 std::string preDefine = getPredefine(assignment);
940 transformCompInPlace(static_cast<Comprehension_t*>(value), expList, out);
941 out.back() = preDefine + out.back();
942 return;
943 }
944 case "TblComprehension"_id: {
945 auto expList = assignment->expList.get();
946 std::string preDefine = getPredefine(assignment);
947 transformTblCompInPlace(static_cast<TblComprehension_t*>(value), expList, out);
948 out.back() = preDefine + out.back();
949 return;
950 }
951 case "For"_id: {
952 str_list temp;
953 auto expList = assignment->expList.get();
954 std::string preDefine = getPredefine(assignment);
955 transformForInPlace(static_cast<For_t*>(value), temp, expList);
956 out.push_back(preDefine + temp.back());
957 return;
958 }
959 case "ForEach"_id: {
960 str_list temp;
961 auto expList = assignment->expList.get();
962 std::string preDefine = getPredefine(assignment);
963 transformForEachInPlace(static_cast<ForEach_t*>(value), temp, expList);
964 out.push_back(preDefine + temp.back());
965 return;
966 }
967 case "ClassDecl"_id: {
968 str_list temp;
969 auto expList = assignment->expList.get();
970 std::string preDefine = getPredefine(assignment);
971 transformClassDecl(static_cast<ClassDecl_t*>(value), temp, ExpUsage::Assignment, expList);
972 out.push_back(preDefine + temp.back());
973 return;
974 }
975 case "While"_id: {
976 str_list temp;
977 auto expList = assignment->expList.get();
978 std::string preDefine = getPredefine(assignment);
979 transformWhileInPlace(static_cast<While_t*>(value), temp, expList);
980 out.push_back(preDefine + temp.back());
981 return;
982 }
983 }
984 auto exp = ast_cast<Exp_t>(value);
985 BREAK_IF(!exp);
986 if (auto chainValue = exp->value->item.as<ChainValue_t>()) {
987 if (isColonChain(chainValue)) {
988 auto assignable = assignment->expList.get();
989 std::string preDefine = getPredefine(transformAssignDefs(assignable));
990 transformColonChain(chainValue, out, ExpUsage::Assignment, assignable);
991 auto nl = preDefine.empty() ? Empty : nll(chainValue);
992 if (!preDefine.empty()) out.back() = preDefine + nl + out.back();
993 return;
994 } else if (hasKeywordColonChainItem(chainValue)) {
995 transformChainValue(chainValue, out, ExpUsage::Assignment, assignment->expList);
996 return;
997 }
998 }
999 BLOCK_END
1000 auto info = extractDestructureInfo(assignment);
1001 if (info.first.empty()) {
1002 transformAssignmentCommon(assignment, out);
1003 } else {
1004 str_list temp;
1005 for (const auto& destruct : info.first) {
1006 if (destruct.items.size() == 1) {
1007 auto& pair = destruct.items.front();
1008 _buf << indent();
1009 if (pair.isVariable && !isDefined(pair.name)) {
1010 _buf << s("local "sv);
1011 }
1012 _buf << pair.name << " = "sv << info.first.front().value << pair.structure << nll(assignment);
1013 addToScope(pair.name);
1014 temp.push_back(clearBuf());
1015 } else if (matchAst(Name, destruct.value)) {
1016 str_list defs, names, values;
1017 for (const auto& item : destruct.items) {
1018 if (item.isVariable && addToScope(item.name)) {
1019 defs.push_back(item.name);
1020 }
1021 names.push_back(item.name);
1022 values.push_back(item.structure);
1023 }
1024 for (auto& v : values) v.insert(0, destruct.value);
1025 if (defs.empty()) {
1026 _buf << indent() << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment);
1027 } else {
1028 _buf << indent() << "local "sv;
1029 if (defs.size() != names.size()) {
1030 _buf << join(defs,", "sv) << nll(assignment) << indent();
1031 }
1032 _buf << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment);
1033 }
1034 temp.push_back(clearBuf());
1035 } else {
1036 str_list defs, names, values;
1037 for (const auto& item : destruct.items) {
1038 if (item.isVariable && addToScope(item.name)) {
1039 defs.push_back(item.name);
1040 }
1041 names.push_back(item.name);
1042 values.push_back(item.structure);
1043 }
1044 if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv) << nll(assignment);
1045 _buf << indent() << "do"sv << nll(assignment);
1046 pushScope();
1047 auto objVar = getUnusedName("_obj_");
1048 for (auto& v : values) v.insert(0, objVar);
1049 _buf << indent() << "local "sv << objVar << " = "sv << destruct.value << nll(assignment);
1050 _buf << indent() << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment);
1051 popScope();
1052 _buf << indent() << "end"sv << nll(assignment);
1053 temp.push_back(clearBuf());
1054 }
1055 }
1056 if (info.second) {
1057 transformAssignmentCommon(info.second, temp);
1058 }
1059 out.push_back(join(temp));
1060 }
1061 }
1062
1063 void transformAssignItem(ast_node* value, str_list& out) {
1064 switch (value->getId()) {
1065 case "With"_id: transformWithClosure(static_cast<With_t*>(value), out); break;
1066 case "If"_id: transformIf(static_cast<If_t*>(value), out, ExpUsage::Closure); break;
1067 case "Switch"_id: transformSwitchClosure(static_cast<Switch_t*>(value), out); break;
1068 case "TableBlock"_id: transformTableBlock(static_cast<TableBlock_t*>(value), out); break;
1069 case "Exp"_id: transformExp(static_cast<Exp_t*>(value), out); break;
1070 default: break;
1071 }
1072 }
1073
1074 std::list<DestructItem> destructFromExp(ast_node* node) {
1075 const node_container* tableItems = nullptr;
1076 if (ast_cast<Exp_t>(node)) {
1077 auto item = singleValueFrom(node)->item.get();
1078 if (!item) throw std::logic_error(debugInfo("Invalid destructure value."sv, node));
1079 auto tbA = item->getByPath<TableLit_t>();
1080 if (tbA) {
1081 tableItems = &tbA->values.objects();
1082 } else {
1083 auto tbB = ast_cast<simple_table_t>(item);
1084 if (tbB) tableItems = &tbB->pairs.objects();
1085 }
1086 } else if (auto table = ast_cast<TableBlock_t>(node)) {
1087 tableItems = &table->values.objects();
1088 }
1089 std::list<DestructItem> pairs;
1090 int index = 0;
1091 for (auto pair : *tableItems) {
1092 switch (pair->getId()) {
1093 case "Exp"_id: {
1094 ++index;
1095 if (!isAssignable(static_cast<Exp_t*>(pair))) {
1096 throw std::logic_error(debugInfo("Can't destructure value."sv, pair));
1097 }
1098 auto value = singleValueFrom(pair);
1099 auto item = value->item.get();
1100 if (ast_cast<simple_table_t>(item) ||
1101 item->getByPath<TableLit_t>()) {
1102 auto subPairs = destructFromExp(pair);
1103 for (auto& p : subPairs) {
1104 pairs.push_back({p.isVariable, p.name,
1105 s("["sv) + std::to_string(index) + s("]"sv) + p.structure});
1106 }
1107 } else {
1108 bool lintGlobal = _config.lintGlobalVariable;
1109 _config.lintGlobalVariable = false;
1110 auto exp = static_cast<Exp_t*>(pair);
1111 auto varName = singleVariableFrom(exp);
1112 bool isVariable = !varName.empty();
1113 if (!isVariable) {
1114 str_list temp;
1115 transformExp(exp, temp);
1116 varName = std::move(temp.back());
1117 }
1118 _config.lintGlobalVariable = lintGlobal;
1119 pairs.push_back({
1120 isVariable,
1121 varName,
1122 s("["sv) + std::to_string(index) + s("]"sv)
1123 });
1124 }
1125 break;
1126 }
1127 case "variable_pair"_id: {
1128 auto vp = static_cast<variable_pair_t*>(pair);
1129 auto name = toString(vp->name);
1130 pairs.push_back({true, name, s("."sv) + name});
1131 break;
1132 }
1133 case "normal_pair"_id: {
1134 auto np = static_cast<normal_pair_t*>(pair);
1135 auto key = np->key->getByPath<Name_t>();
1136 if (!key) throw std::logic_error(debugInfo("Invalid key for destructure."sv, np));
1137 if (auto exp = np->value.as<Exp_t>()) {
1138 if (!isAssignable(exp)) throw std::logic_error(debugInfo("Can't destructure value."sv, exp));
1139 auto item = singleValueFrom(exp)->item.get();
1140 if (ast_cast<simple_table_t>(item) ||
1141 item->getByPath<TableLit_t>()) {
1142 auto subPairs = destructFromExp(exp);
1143 for (auto& p : subPairs) {
1144 pairs.push_back({p.isVariable, p.name,
1145 s("."sv) + toString(key) + p.structure});
1146 }
1147 } else {
1148 bool lintGlobal = _config.lintGlobalVariable;
1149 _config.lintGlobalVariable = false;
1150 auto varName = singleVariableFrom(exp);
1151 bool isVariable = !varName.empty();
1152 if (!isVariable) {
1153 str_list temp;
1154 transformExp(exp, temp);
1155 varName = std::move(temp.back());
1156 }
1157 _config.lintGlobalVariable = lintGlobal;
1158 pairs.push_back({
1159 isVariable,
1160 varName,
1161 s("."sv) + toString(key)
1162 });
1163 }
1164 break;
1165 }
1166 if (np->value.as<TableBlock_t>()) {
1167 auto subPairs = destructFromExp(pair);
1168 for (auto& p : subPairs) {
1169 pairs.push_back({p.isVariable, p.name,
1170 s("."sv) + toString(key) + p.structure});
1171 }
1172 }
1173 break;
1174 }
1175 }
1176 }
1177 return pairs;
1178 }
1179
1180 std::pair<std::list<Destructure>, ast_ptr<false, ExpListAssign_t>>
1181 extractDestructureInfo(ExpListAssign_t* assignment) {
1182 auto x = assignment;
1183 std::list<Destructure> destructs;
1184 if (!assignment->action.is<Assign_t>()) return { destructs, nullptr };
1185 auto exprs = assignment->expList->exprs.objects();
1186 auto values = assignment->action.to<Assign_t>()->values.objects();
1187 size_t size = std::max(exprs.size(),values.size());
1188 ast_ptr<false, Exp_t> var;
1189 if (exprs.size() < size) {
1190 var = toAst<Exp_t>("_"sv, Exp, x);
1191 while (exprs.size() < size) exprs.emplace_back(var);
1192 }
1193 ast_ptr<false, Exp_t> nullNode;
1194 if (values.size() < size) {
1195 nullNode = toAst<Exp_t>("nil"sv, Exp, x);
1196 while (values.size() < size) values.emplace_back(nullNode);
1197 }
1198 using iter = node_container::iterator;
1199 std::vector<std::pair<iter, iter>> destructPairs;
1200 str_list temp;
1201 for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) {
1202 auto expr = *i;
1203 ast_node* destructNode = expr->getByPath<Value_t, SimpleValue_t, TableLit_t>();
1204 if (destructNode || (destructNode = expr->getByPath<Value_t, simple_table_t>())) {
1205 destructPairs.push_back({i,j});
1206 pushScope();
1207 transformAssignItem(*j, temp);
1208 popScope();
1209 auto& destruct = destructs.emplace_back();
1210 destruct.value = temp.back();
1211 temp.pop_back();
1212 auto pairs = destructFromExp(expr);
1213 destruct.items = std::move(pairs);
1214 }
1215 }
1216 for (const auto& p : destructPairs) {
1217 exprs.erase(p.first);
1218 values.erase(p.second);
1219 }
1220 ast_ptr<false, ExpListAssign_t> newAssignment;
1221 if (!destructPairs.empty() && !exprs.empty()) {
1222 auto x = assignment;
1223 auto expList = x->new_ptr<ExpList_t>();
1224 auto newAssign = x->new_ptr<ExpListAssign_t>();
1225 newAssign->expList.set(expList);
1226 for (auto expr : exprs) expList->exprs.push_back(expr);
1227 auto assign = x->new_ptr<Assign_t>();
1228 for (auto value : values) assign->values.push_back(value);
1229 newAssign->action.set(assign);
1230 newAssignment = newAssign;
1231 }
1232 return {std::move(destructs), newAssignment};
1233 }
1234
1235 void transformAssignmentCommon(ExpListAssign_t* assignment, str_list& out) {
1236 auto x = assignment;
1237 str_list temp;
1238 auto expList = assignment->expList.get();
1239 auto action = assignment->action.get();
1240 switch (action->getId()) {
1241 case "Update"_id: {
1242 auto update = static_cast<Update_t*>(action);
1243 auto leftExp = static_cast<Exp_t*>(expList->exprs.objects().front());
1244 auto leftValue = singleValueFrom(leftExp);
1245 if (!leftValue) throw std::logic_error(debugInfo("Left hand expression is not assignable."sv, leftExp));
1246 if (auto chain = leftValue->getByPath<ChainValue_t>()) {
1247 auto tmpChain = x->new_ptr<ChainValue_t>();
1248 for (auto item : chain->items.objects()) {
1249 bool itemAdded = false;
1250 BLOCK_START
1251 auto exp = ast_cast<Exp_t>(item);
1252 BREAK_IF(!exp);
1253 auto var = singleVariableFrom(exp);
1254 BREAK_IF(!var.empty());
1255 auto upVar = getUnusedName("_update_");
1256 auto assignment = x->new_ptr<ExpListAssign_t>();
1257 assignment->expList.set(toAst<ExpList_t>(upVar, ExpList, x));
1258 auto assign = x->new_ptr<Assign_t>();
1259 assign->values.push_back(exp);
1260 assignment->action.set(assign);
1261 transformAssignment(assignment, temp);
1262 tmpChain->items.push_back(toAst<Exp_t>(upVar, Exp, x));
1263 itemAdded = true;
1264 BLOCK_END
1265 if (!itemAdded) tmpChain->items.push_back(item);
1266 }
1267 chain->items.clear();
1268 chain->items.dup(tmpChain->items);
1269 }
1270 transformValue(leftValue, temp);
1271 auto left = std::move(temp.back());
1272 temp.pop_back();
1273 transformExp(update->value, temp);
1274 auto right = std::move(temp.back());
1275 temp.pop_back();
1276 if (!singleValueFrom(update->value)) {
1277 right = s("("sv) + right + s(")"sv);
1278 }
1279 _buf << join(temp) << indent() << left << " = "sv << left <<
1280 " "sv << toString(update->op) << " "sv << right << nll(assignment);
1281 out.push_back(clearBuf());
1282 break;
1283 }
1284 case "Assign"_id: {
1285 auto defs = getAssignDefs(expList);
1286 bool oneLined = defs.size() == expList->exprs.objects().size() &&
1287 traversal::Stop != action->traverse([&](ast_node* n) {
1288 if (n->getId() == "Callable"_id) {
1289 if (auto name = n->getByPath<Variable_t>()) {
1290 for (const auto& def : defs) {
1291 if (def == toString(name)) {
1292 return traversal::Stop;
1293 }
1294 }
1295 }
1296 }
1297 return traversal::Continue;
1298 });
1299 if (oneLined) {
1300 auto assign = static_cast<Assign_t*>(action);
1301 for (auto value : assign->values.objects()) {
1302 transformAssignItem(value, temp);
1303 }
1304 std::string preDefine = getPredefine(defs);
1305 for (const auto& def : defs) {
1306 addToScope(def);
1307 }
1308 if (preDefine.empty()) {
1309 transformExpList(expList, temp);
1310 std::string left = std::move(temp.back());
1311 temp.pop_back();
1312 out.push_back(indent() + left + s(" = "sv) + join(temp, ", "sv) + nll(assignment));
1313 } else {
1314 out.push_back(preDefine + s(" = "sv) + join(temp, ", "sv) + nll(assignment));
1315 }
1316 }
1317 else {
1318 std::string preDefine = getPredefine(defs);
1319 for (const auto& def : defs) {
1320 addToScope(def);
1321 }
1322 transformExpList(expList, temp);
1323 std::string left = temp.back();
1324 temp.pop_back();
1325 auto assign = static_cast<Assign_t*>(action);
1326 for (auto value : assign->values.objects()) {
1327 transformAssignItem(value, temp);
1328 }
1329 out.push_back((preDefine.empty() ? Empty : preDefine + nll(assignment)) + indent() + left + s(" = "sv) + join(temp, ", "sv) + nll(assignment));
1330 }
1331 break;
1332 }
1333 default: break;
1334 }
1335 }
1336
1337 void transformCond(const node_container& nodes, str_list& out, ExpUsage usage = ExpUsage::Common, bool unless = false) {
1338 std::vector<ast_ptr<false, ast_node>> ns(false);
1339 for (auto it = nodes.rbegin(); it != nodes.rend(); ++it) {
1340 ns.push_back(*it);
1341 if (auto cond = ast_cast<IfCond_t>(*it)) {
1342 if (*it != nodes.front() && cond->assign) {
1343 auto x = *it;
1344 auto newIf = x->new_ptr<If_t>();
1345 for (auto j = ns.rbegin(); j != ns.rend(); ++j) {
1346 newIf->nodes.push_back(*j);
1347 }
1348 ns.clear();
1349 auto simpleValue = x->new_ptr<SimpleValue_t>();
1350 simpleValue->value.set(newIf);
1351 auto value = x->new_ptr<Value_t>();
1352 value->item.set(simpleValue);
1353 auto exp = x->new_ptr<Exp_t>();
1354 exp->value.set(value);
1355 auto expList = x->new_ptr<ExpList_t>();
1356 expList->exprs.push_back(exp);
1357 auto expListAssign = x->new_ptr<ExpListAssign_t>();
1358 expListAssign->expList.set(expList);
1359 auto stmt = x->new_ptr<Statement_t>();
1360 stmt->content.set(expListAssign);
1361 auto body = x->new_ptr<Body_t>();
1362 body->content.set(stmt);
1363 ns.push_back(body.get());
1364 }
1365 }
1366 }
1367 if (nodes.size() != ns.size()) {
1368 auto x = ns.back();
1369 auto newIf = x->new_ptr<If_t>();
1370 for (auto j = ns.rbegin(); j != ns.rend(); ++j) {
1371 newIf->nodes.push_back(*j);
1372 }
1373 transformCond(newIf->nodes.objects(), out, usage, unless);
1374 return;
1375 }
1376 str_list temp;
1377 if (usage == ExpUsage::Closure) {
1378 temp.push_back(s("(function()"sv) + nll(nodes.front()));
1379 pushScope();
1380 }
1381 std::list<std::pair<IfCond_t*, Body_t*>> ifCondPairs;
1382 ifCondPairs.emplace_back();
1383 for (auto node : nodes) {
1384 switch (node->getId()) {
1385 case "IfCond"_id:
1386 ifCondPairs.back().first = static_cast<IfCond_t*>(node);
1387 break;
1388 case "Body"_id:
1389 ifCondPairs.back().second = static_cast<Body_t*>(node);
1390 ifCondPairs.emplace_back();
1391 break;
1392 default: break;
1393 }
1394 }
1395 auto assign = ifCondPairs.front().first->assign.get();
1396 bool storingValue = false;
1397 ast_ptr<false, ExpListAssign_t> extraAssignment;
1398 if (assign) {
1399 auto exp = ifCondPairs.front().first->condition.get();
1400 auto x = exp;
1401 auto var = singleVariableFrom(exp);
1402 if (var.empty()) {
1403 storingValue = true;
1404 auto desVar = getUnusedName("_des_");
1405 if (assign->values.objects().size() == 1) {
1406 auto var = singleVariableFrom(assign->values.objects().front());
1407 if (!var.empty()) {
1408 desVar = var;
1409 storingValue = false;
1410 }
1411 }
1412 if (storingValue) {
1413 if (usage != ExpUsage::Closure) {
1414 temp.push_back(indent() + s("do"sv) + nll(assign));
1415 pushScope();
1416 }
1417 auto expList = toAst<ExpList_t>(desVar, ExpList, x);
1418 auto assignment = x->new_ptr<ExpListAssign_t>();
1419 assignment->expList.set(expList);
1420 assignment->action.set(assign);
1421 transformAssignment(assignment, temp);
1422 }
1423 {
1424 auto expList = x->new_ptr<ExpList_t>();
1425 expList->exprs.push_back(exp);
1426 auto assignOne = x->new_ptr<Assign_t>();
1427 auto valExp = toAst<Exp_t>(desVar, Exp, x);
1428 assignOne->values.push_back(valExp);
1429 auto assignment = x->new_ptr<ExpListAssign_t>();
1430 assignment->expList.set(expList);
1431 assignment->action.set(assignOne);
1432 extraAssignment.set(assignment);
1433 ifCondPairs.front().first->condition.set(valExp);
1434 }
1435 } else {
1436 if (!isDefined(var)) {
1437 storingValue = true;
1438 if (usage != ExpUsage::Closure) {
1439 temp.push_back(indent() + s("do"sv) + nll(assign));
1440 pushScope();
1441 }
1442 }
1443 auto expList = x->new_ptr<ExpList_t>();
1444 expList->exprs.push_back(exp);
1445 auto assignment = x->new_ptr<ExpListAssign_t>();
1446 assignment->expList.set(expList);
1447 assignment->action.set(assign);
1448 transformAssignment(assignment, temp);
1449 }
1450 }
1451 for (const auto& pair : ifCondPairs) {
1452 if (pair.first) {
1453 str_list tmp;
1454 auto condition = pair.first->condition.get();
1455 if (unless) {
1456 if (auto value = singleValueFrom(condition)) {
1457 transformValue(value, tmp);
1458 } else {
1459 transformExp(condition, tmp);
1460 tmp.back() = s("("sv) + tmp.back() + s(")"sv);
1461 }
1462 tmp.back().insert(0, s("not "sv));
1463 unless = false;
1464 } else {
1465 transformExp(condition, tmp);
1466 }
1467 _buf << indent();
1468 if (pair != ifCondPairs.front()) {
1469 _buf << "else"sv;
1470 }
1471 _buf << "if "sv << tmp.back() << " then"sv << nll(condition);
1472 temp.push_back(clearBuf());
1473 }
1474 if (pair.second) {
1475 if (!pair.first) {
1476 temp.push_back(indent() + s("else"sv) + nll(pair.second));
1477 }
1478 pushScope();
1479 if (pair == ifCondPairs.front() && extraAssignment) {
1480 transformAssignment(extraAssignment, temp);
1481 }
1482 transformBody(pair.second, temp, usage != ExpUsage::Common);
1483 popScope();
1484 }
1485 if (!pair.first) {
1486 temp.push_back(indent() + s("end"sv) + nll(nodes.front()));
1487 break;
1488 }
1489 }
1490 if (storingValue && usage != ExpUsage::Closure) {
1491 popScope();
1492 temp.push_back(indent() + s("end"sv) + nlr(nodes.front()));
1493 }
1494 if (usage == ExpUsage::Closure) {
1495 popScope();
1496 temp.push_back(indent() + s("end)()"sv));
1497 }
1498 out.push_back(join(temp));
1499 }
1500
1501 void transformIf(If_t* ifNode, str_list& out, ExpUsage usage = ExpUsage::Common) {
1502 transformCond(ifNode->nodes.objects(), out, usage);
1503 }
1504
1505 void transformUnless(Unless_t* unless, str_list& out, ExpUsage usage = ExpUsage::Common) {
1506 transformCond(unless->nodes.objects(), out, usage, true);
1507 }
1508
1509 void transformExpList(ExpList_t* expList, str_list& out) {
1510 str_list temp;
1511 for (auto exp : expList->exprs.objects()) {
1512 transformExp(static_cast<Exp_t*>(exp), temp);
1513 }
1514 out.push_back(join(temp, ", "sv));
1515 }
1516
1517 void transformExpListLow(ExpListLow_t* expListLow, str_list& out) {
1518 str_list temp;
1519 for (auto exp : expListLow->exprs.objects()) {
1520 transformExp(static_cast<Exp_t*>(exp), temp);
1521 }
1522 out.push_back(join(temp, ", "sv));
1523 }
1524
1525 void transformExp(Exp_t* exp, str_list& out) {
1526 str_list temp;
1527 transformValue(exp->value, temp);
1528 for (auto _opValue : exp->opValues.objects()) {
1529 auto opValue = static_cast<exp_op_value_t*>(_opValue);
1530 transformBinaryOperator(opValue->op, temp);
1531 transformValue(opValue->value, temp);
1532 }
1533 out.push_back(join(temp, " "sv));
1534 }
1535
1536 void transformValue(Value_t* value, str_list& out) {
1537 auto item = value->item.get();
1538 switch (item->getId()) {
1539 case "SimpleValue"_id: transformSimpleValue(static_cast<SimpleValue_t*>(item), out); break;
1540 case "simple_table"_id: transform_simple_table(static_cast<simple_table_t*>(item), out); break;
1541 case "ChainValue"_id: {
1542 auto chainValue = static_cast<ChainValue_t*>(item);
1543 if (isColonChain(chainValue)) {
1544 transformColonChainClosure(chainValue, out);
1545 } else {
1546 transformChainValue(chainValue, out);
1547 }
1548 break;
1549 }
1550 case "String"_id: transformString(static_cast<String_t*>(item), out); break;
1551 default: break;
1552 }
1553 }
1554
1555 void transformCallable(Callable_t* callable, str_list& out, bool invoke) {
1556 auto item = callable->item.get();
1557 switch (item->getId()) {
1558 case "Variable"_id: {
1559 transformVariable(static_cast<Variable_t*>(item), out);
1560 if (_config.lintGlobalVariable && !isDefined(out.back())) {
1561 if (_globals.find(out.back()) == _globals.end()) {
1562 _globals[out.back()] = {item->m_begin.m_line, item->m_begin.m_col};
1563 }
1564 }
1565 break;
1566 }
1567 case "SelfName"_id: { transformSelfName(static_cast<SelfName_t*>(item), out, invoke);
1568 if (_config.lintGlobalVariable) {
1569 std::string self("self"sv);
1570 if (!isDefined(self)) {
1571 if (_globals.find(self) == _globals.end()) {
1572 _globals[self] = {item->m_begin.m_line, item->m_begin.m_col};
1573 }
1574 }
1575 }
1576 break;
1577 }
1578 case "VarArg"_id: out.push_back(s("..."sv)); break;
1579 case "Parens"_id: transformParens(static_cast<Parens_t*>(item), out); break;
1580 default: break;
1581 }
1582 }
1583
1584 void transformParens(Parens_t* parans, str_list& out) {
1585 str_list temp;
1586 transformExp(parans->expr, temp);
1587 out.push_back(s("("sv) + temp.front() + s(")"sv));
1588 }
1589
1590 void transformSimpleValue(SimpleValue_t* simpleValue, str_list& out) {
1591 auto value = simpleValue->value.get();
1592 switch (value->getId()) {
1593 case "const_value"_id: transform_const_value(static_cast<const_value_t*>(value), out); break;
1594 case "If"_id: transformIf(static_cast<If_t*>(value), out, ExpUsage::Closure); break;
1595 case "Unless"_id: transformUnless(static_cast<Unless_t*>(value), out, ExpUsage::Closure); break;
1596 case "Switch"_id: transformSwitchClosure(static_cast<Switch_t*>(value), out); break;
1597 case "With"_id: transformWithClosure(static_cast<With_t*>(value), out); break;
1598 case "ClassDecl"_id: transformClassDeclClosure(static_cast<ClassDecl_t*>(value), out); break;
1599 case "ForEach"_id: transformForEachClosure(static_cast<ForEach_t*>(value), out); break;
1600 case "For"_id: transformForClosure(static_cast<For_t*>(value), out); break;
1601 case "While"_id: transformWhileClosure(static_cast<While_t*>(value), out); break;
1602 case "Do"_id: transformDoClosure(static_cast<Do_t*>(value), out); break;
1603 case "unary_exp"_id: transform_unary_exp(static_cast<unary_exp_t*>(value), out); break;
1604 case "TblComprehension"_id: transformTblCompClosure(static_cast<TblComprehension_t*>(value), out); break;
1605 case "TableLit"_id: transformTableLit(static_cast<TableLit_t*>(value), out); break;
1606 case "Comprehension"_id: transformCompClosure(static_cast<Comprehension_t*>(value), out); break;
1607 case "FunLit"_id: transformFunLit(static_cast<FunLit_t*>(value), out); break;
1608 case "Num"_id: transformNum(static_cast<Num_t*>(value), out); break;
1609 default: break;
1610 }
1611 }
1612
1613 void transformFunLit(FunLit_t* funLit, str_list& out) {
1614 str_list temp;
1615 bool isFatArrow = toString(funLit->arrow) == "=>"sv;
1616 pushScope();
1617 if (isFatArrow) {
1618 forceAddToScope(s("self"sv));
1619 }
1620 if (auto argsDef = funLit->argsDef.get()) {
1621 transformFnArgsDef(argsDef, temp);
1622 if (funLit->body) {
1623 transformBody(funLit->body, temp, true);
1624 } else {
1625 temp.push_back(Empty);
1626 }
1627 auto it = temp.begin();
1628 auto& args = *it;
1629 auto& initArgs = *(++it);
1630 auto& bodyCodes = *(++it);
1631 _buf << "function("sv <<
1632 (isFatArrow ? s("self, "sv) : Empty) <<
1633 args << ')';
1634 if (!initArgs.empty() || !bodyCodes.empty()) {
1635 _buf << nlr(argsDef) << initArgs << bodyCodes;
1636 popScope();
1637 _buf << indent() << "end"sv;
1638 } else {
1639 popScope();
1640 _buf << " end"sv;
1641 }
1642 } else {
1643 if (funLit->body) {
1644 transformBody(funLit->body, temp, true);
1645 } else {
1646 temp.push_back(Empty);
1647 }
1648 auto& bodyCodes = temp.back();
1649 _buf << "function("sv <<
1650 (isFatArrow ? s("self"sv) : Empty) <<
1651 ')';
1652 if (!bodyCodes.empty()) {
1653 _buf << nll(funLit) << bodyCodes;
1654 popScope();
1655 _buf << indent() << "end"sv;
1656 } else {
1657 popScope();
1658 _buf << " end"sv;
1659 }
1660 }
1661 out.push_back(clearBuf());
1662 }
1663
1664 void transformCodes(const node_container& nodes, str_list& out, bool implicitReturn) {
1665 LocalMode mode = LocalMode::None;
1666 Local_t* any = nullptr, *capital = nullptr;
1667 for (auto node : nodes) {
1668 auto stmt = static_cast<Statement_t*>(node);
1669 if (auto local = stmt->content.as<Local_t>()) {
1670 if (auto flag = local->name.as<local_flag_t>()) {
1671 LocalMode newMode = toString(flag) == "*"sv ? LocalMode::Any : LocalMode::Capital;
1672 if (int(newMode) > int(mode)) {
1673 mode = newMode;
1674 }
1675 if (mode == LocalMode::Any) {
1676 if (!any) any = local;
1677 if (!capital) capital = local;
1678 } else {
1679 if (!capital) capital = local;
1680 }
1681 } else {
1682 auto names = local->name.to<NameList_t>();
1683 for (auto name : names->names.objects()) {
1684 local->forceDecls.push_back(toString(name));
1685 }
1686 }
1687 } else if (mode != LocalMode::None) {
1688 ClassDecl_t* classDecl = nullptr;
1689 if (auto assignment = assignmentFrom(stmt)) {
1690 auto vars = getAssignVars(assignment);
1691 for (const auto& var : vars) {
1692 if (var.empty()) continue;
1693 if (std::isupper(var[0]) && capital) {
1694 capital->decls.push_back(var);
1695 } else if (any) {
1696 any->decls.push_back(var);
1697 }
1698 }
1699 auto info = extractDestructureInfo(assignment);
1700 if (!info.first.empty()) {
1701 for (const auto& destruct : info.first)
1702 for (const auto& item : destruct.items)
1703 if (item.isVariable) {
1704 if (std::isupper(item.name[0]) && capital) { capital->decls.push_back(item.name);
1705 } else if (any) {
1706 any->decls.push_back(item.name);
1707 }
1708 }
1709 }
1710 BLOCK_START
1711 auto assign = assignment->action.as<Assign_t>();
1712 BREAK_IF(!assign);
1713 BREAK_IF(assign->values.objects().size() != 1);
1714 auto exp = ast_cast<Exp_t>(assign->values.objects().front());
1715 BREAK_IF(!exp);
1716 auto value = singleValueFrom(exp);
1717 classDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
1718 BLOCK_END
1719 } else if (auto expList = expListFrom(stmt)) {
1720 auto value = singleValueFrom(expList);
1721 classDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
1722 }
1723 if (classDecl) {
1724 if (auto variable = classDecl->name->item.as<Variable_t>()) {
1725 auto className = toString(variable);
1726 if (!className.empty()) {
1727 if (std::isupper(className[0]) && capital) {
1728 capital->decls.push_back(className);
1729 } else if (any) {
1730 any->decls.push_back(className);
1731 }
1732 }
1733 }
1734 }
1735 }
1736 }
1737 if (implicitReturn) {
1738 auto last = static_cast<Statement_t*>(nodes.back());
1739 auto x = last;
1740 BLOCK_START
1741 auto expList = expListFrom(last);
1742 BREAK_IF(!expList ||
1743 (last->appendix &&
1744 last->appendix->item.is<CompInner_t>()));
1745 auto expListLow = x->new_ptr<ExpListLow_t>();
1746 expListLow->exprs.dup(expList->exprs);
1747 auto returnNode = x->new_ptr<Return_t>();
1748 returnNode->valueList.set(expListLow);
1749 last->content.set(returnNode);
1750 BLOCK_END
1751 }
1752 str_list temp;
1753 for (auto node : nodes) {
1754 transformStatement(static_cast<Statement_t*>(node), temp);
1755 }
1756 out.push_back(join(temp));
1757 }
1758
1759 void transformBody(Body_t* body, str_list& out, bool implicitReturn = false) {
1760 if (auto stmt = body->content.as<Statement_t>()) {
1761 transformCodes(node_container{stmt}, out, implicitReturn);
1762 } else {
1763 transformCodes(body->content.to<Block_t>()->statements.objects(), out, implicitReturn);
1764 }
1765 }
1766
1767 void transformBlock(Block_t* block, str_list& out, bool implicitReturn = true) {
1768 transformCodes(block->statements.objects(), out, implicitReturn);
1769 }
1770
1771 void transformReturn(Return_t* returnNode, str_list& out) {
1772 if (auto valueList = returnNode->valueList.get()) {
1773 if (auto singleValue = singleValueFrom(valueList)) {
1774 if (auto simpleValue = singleValue->item.as<SimpleValue_t>()) {
1775 auto value = simpleValue->value.get();
1776 switch (value->getId()) {
1777 case "Comprehension"_id:
1778 transformCompReturn(static_cast<Comprehension_t*>(value), out);
1779 return;
1780 case "TblComprehension"_id:
1781 transformTblCompReturn(static_cast<TblComprehension_t*>(value), out);
1782 return;
1783 case "With"_id:
1784 transformWith(static_cast<With_t*>(value), out, nullptr, true);
1785 return;
1786 case "ClassDecl"_id:
1787 transformClassDecl(static_cast<ClassDecl_t*>(value), out, ExpUsage::Return);
1788 return;
1789 case "Do"_id:
1790 transformDo(static_cast<Do_t*>(value), out, true);
1791 return;
1792 case "Switch"_id:
1793 transformSwitch(static_cast<Switch_t*>(value), out, true);
1794 return;
1795 case "While"_id:
1796 transformWhileInPlace(static_cast<While_t*>(value), out);
1797 return;
1798 case "For"_id:
1799 transformForInPlace(static_cast<For_t*>(value), out);
1800 return;
1801 case "ForEach"_id:
1802 transformForEachInPlace(static_cast<ForEach_t*>(value), out);
1803 return;
1804 case "If"_id:
1805 transformIf(static_cast<If_t*>(value), out, ExpUsage::Return);
1806 return;
1807 case "Unless"_id:
1808 transformUnless(static_cast<Unless_t*>(value), out, ExpUsage::Return);
1809 return;
1810 }
1811 }
1812 if (auto chainValue = singleValue->item.as<ChainValue_t>()) {
1813 if (isColonChain(chainValue)) {
1814 transformColonChain(chainValue, out, ExpUsage::Return);
1815 } else {
1816 transformChainValue(chainValue, out, ExpUsage::Return);
1817 }
1818 return;
1819 }
1820 transformValue(singleValue, out);
1821 out.back() = indent() + s("return "sv) + out.back() + nlr(returnNode);
1822 return;
1823 } else {
1824 str_list temp;
1825 transformExpListLow(valueList, temp);
1826 out.push_back(indent() + s("return "sv) + temp.back() + nlr(returnNode));
1827 }
1828 } else {
1829 out.push_back(indent() + s("return"sv) + nll(returnNode));
1830 }
1831 }
1832
1833 void transformFnArgsDef(FnArgsDef_t* argsDef, str_list& out) {
1834 if (!argsDef->defList) {
1835 out.push_back(Empty);
1836 out.push_back(Empty);
1837 } else {
1838 transformFnArgDefList(argsDef->defList, out);
1839 }
1840 if (argsDef->shadowOption) {
1841 transform_outer_var_shadow(argsDef->shadowOption);
1842 }
1843 }
1844
1845 void transform_outer_var_shadow(outer_var_shadow_t* shadow) {
1846 markVarShadowed();
1847 if (shadow->varList) {
1848 for (auto name : shadow->varList->names.objects()) {
1849 addToAllowList(toString(name));
1850 }
1851 }
1852 }
1853
1854 void transformFnArgDefList(FnArgDefList_t* argDefList, str_list& out) {
1855 auto x = argDefList;
1856 struct ArgItem {
1857 std::string name;
1858 std::string assignSelf;
1859 };
1860 std::list<ArgItem> argItems;
1861 str_list temp;
1862 std::string varNames;
1863 bool assignSelf = false;
1864 for (auto _def : argDefList->definitions.objects()) {
1865 auto def = static_cast<FnArgDef_t*>(_def);
1866 auto& arg = argItems.emplace_back();
1867 switch (def->name->getId()) {
1868 case "Variable"_id: arg.name = toString(def->name); break;
1869 case "SelfName"_id: {
1870 assignSelf = true;
1871 auto selfName = static_cast<SelfName_t*>(def->name.get());
1872 switch (selfName->name->getId()) {
1873 case "self_class_name"_id: {
1874 auto clsName = static_cast<self_class_name_t*>(selfName->name.get());
1875 arg.name = toString(clsName->name);
1876 arg.assignSelf = s("self.__class."sv) + arg.name;
1877 break;
1878 }
1879 case "self_class"_id:
1880 arg.name = "self.__class"sv;
1881 break;
1882 case "self_name"_id: {
1883
1884 auto sfName = static_cast<self_name_t*>(selfName->name.get());
1885 arg.name = toString(sfName->name);
1886 arg.assignSelf = s("self."sv) + arg.name;
1887 break;
1888 }
1889 case "self"_id:
1890 arg.name = "self"sv;
1891 break;
1892 default: break;
1893 }
1894 break;
1895 }
1896 }
1897 forceAddToScope(arg.name);
1898 if (def->defaultValue) {
1899 pushScope();
1900 auto expList = toAst<ExpList_t>(arg.name, ExpList, x);
1901 auto assign = x->new_ptr<Assign_t>();
1902 assign->values.push_back(def->defaultValue.get());
1903 auto assignment = x->new_ptr<ExpListAssign_t>();
1904 assignment->expList.set(expList);
1905 assignment->action.set(assign);
1906 transformAssignment(assignment, temp);
1907 popScope();
1908 _buf << indent() << "if "sv << arg.name << " == nil then"sv << nll(def);
1909 _buf << temp.back();
1910 _buf << indent() << "end"sv << nll(def);
1911 temp.back() = clearBuf();
1912 }
1913 if (varNames.empty()) varNames = arg.name;
1914 else varNames.append(s(", "sv) + arg.name);
1915 }
1916 if (argDefList->varArg) {
1917 auto& arg = argItems.emplace_back();
1918 arg.name = "..."sv;
1919 if (varNames.empty()) varNames = arg.name;
1920 else varNames.append(s(", "sv) + arg.name);
1921 }
1922 std::string initCodes = join(temp);
1923 if (assignSelf) {
1924 auto sjoin = [](const decltype(argItems)& items, int index) {
1925 std::string result;
1926 for (auto it = items.begin(); it != items.end(); ++it) {
1927 if (it->assignSelf.empty()) continue;
1928 if (result.empty()) result = (&it->name)[index];
1929 else result.append(s(", "sv) + (&it->name)[index]);
1930 }
1931 return result;
1932 };
1933 std::string sleft = sjoin(argItems, 1);
1934 std::string sright = sjoin(argItems, 0);
1935 initCodes.append(indent() + sleft + s(" = "sv) + sright + nll(argDefList));
1936 }
1937 out.push_back(varNames);
1938 out.push_back(initCodes);
1939 }
1940
1941 void transformSelfName(SelfName_t* selfName, str_list& out, bool invoke) {
1942 auto name = selfName->name.get();
1943 switch (name->getId()) {
1944 case "self_class_name"_id: {
1945 auto clsName = static_cast<self_class_name_t*>(name);
1946 out.push_back(s("self.__class"sv) + s(invoke ? ":"sv : "."sv) + toString(clsName->name));
1947 break;
1948 }
1949 case "self_class"_id:
1950 out.push_back(s("self.__class"sv));
1951 break;
1952 case "self_name"_id: {
1953 auto sfName = static_cast<self_class_name_t*>(name);
1954 out.push_back(s("self"sv) + s(invoke ? ":"sv : "."sv) + toString(sfName->name));
1955 break;
1956 }
1957 case "self"_id:
1958 out.push_back(s("self"sv));
1959 break;
1960 }
1961 }
1962
1963 void transformColonChainClosure(ChainValue_t* chainValue, str_list& out) {
1964 str_list temp;
1965 temp.push_back(s("(function()"sv) + nll(chainValue));
1966 pushScope();
1967 transformColonChain(chainValue, temp, ExpUsage::Return);
1968 popScope();
1969 temp.push_back(indent() + s("end)()"sv));
1970 out.push_back(join(temp));
1971 }
1972
1973 void transformColonChain(ChainValue_t* chainValue, str_list& out, ExpUsage usage = ExpUsage::Common, ExpList_t* expList = nullptr) {
1974 auto x = chainValue;
1975 const auto& chainList = chainValue->items.objects();
1976 auto baseChain = x->new_ptr<ChainValue_t>();
1977 switch (chainList.front()->getId()) {
1978 case "DotChainItem"_id:
1979 case "ColonChainItem"_id:
1980 if (_withVars.empty()) {
1981 throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, chainList.front()));
1982 } else {
1983 baseChain->items.push_back(toAst<Callable_t>(_withVars.top(), Callable, x));
1984 }
1985 break;
1986 }
1987 auto end = --chainList.end();
1988 for (auto it = chainList.begin(); it != end; ++it) {
1989 baseChain->items.push_back(*it);
1990 }
1991 auto colonChainItem = static_cast<ColonChainItem_t*>(chainList.back());
1992 auto funcName = toString(colonChainItem->name);
1993 if (usage != ExpUsage::Return) pushScope();
1994 auto baseVar = getUnusedName("_base_"sv);
1995 auto fnVar = getUnusedName("_fn_"sv);
1996 str_list temp;
1997 {
1998 auto value = x->new_ptr<Value_t>();
1999 value->item.set(baseChain);
2000 auto exp = x->new_ptr<Exp_t>();
2001 exp->value.set(value);
2002 auto assign = x->new_ptr<Assign_t>();
2003 assign->values.push_back(exp);
2004 auto assignment = x->new_ptr<ExpListAssign_t>();
2005 assignment->expList.set(toAst<ExpList_t>(baseVar, ExpList, x));
2006 assignment->action.set(assign);
2007 transformAssignment(assignment, temp);
2008 }
2009 {
2010 auto assign = x->new_ptr<Assign_t>();
2011 assign->values.push_back(toAst<Exp_t>(baseVar + "." + funcName, Exp, x));
2012 auto assignment = x->new_ptr<ExpListAssign_t>();
2013 assignment->expList.set(toAst<ExpList_t>(fnVar, ExpList, x));
2014 assignment->action.set(assign);
2015 transformAssignment(assignment, temp);
2016 }
2017 auto funLit = toAst<Exp_t>(s("(...)-> "sv) + fnVar + s(" "sv) + baseVar + s(", ..."sv), Exp, x);
2018 switch (usage) {
2019 case ExpUsage::Return:
2020 transformExp(funLit, temp);
2021 _buf << temp.front();
2022 _buf << *(++temp.begin());
2023 _buf << indent() << "return " << temp.back() << nll(chainValue);
2024 break;
2025 case ExpUsage::Assignment: {
2026 auto assign = x->new_ptr<Assign_t>();
2027 assign->values.push_back(funLit);
2028 auto assignment = x->new_ptr<ExpListAssign_t>();
2029 assignment->expList.set(expList);
2030 assignment->action.set(assign);
2031 transformAssignment(assignment, temp);
2032 _buf << indent(-1) << "do"sv << nll(chainValue);
2033 _buf << temp.front();
2034 _buf << *(++temp.begin());
2035 _buf << temp.back();
2036 popScope();
2037 _buf << indent() << "end"sv << nll(chainValue);
2038 break;
2039 }
2040 case ExpUsage::Common: {
2041 auto assign = x->new_ptr<Assign_t>();
2042 assign->values.push_back(funLit);
2043 auto assignment = x->new_ptr<ExpListAssign_t>();
2044 assignment->expList.set(toAst<ExpList_t>("_"sv, ExpList, x));
2045 assignment->action.set(assign);
2046 transformAssignment(assignment, temp);
2047 _buf << indent(-1) << "do"sv << nll(chainValue);
2048 _buf << temp.front();
2049 _buf << *(++temp.begin());
2050 _buf << temp.back();
2051 popScope();
2052 _buf << indent() << "end"sv << nll(chainValue);
2053 break;
2054 }
2055 default: break;
2056 }
2057 out.push_back(clearBuf());
2058 }
2059
2060 void transformChainList(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
2061 auto x = chainList.front();
2062 str_list temp;
2063 switch (chainList.front()->getId()) {
2064 case "DotChainItem"_id:
2065 case "ColonChainItem"_id:
2066 if (_withVars.empty()) {
2067 throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, chainList.front()));
2068 } else {
2069 temp.push_back(_withVars.top());
2070 }
2071 break;
2072 }
2073 for (auto it = chainList.begin(); it != chainList.end(); ++it) {
2074 auto item = *it;
2075 switch (item->getId()) {
2076 case "Invoke"_id:
2077 transformInvoke(static_cast<Invoke_t*>(item), temp);
2078 break;
2079 case "DotChainItem"_id:
2080 transformDotChainItem(static_cast<DotChainItem_t*>(item), temp);
2081 break;
2082 case "ColonChainItem"_id: {
2083 auto colonItem = static_cast<ColonChainItem_t*>(item);
2084 auto next = it; ++next;
2085 auto followItem = next != chainList.end() ? *next : nullptr;
2086 if (!ast_is<Invoke_t, InvokeArgs_t>(followItem)) {
2087 throw std::logic_error(debugInfo("Colon chain item must be followed by invoke arguments."sv, colonItem));
2088 }
2089 if (colonItem->name.is<LuaKeyword_t>()) {
2090 std::string callVar;
2091 auto block = x->new_ptr<Block_t>();
2092 {
2093 auto chainValue = x->new_ptr<ChainValue_t>();
2094 switch (chainList.front()->getId()) {
2095 case "DotChainItem"_id:
2096 case "ColonChainItem"_id:
2097 chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), Callable, x));
2098 break;
2099 }
2100 for (auto i = chainList.begin(); i != it; ++i) {
2101 chainValue->items.push_back(*i);
2102 }
2103 auto value = x->new_ptr<Value_t>();
2104 value->item.set(chainValue);
2105 auto exp = x->new_ptr<Exp_t>();
2106 exp->value.set(value);
2107 callVar = singleVariableFrom(exp);
2108 if (callVar.empty()) {
2109 callVar = getUnusedName(s("_call_"sv));
2110 auto assignment = x->new_ptr<ExpListAssign_t>();
2111 assignment->expList.set(toAst<ExpList_t>(callVar, ExpList, x));
2112 auto assign = x->new_ptr<Assign_t>();
2113 assign->values.push_back(exp);
2114 assignment->action.set(assign);
2115 auto stmt = x->new_ptr<Statement_t>();
2116 stmt->content.set(assignment);
2117 block->statements.push_back(stmt);
2118 }
2119 }
2120 {
2121 auto name = toString(colonItem->name);
2122 auto chainValue = x->new_ptr<ChainValue_t>();
2123 chainValue->items.push_back(toAst<Callable_t>(callVar, Callable, x));
2124 chainValue->items.push_back(toAst<Exp_t>(s("\""sv) + name + s("\""sv), Exp, x));
2125 if (auto invoke = ast_cast<Invoke_t>(followItem)) {
2126 invoke->args.push_front(toAst<Exp_t>(callVar, Exp, x));
2127 } else {
2128 auto invokeArgs = static_cast<InvokeArgs_t*>(followItem);
2129 invokeArgs->args.push_front(toAst<Exp_t>(callVar, Exp, x));
2130 }
2131 chainValue->items.push_back(followItem);
2132 for (auto i = ++next; i != chainList.end(); ++i) {
2133 chainValue->items.push_back(*i);
2134 }
2135 auto value = x->new_ptr<Value_t>();
2136 value->item.set(chainValue);
2137 auto exp = x->new_ptr<Exp_t>();
2138 exp->value.set(value);
2139 auto expList = x->new_ptr<ExpList_t>();
2140 expList->exprs.push_back(exp);
2141 auto expListAssign = x->new_ptr<ExpListAssign_t>();
2142 expListAssign->expList.set(expList);
2143 auto stmt = x->new_ptr<Statement_t>();
2144 stmt->content.set(expListAssign);
2145 block->statements.push_back(stmt);
2146 }
2147 switch (usage) {
2148 case ExpUsage::Common:
2149 transformBlock(block, out, false);
2150 return;
2151 case ExpUsage::Return:
2152 transformBlock(block, out, true);
2153 return;
2154 case ExpUsage::Assignment: {
2155 auto body = x->new_ptr<Body_t>();
2156 body->content.set(block);
2157 assignLastExplist(assignList, body);
2158 transformBlock(block, out);
2159 return;
2160 }
2161 default:
2162 break;
2163 }
2164 auto body = x->new_ptr<Body_t>();
2165 body->content.set(block);
2166 auto funLit = toAst<FunLit_t>("->"sv, FunLit, x);
2167 funLit->body.set(body);
2168 auto simpleValue = x->new_ptr<SimpleValue_t>();
2169 simpleValue->value.set(funLit);
2170 auto value = x->new_ptr<Value_t>();
2171 value->item.set(simpleValue);
2172 auto exp = x->new_ptr<Exp_t>();
2173 exp->value.set(value);
2174 auto paren = x->new_ptr<Parens_t>();
2175 paren->expr.set(exp);
2176 auto callable = x->new_ptr<Callable_t>();
2177 callable->item.set(paren);
2178 auto chainValue = x->new_ptr<ChainValue_t>();
2179 chainValue->items.push_back(callable);
2180 auto invoke = x->new_ptr<Invoke_t>();
2181 chainValue->items.push_back(invoke);
2182 transformChainValue(chainValue, out);
2183 return;
2184 }
2185 transformColonChainItem(colonItem, temp);
2186 break;
2187 }
2188 case "Slice"_id:
2189 transformSlice(static_cast<Slice_t*>(item), temp);
2190 break;
2191 case "Callable"_id: {
2192 auto next = it; ++next;
2193 auto followItem = next != chainList.end() ? *next : nullptr;
2194 transformCallable(static_cast<Callable_t*>(item), temp,
2195 followItem && ast_is<Invoke_t, InvokeArgs_t>(followItem));
2196 break;
2197 }
2198 case "String"_id:
2199 transformString(static_cast<String_t*>(item), temp);
2200 temp.back() = s("("sv) + temp.back() + s(")"sv);
2201 break;
2202 case "Exp"_id:
2203 transformExp(static_cast<Exp_t*>(item), temp);
2204 temp.back() = s("["sv) + temp.back() + s("]"sv);
2205 break;
2206 case "InvokeArgs"_id: transformInvokeArgs(static_cast<InvokeArgs_t*>(item), temp); break;
2207 default: break;
2208 }
2209 }
2210 switch (usage) {
2211 case ExpUsage::Common:
2212 out.push_back(indent() + join(temp) + nll(chainList.front()));
2213 break;
2214 case ExpUsage::Return:
2215 out.push_back(indent() + s("return "sv) + join(temp) + nll(chainList.front()));
2216 break;
2217 default:
2218 out.push_back(join(temp));
2219 break;
2220 }
2221 }
2222
2223 void transformChainValue(ChainValue_t* chainValue, str_list& out, ExpUsage usage = ExpUsage::Closure, ExpList_t* assignList = nullptr) {
2224 transformChainList(chainValue->items.objects(), out, usage, assignList);
2225 }
2226
2227 void transformAssignableChain(AssignableChain_t* chain, str_list& out) {
2228 transformChainList(chain->items.objects(), out, ExpUsage::Closure);
2229 }
2230
2231 void transformDotChainItem(DotChainItem_t* dotChainItem, str_list& out) {
2232 auto name = toString(dotChainItem->name);
2233 if (State::keywords.find(name) != State::keywords.end()) {
2234 out.push_back(s("[\""sv) + name + s("\"]"sv));
2235 } else {
2236 out.push_back(s("."sv) + name);
2237 }
2238 }
2239
2240 void transformColonChainItem(ColonChainItem_t* colonChainItem, str_list& out) {
2241 auto name = toString(colonChainItem->name);
2242 out.push_back(s(colonChainItem->switchToDot ? "."sv : ":"sv) + name);
2243 }
2244
2245 void transformSlice(Slice_t* slice, str_list&) {
2246 throw std::logic_error(debugInfo("Slice syntax not supported here."sv, slice));
2247 }
2248
2249 void transformInvoke(Invoke_t* invoke, str_list& out) {
2250 str_list temp;
2251 for (auto arg : invoke->args.objects()) {
2252 switch (arg->getId()) {
2253 case "Exp"_id: transformExp(static_cast<Exp_t*>(arg), temp); break;
2254 case "SingleString"_id: transformSingleString(static_cast<SingleString_t*>(arg), temp); break;
2255 case "DoubleString"_id: transformDoubleString(static_cast<DoubleString_t*>(arg), temp); break;
2256 case "LuaString"_id: transformLuaString(static_cast<LuaString_t*>(arg), temp); break;
2257 default: break;
2258 }
2259 }
2260 out.push_back(s("("sv) + join(temp, ", "sv) + s(")"sv));
2261 }
2262
2263 void transform_unary_exp(unary_exp_t* unary_exp, str_list& out) {
2264 std::string op = toString(unary_exp->m_begin.m_it, unary_exp->item->m_begin.m_it);
2265 str_list temp{op + (op == "not"sv ? s(" "sv) : Empty)};
2266 transformExp(unary_exp->item, temp);
2267 out.push_back(join(temp));
2268 }
2269
2270 void transformVariable(Variable_t* name, str_list& out) {
2271 out.push_back(toString(name));
2272 }
2273
2274 void transformNum(Num_t* num, str_list& out) {
2275 out.push_back(toString(num));
2276 }
2277
2278 void transformTableLit(TableLit_t* table, str_list& out) {
2279 transformTable(table, table->values.objects(), out);
2280 }
2281
2282 void transformCompCommon(Comprehension_t* comp, str_list& out) {
2283 str_list temp;
2284 auto x = comp;
2285 auto compInner = comp->forLoop.get();
2286 for (auto item : compInner->items.objects()) {
2287 switch (item->getId()) {
2288 case "CompForEach"_id:
2289 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
2290 break;
2291 case "CompFor"_id:
2292 transformCompFor(static_cast<CompFor_t*>(item), temp);
2293 break;
2294 case "Exp"_id:
2295 transformExp(static_cast<Exp_t*>(item), temp);
2296 temp.back() = indent() + s("if "sv) + temp.back() + s(" then"sv) + nll(item);
2297 pushScope();
2298 break;
2299 }
2300 }
2301 if (auto stmt = comp->value.as<Statement_t>()) {
2302 transformStatement(stmt, temp);
2303 } else if (auto exp = comp->value.as<Exp_t>()) {
2304 auto expList = x->new_ptr<ExpList_t>();
2305 expList->exprs.push_back(exp);
2306 auto expListAssign = x->new_ptr<ExpListAssign_t>();
2307 expListAssign->expList.set(expList);
2308 auto statement = x->new_ptr<Statement_t>();
2309 statement->content.set(expListAssign);
2310 transformStatement(statement, temp);
2311 }
2312 auto value = temp.back();
2313 temp.pop_back();
2314 _buf << join(temp) << value;
2315 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
2316 popScope();
2317 _buf << indent() << "end"sv << nll(comp);
2318 }
2319 out.push_back(clearBuf());
2320 }
2321
2322 void transformComprehension(Comprehension_t* comp, str_list& out) {
2323 str_list temp;
2324 std::string accum = getUnusedName("_accum_");
2325 std::string len = getUnusedName("_len_");
2326 addToScope(accum);
2327 addToScope(len);
2328 auto compInner = comp->forLoop.get();
2329 for (auto item : compInner->items.objects()) {
2330 switch (item->getId()) {
2331 case "CompForEach"_id:
2332 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
2333 break;
2334 case "CompFor"_id:
2335 transformCompFor(static_cast<CompFor_t*>(item), temp);
2336 break;
2337 case "Exp"_id:
2338 transformExp(static_cast<Exp_t*>(item), temp);
2339 temp.back() = indent() + s("if "sv) + temp.back() + s(" then"sv) + nll(item);
2340 pushScope();
2341 break;
2342 }
2343 }
2344 transformExp(comp->value.to<Exp_t>(), temp);
2345 auto value = temp.back();
2346 temp.pop_back();
2347 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
2348 popScope();
2349 }
2350 _buf << indent() << "local "sv << accum << " = { }"sv << nll(comp);
2351 _buf << indent() << "local "sv << len << " = 1"sv << nll(comp);
2352 _buf << join(temp);
2353 _buf << indent(int(temp.size())) << accum << "["sv << len << "] = "sv << value << nll(comp);
2354 _buf << indent(int(temp.size())) << len << " = "sv << len << " + 1"sv << nll(comp);
2355 for (int ind = int(temp.size()) - 1; ind > -1 ; --ind) {
2356 _buf << indent(ind) << "end"sv << nll(comp);
2357 }
2358 out.push_back(accum);
2359 out.push_back(clearBuf());
2360 }
2361
2362 void transformCompInPlace(Comprehension_t* comp, ExpList_t* expList, str_list& out) {
2363 auto x = comp;
2364 str_list temp;
2365 auto ind = indent();
2366 pushScope();
2367 transformComprehension(comp, temp);
2368 auto assign = x->new_ptr<Assign_t>();
2369 assign->values.push_back(toAst<Exp_t>(temp.front(), Exp, x));
2370 auto assignment = x->new_ptr<ExpListAssign_t>();
2371 assignment->expList.set(expList);
2372 assignment->action.set(assign);
2373 transformAssignment(assignment, temp);
2374 out.push_back(
2375 ind + s("do"sv) + nll(comp) +
2376 *(++temp.begin()) +
2377 temp.back());
2378 popScope();
2379 out.back() = out.back() + indent() + s("end"sv) + nlr(comp);
2380 }
2381
2382 void transformCompReturn(Comprehension_t* comp, str_list& out) {
2383 str_list temp;
2384 transformComprehension(comp, temp);
2385 out.push_back(temp.back() + indent() + s("return "sv) + temp.front() + nlr(comp));
2386 }
2387
2388 void transformCompClosure(Comprehension_t* comp, str_list& out) {
2389 str_list temp;
2390 std::string before = s("(function()"sv) + nll(comp);
2391 pushScope();
2392 transformComprehension(comp, temp);
2393 out.push_back(
2394 before +
2395 temp.back() +
2396 indent() + s("return "sv) + temp.front() + nlr(comp));
2397 popScope();
2398 out.back() = out.back() + indent() + s("end)()"sv);
2399 }
2400
2401 void transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out) {
2402 auto x = nameList;
2403 str_list temp;
2404 str_list vars;
2405 str_list varBefore, varAfter;
2406 std::list<std::pair<ast_node*, ast_ptr<false, ast_node>>> destructPairs;
2407 for (auto _item : nameList->items.objects()) {
2408 auto item = static_cast<NameOrDestructure_t*>(_item)->item.get();
2409 switch (item->getId()) {
2410 case "Variable"_id:
2411 transformVariable(static_cast<Variable_t*>(item), vars);
2412 varAfter.push_back(vars.back());
2413 break;
2414 case "TableLit"_id: {
2415 auto desVar = getUnusedName("_des_"sv);
2416 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, Exp, x));
2417 vars.push_back(desVar);
2418 varAfter.push_back(desVar);
2419 break;
2420 }
2421 default: break;
2422 }
2423 }
2424 switch (loopTarget->getId()) {
2425 case "star_exp"_id: {
2426 auto star_exp = static_cast<star_exp_t*>(loopTarget);
2427 std::string listVar;
2428 if (_config.reuseVariable) listVar = singleVariableFrom(star_exp->value);
2429 auto indexVar = getUnusedName("_index_");
2430 varAfter.push_back(indexVar);
2431 auto value = singleValueFrom(star_exp->value);
2432 if (!value) throw std::logic_error(debugInfo("Invalid star syntax."sv, star_exp));
2433 bool endWithSlice = false;
2434 BLOCK_START
2435 auto chainValue = value->item.as<ChainValue_t>();
2436 BREAK_IF(!chainValue);
2437 auto chainList = chainValue->items.objects();
2438 auto slice = ast_cast<Slice_t>(chainList.back());
2439 BREAK_IF(!slice);
2440 endWithSlice = true;
2441 if (listVar.empty() && chainList.size() == 2 &&
2442 ast_is<Callable_t>(chainList.front())) {
2443 transformCallable(static_cast<Callable_t*>(chainList.front()), temp, false);
2444 listVar = temp.back();
2445 temp.pop_back();
2446 }
2447 chainList.pop_back();
2448 auto chain = x->new_ptr<ChainValue_t>();
2449 for (auto item : chainList) {
2450 chain->items.push_back(item);
2451 }
2452 std::string startValue("1"sv);
2453 if (auto exp = slice->startValue.as<Exp_t>()) {
2454 transformExp(exp, temp);
2455 startValue = temp.back();
2456 temp.pop_back();
2457 }
2458 std::string stopValue;
2459 if (auto exp = slice->stopValue.as<Exp_t>()) {
2460 transformExp(exp, temp);
2461 stopValue = temp.back();
2462 temp.pop_back();
2463 }
2464 std::string stepValue;
2465 if (auto exp = slice->stepValue.as<Exp_t>()) {
2466 transformExp(exp, temp);
2467 stepValue = temp.back();
2468 temp.pop_back();
2469 }
2470 if (listVar.empty()) {
2471 listVar = getUnusedName("_list_");
2472 varBefore.push_back(listVar);
2473 transformChainValue(chain, temp);
2474 _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList);
2475 }
2476 std::string maxVar;
2477 if (!stopValue.empty()) {
2478 maxVar = getUnusedName("_max_");
2479 varBefore.push_back(maxVar);
2480 _buf << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList);
2481 }
2482 _buf << indent() << "for "sv << indexVar << " = "sv;
2483 _buf << startValue << ", "sv;
2484 if (stopValue.empty()) {
2485 _buf << "#"sv << listVar;
2486 } else {
2487 _buf << maxVar << " < 0 and #"sv << listVar <<" + " << maxVar << " or "sv << maxVar;
2488 }
2489 if (!stepValue.empty()) {
2490 _buf << ", "sv << stepValue;
2491 }
2492 _buf << " do"sv << nlr(loopTarget);
2493 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList);
2494 out.push_back(clearBuf());
2495 BLOCK_END
2496 bool newListVal = false;
2497 if (listVar.empty()) {
2498 newListVal = true;
2499 listVar = getUnusedName("_list_");
2500 varBefore.push_back(listVar);
2501 }
2502 if (!endWithSlice) {
2503 transformExp(star_exp->value, temp);
2504 if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList);
2505 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nlr(loopTarget);
2506 _buf << indent(1) << "local "sv << join(vars) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList);
2507 out.push_back(clearBuf());
2508 }
2509 break;
2510 }
2511 case "Exp"_id:
2512 transformExp(static_cast<Exp_t*>(loopTarget), temp);
2513 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget);
2514 out.push_back(clearBuf());
2515 break;
2516 case "ExpList"_id:
2517 transformExpList(static_cast<ExpList_t*>(loopTarget), temp);
2518 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget);
2519 out.push_back(clearBuf());
2520 break;
2521 default: break;
2522 }
2523 for (auto& var : varBefore) addToScope(var);
2524 pushScope();
2525 for (auto& var : varAfter) addToScope(var);
2526 if (!destructPairs.empty()) {
2527 temp.clear();
2528 for (auto& pair : destructPairs) {
2529 auto sValue = x->new_ptr<SimpleValue_t>();
2530 sValue->value.set(pair.first);
2531 auto value = x->new_ptr<Value_t>();
2532 value->item.set(sValue);
2533 auto exp = x->new_ptr<Exp_t>();
2534 exp->value.set(value);
2535 auto expList = x->new_ptr<ExpList_t>();
2536 expList->exprs.push_back(exp);
2537 auto assign = x->new_ptr<Assign_t>();
2538 assign->values.push_back(pair.second);
2539 auto assignment = x->new_ptr<ExpListAssign_t>();
2540 assignment->expList.set(expList);
2541 assignment->action.set(assign);
2542 transformAssignment(assignment, temp);
2543 }
2544 out.back().append(join(temp));
2545 }
2546 }
2547
2548 void transformCompForEach(CompForEach_t* comp, str_list& out) {
2549 transformForEachHead(comp->nameList, comp->loopValue, out);
2550 }
2551
2552 void transformInvokeArgs(InvokeArgs_t* invokeArgs, str_list& out) {
2553 str_list temp;
2554 for (auto arg : invokeArgs->args.objects()) {
2555 switch (arg->getId()) {
2556 case "Exp"_id: transformExp(static_cast<Exp_t*>(arg), temp); break;
2557 case "TableBlock"_id: transformTableBlock(static_cast<TableBlock_t*>(arg), temp); break;
2558 default: break;
2559 }
2560 }
2561 out.push_back(s("("sv) + join(temp, ", "sv) + s(")"sv));
2562 }
2563
2564 void transformForHead(For_t* forNode, str_list& out) {
2565 str_list temp;
2566 std::string varName = toString(forNode->varName);
2567 transformExp(forNode->startValue, temp);
2568 transformExp(forNode->stopValue, temp);
2569 if (forNode->stepValue) {
2570 transformExp(forNode->stepValue->value, temp);
2571 } else {
2572 temp.emplace_back();
2573 }
2574 auto it = temp.begin();
2575 const auto& start = *it;
2576 const auto& stop = *(++it);
2577 const auto& step = *(++it);
2578 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : s(", "sv) + step) << " do"sv << nll(forNode);
2579 pushScope();
2580 addToScope(varName);
2581 out.push_back(clearBuf());
2582 }
2583
2584 void transformLoopBody(Body_t* body, str_list& out, const std::string& appendContent) {
2585 str_list temp;
2586 bool withContinue = traversal::Stop == body->traverse([&](ast_node* node) {
2587 switch (node->getId()) {
2588 case "For"_id:
2589 case "ForEach"_id:
2590 return traversal::Return;
2591 case "BreakLoop"_id: {
2592 return toString(node) == "continue"sv ?
2593 traversal::Stop : traversal::Return;
2594 }
2595 default:
2596 return traversal::Continue;
2597 }
2598 });
2599 if (withContinue) {
2600 auto continueVar = getUnusedName("_continue_"sv);
2601 addToScope(continueVar);
2602 _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body);
2603 _buf << indent() << "repeat"sv << nll(body);
2604 temp.push_back(clearBuf());
2605 _continueVars.push(continueVar);
2606 pushScope();
2607 }
2608 transformBody(body, temp);
2609 if (withContinue) {
2610 if (!appendContent.empty()) {
2611 _buf << indent() << appendContent;
2612 }
2613 _buf << indent() << _continueVars.top() << " = true"sv << nll(body);
2614 popScope();
2615 _buf << indent() << "until true"sv << nlr(body);
2616 _buf << indent() << "if not "sv << _continueVars.top() << " then"sv << nlr(body);
2617 _buf << indent(1) << "break"sv << nlr(body);
2618 _buf << indent() << "end"sv << nlr(body);
2619 temp.push_back(clearBuf());
2620 _continueVars.pop();
2621 } else if (!appendContent.empty()) {
2622 temp.back().append(indent() + appendContent);
2623 }
2624 out.push_back(join(temp));
2625 }
2626
2627 void transformFor(For_t* forNode, str_list& out) {
2628 str_list temp;
2629 transformForHead(forNode, temp);
2630 transformLoopBody(forNode->body, temp, Empty);
2631 popScope();
2632 out.push_back(join(temp) + indent() + s("end"sv) + nlr(forNode));
2633 }
2634
2635 std::string transformForInner(For_t* forNode, str_list& out) {
2636 auto x = forNode;
2637 std::string accum = getUnusedName("_accum_");
2638 addToScope(accum);
2639 std::string len = getUnusedName("_len_");
2640 addToScope(len);
2641 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forNode);
2642 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode);
2643 out.push_back(clearBuf());
2644 transformForHead(forNode, out);
2645 auto expList = toAst<ExpList_t>(accum + s("["sv) + len + s("]"sv), ExpList, x);
2646 assignLastExplist(expList, forNode->body);
2647 auto lenLine = len + s(" = "sv) + len + s(" + 1"sv) + nlr(forNode->body);
2648 transformLoopBody(forNode->body, out, lenLine);
2649 popScope();
2650 out.push_back(indent() + s("end"sv) + nlr(forNode));
2651 return accum;
2652 }
2653
2654 void transformForClosure(For_t* forNode, str_list& out) {
2655 str_list temp;
2656 _buf << "(function()"sv << nll(forNode);
2657 pushScope();
2658 auto accum = transformForInner(forNode, temp);
2659 temp.push_back(indent() + s("return "sv) + accum + nlr(forNode));
2660 popScope();
2661 temp.push_back(indent() + s("end)()"sv));
2662 out.push_back(join(temp));
2663 }
2664
2665 void transformForInPlace(For_t* forNode, str_list& out, ExpList_t* assignExpList = nullptr) {
2666 auto x = forNode;
2667 str_list temp;
2668 if (assignExpList) {
2669 _buf << indent() << "do"sv << nll(forNode);
2670 pushScope();
2671 auto accum = transformForInner(forNode, temp);
2672 auto assign = x->new_ptr<Assign_t>();
2673 assign->values.push_back(toAst<Exp_t>(accum, Exp, x));
2674 auto assignment = x->new_ptr<ExpListAssign_t>();
2675 assignment->expList.set(assignExpList);
2676 assignment->action.set(assign);
2677 transformAssignment(assignment, temp);
2678 popScope();
2679 temp.push_back(indent() + s("end"sv) + nlr(forNode));
2680 } else {
2681 auto accum = transformForInner(forNode, temp);
2682 auto returnNode = x->new_ptr<Return_t>();
2683 auto expListLow = toAst<ExpListLow_t>(accum, ExpListLow, x);
2684 returnNode->valueList.set(expListLow);
2685 transformReturn(returnNode, temp);
2686 }
2687 out.push_back(join(temp));
2688 }
2689
2690 void transformBinaryOperator(BinaryOperator_t* node, str_list& out) {
2691 auto op = toString(node);
2692 out.push_back(op == "!="sv ? s("~="sv) : op);
2693 }
2694
2695 void transformForEach(ForEach_t* forEach, str_list& out) {
2696 str_list temp;
2697 transformForEachHead(forEach->nameList, forEach->loopValue, temp);
2698 transformLoopBody(forEach->body, temp, Empty);
2699 popScope();
2700 out.push_back(temp.front() + temp.back() + indent() + s("end"sv) + nlr(forEach));
2701 }
2702
2703 std::string transformForEachInner(ForEach_t* forEach, str_list& out) {
2704 auto x = forEach;
2705 std::string accum = getUnusedName("_accum_");
2706 addToScope(accum);
2707 std::string len = getUnusedName("_len_");
2708 addToScope(len);
2709 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forEach);
2710 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach);
2711 out.push_back(clearBuf());
2712 transformForEachHead(forEach->nameList, forEach->loopValue, out);
2713 auto expList = toAst<ExpList_t>(accum + s("["sv) + len + s("]"sv), ExpList, x);
2714 assignLastExplist(expList, forEach->body);
2715 auto lenLine = len + s(" = "sv) + len + s(" + 1"sv) + nlr(forEach->body);
2716 transformLoopBody(forEach->body, out, lenLine);
2717 popScope();
2718 out.push_back(indent() + s("end"sv) + nlr(forEach));
2719 return accum;
2720 }
2721
2722 void transformForEachClosure(ForEach_t* forEach, str_list& out) {
2723 str_list temp;
2724 _buf << "(function()"sv << nll(forEach);
2725 pushScope();
2726 auto accum = transformForEachInner(forEach, temp);
2727 temp.push_back(indent() + s("return "sv) + accum + nlr(forEach));
2728 popScope();
2729 temp.push_back(indent() + s("end)()"sv));
2730 out.push_back(join(temp));
2731 }
2732
2733 void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList = nullptr) {
2734 auto x = forEach;
2735 str_list temp;
2736 if (assignExpList) {
2737 _buf << indent() << "do"sv << nll(forEach);
2738 pushScope();
2739 auto accum = transformForEachInner(forEach, temp);
2740 auto assign = x->new_ptr<Assign_t>();
2741 assign->values.push_back(toAst<Exp_t>(accum, Exp, x));
2742 auto assignment = x->new_ptr<ExpListAssign_t>();
2743 assignment->expList.set(assignExpList);
2744 assignment->action.set(assign);
2745 transformAssignment(assignment, temp);
2746 popScope();
2747 temp.push_back(indent() + s("end"sv) + nlr(forEach));
2748 } else {
2749 auto accum = transformForEachInner(forEach, temp);
2750 auto returnNode = x->new_ptr<Return_t>();
2751 auto expListLow = toAst<ExpListLow_t>(accum, ExpListLow, x);
2752 returnNode->valueList.set(expListLow);
2753 transformReturn(returnNode, temp);
2754 }
2755 out.push_back(join(temp));
2756 }
2757
2758 void transform_variable_pair(variable_pair_t* pair, str_list& out) {
2759 auto name = toString(pair->name);
2760 out.push_back(name + s(" = "sv) + name);
2761 }
2762
2763 void transform_normal_pair(normal_pair_t* pair, str_list& out) {
2764 auto key = pair->key.get();
2765 str_list temp;
2766 switch (key->getId()) {
2767 case "KeyName"_id: {
2768 transformKeyName(static_cast<KeyName_t*>(key), temp);
2769 if (State::luaKeywords.find(temp.back()) != State::luaKeywords.end()) {
2770 temp.back() = s("[\""sv) + temp.back() + s("\"]");
2771 }
2772 break;
2773 }
2774 case "Exp"_id:
2775 transformExp(static_cast<Exp_t*>(key), temp);
2776 temp.back() = s("["sv) + temp.back() + s("]"sv);
2777 break;
2778 case "DoubleString"_id:
2779 transformDoubleString(static_cast<DoubleString_t*>(key), temp);
2780 temp.back() = s("["sv) + temp.back() + s("]"sv);
2781 break;
2782 case "SingleString"_id: transformSingleString(static_cast<SingleString_t*>(key), temp);
2783 temp.back() = s("["sv) + temp.back() + s("]"sv);
2784 break;
2785 default: break;
2786 }
2787 auto value = pair->value.get();
2788 switch (value->getId()) {
2789 case "Exp"_id: transformExp(static_cast<Exp_t*>(value), temp); break;
2790 case "TableBlock"_id: transformTableBlock(static_cast<TableBlock_t*>(value), temp); break;
2791 default: break;
2792 }
2793 out.push_back(temp.front() + s(" = "sv) + temp.back());
2794 }
2795
2796 void transformKeyName(KeyName_t* keyName, str_list& out) {
2797 auto name = keyName->name.get();
2798 switch (name->getId()) {
2799 case "SelfName"_id: transformSelfName(static_cast<SelfName_t*>(name), out, false); break;
2800 case "Name"_id: out.push_back(toString(name)); break;
2801 default: break;
2802 }
2803 }
2804
2805 void replace(std::string& str, std::string_view from, std::string_view to) {
2806 size_t start_pos = 0;
2807 while((start_pos = str.find(from, start_pos)) != std::string::npos) {
2808 str.replace(start_pos, from.size(), to);
2809 start_pos += to.size();
2810 }
2811 }
2812
2813 void transformLuaString(LuaString_t* luaString, str_list& out) {
2814 auto content = toString(luaString->content);
2815 replace(content, "\r"sv, "");
2816 if (content[0] == '\n') content.erase(content.begin());
2817 out.push_back(toString(luaString->open) + content + toString(luaString->close));
2818 }
2819
2820 void transformSingleString(SingleString_t* singleString, str_list& out) {
2821 auto str = toString(singleString);
2822 replace(str, "\r"sv, "");
2823 replace(str, "\n"sv, "\\n"sv);
2824 out.push_back(str);
2825 }
2826
2827 void transformDoubleString(DoubleString_t* doubleString, str_list& out) {
2828 str_list temp;
2829 for (auto _seg : doubleString->segments.objects()) {
2830 auto seg = static_cast<double_string_content_t*>(_seg);
2831 auto content = seg->content.get();
2832 switch (content->getId()) {
2833 case "double_string_inner"_id: {
2834 auto str = toString(content);
2835 replace(str, "\r"sv, "");
2836 replace(str, "\n"sv, "\\n"sv);
2837 temp.push_back(s("\""sv) + str + s("\""sv));
2838 break;
2839 }
2840 case "Exp"_id:
2841 transformExp(static_cast<Exp_t*>(content), temp);
2842 temp.back() = s("tostring("sv) + temp.back() + s(")"sv);
2843 break;
2844 default: break;
2845 }
2846 }
2847 out.push_back(temp.empty() ? s("\"\""sv) : join(temp, " .. "sv));
2848 }
2849
2850 void transformString(String_t* string, str_list& out) {
2851 auto str = string->str.get();
2852 switch (str->getId()) {
2853 case "SingleString"_id: transformSingleString(static_cast<SingleString_t*>(str), out); break;
2854 case "DoubleString"_id: transformDoubleString(static_cast<DoubleString_t*>(str), out); break;
2855 case "LuaString"_id: transformLuaString(static_cast<LuaString_t*>(str), out); break;
2856 default: break;
2857 }
2858 }
2859
2860 std::pair<std::string,bool> defineClassVariable(Assignable_t* assignable) {
2861 if (auto variable = assignable->item.as<Variable_t>()) {
2862 auto name = toString(variable);
2863 if (addToScope(name)) {
2864 return {name, true};
2865 } else {
2866 return {name, false};
2867 }
2868 }
2869 return {Empty, false};
2870 }
2871
2872 void transformClassDeclClosure(ClassDecl_t* classDecl, str_list& out) {
2873 str_list temp;
2874 temp.push_back(s("(function()"sv) + nll(classDecl));
2875 pushScope();
2876 transformClassDecl(classDecl, temp, ExpUsage::Return);
2877 popScope();
2878 temp.push_back(s("end)()"sv));
2879 out.push_back(join(temp));
2880 }
2881
2882 void transformClassDecl(ClassDecl_t* classDecl, str_list& out, ExpUsage usage = ExpUsage::Common, ExpList_t* expList = nullptr) {
2883 str_list temp;
2884 auto x = classDecl;
2885 auto body = classDecl->body.get();
2886 auto assignable = classDecl->name.get();
2887 auto extend = classDecl->extend.get();
2888 std::string className;
2889 std::string assignItem;
2890 if (assignable) {
2891 if (!isAssignable(assignable)) {
2892 throw std::logic_error(debugInfo("Left hand expression is not assignable."sv, assignable));
2893 }
2894 bool newDefined = false;
2895 std::tie(className, newDefined) = defineClassVariable(assignable);
2896 if (newDefined) {
2897 temp.push_back(indent() + s("local "sv) + className + nll(classDecl));
2898 }
2899 if (className.empty()) {
2900 if (auto chain = ast_cast<AssignableChain_t>(assignable->item)) {
2901 if (auto dotChain = ast_cast<DotChainItem_t>(chain->items.back())) {
2902 className = s("\""sv) + toString(dotChain->name) + s("\""sv);
2903 } else if (auto index = ast_cast<Exp_t>(chain->items.back())) {
2904 if (auto name = index->getByPath<Value_t, String_t>()) {
2905 transformString(name, temp);
2906 className = temp.back();
2907 temp.pop_back();
2908 }
2909 }
2910 }
2911 } else {
2912 className = s("\""sv) + className + s("\""sv);
2913 }
2914 pushScope();
2915 transformAssignable(assignable, temp);
2916 popScope();
2917 assignItem = temp.back();
2918 temp.pop_back();
2919 } else if (expList) {
2920 auto name = singleVariableFrom(expList);
2921 if (!name.empty()) {
2922 className = s("\""sv) + name + s("\""sv);
2923 }
2924 }
2925 temp.push_back(indent() + s("do"sv) + nll(classDecl));
2926 pushScope();
2927 auto classVar = getUnusedName("_class_"sv);
2928 addToScope(classVar);
2929 temp.push_back(indent() + s("local "sv) + classVar + nll(classDecl));
2930 if (body) {
2931 str_list varDefs;
2932 for (auto item : body->contents.objects()) {
2933 if (auto statement = ast_cast<Statement_t>(item)) {
2934 ClassDecl_t* clsDecl = nullptr;
2935 if (auto assignment = assignmentFrom(statement)) {
2936 auto names = transformAssignDefs(assignment->expList.get());
2937 varDefs.insert(varDefs.end(), names.begin(), names.end());
2938 auto info = extractDestructureInfo(assignment);
2939 if (!info.first.empty()) {
2940 for (const auto& destruct : info.first)
2941 for (const auto& item : destruct.items)
2942 if (item.isVariable && addToScope(item.name))
2943 varDefs.push_back(item.name);
2944 }
2945 BLOCK_START
2946 auto assign = assignment->action.as<Assign_t>();
2947 BREAK_IF(!assign);
2948 BREAK_IF(assign->values.objects().size() != 1);
2949 auto exp = ast_cast<Exp_t>(assign->values.objects().front());
2950 BREAK_IF(!exp);
2951 auto value = singleValueFrom(exp);
2952 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
2953 BLOCK_END
2954 } else if (auto expList = expListFrom(statement)) {
2955 auto value = singleValueFrom(expList);
2956 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
2957 }
2958 if (clsDecl) {
2959 std::string clsName;
2960 bool newDefined = false;
2961 std::tie(clsName,newDefined) = defineClassVariable(clsDecl->name);
2962 if (newDefined) varDefs.push_back(clsName);
2963 }
2964 }
2965 }
2966 if (!varDefs.empty()) {
2967 temp.push_back(indent() + s("local ") + join(varDefs, ", "sv) + nll(body));
2968 }
2969 }
2970 std::string parent, parentVar;
2971 if (extend) {
2972 parentVar = getUnusedName("_parent_"sv);
2973 addToScope(parentVar);
2974 transformExp(extend, temp);
2975 parent = temp.back();
2976 temp.pop_back();
2977 temp.push_back(indent() + s("local "sv) + parentVar + s(" = "sv) + parent + nll(classDecl));
2978 }
2979 auto baseVar = getUnusedName("_base_"sv);
2980 addToScope(baseVar);
2981 temp.push_back(indent() + s("local "sv) + baseVar + s(" = "sv));
2982 str_list builtins;
2983 str_list commons;
2984 str_list statements;
2985 if (body) {
2986 std::list<ClassMember> members;
2987 for (auto content : classDecl->body->contents.objects()) {
2988 switch (content->getId()) {
2989 case "class_member_list"_id: {
2990 size_t inc = transform_class_member_list(static_cast<class_member_list_t*>(content), members, classVar);
2991 auto it = members.end();
2992 for (size_t i = 0; i < inc; ++i, --it);
2993 for (; it != members.end(); ++it) {
2994 auto& member = *it;
2995 if (member.type == MemType::Property) {
2996 statements.push_back(indent() + member.item + nll(content));
2997 } else {
2998 member.item = indent(1) + member.item;
2999 }
3000 }
3001 break;
3002 }
3003 case "Statement"_id:
3004 transformStatement(static_cast<Statement_t*>(content), statements);
3005 break;
3006 default: break;
3007 }
3008 }
3009 for (auto& member : members) {
3010 switch (member.type) {
3011 case MemType::Common:
3012 commons.push_back((commons.empty() ? Empty : s(","sv) + nll(member.node)) + member.item);
3013 break;
3014 case MemType::Builtin:
3015 builtins.push_back((builtins.empty() ? Empty : s(","sv) + nll(member.node)) + member.item);
3016 break;
3017 default: break;
3018 }
3019 }
3020 if (!commons.empty()) {
3021 temp.back() += s("{"sv) + nll(body);
3022 temp.push_back(join(commons) + nll(body));
3023 temp.push_back(indent() + s("}"sv) + nll(body));
3024 } else {
3025 temp.back() += s("{ }"sv) + nll(body);
3026 }
3027 } else {
3028 temp.back() += s("{ }"sv) + nll(classDecl);
3029 }
3030 temp.push_back(indent() + baseVar + s(".__index = "sv) + baseVar + nll(classDecl));
3031 str_list tmp;
3032 if (usage == ExpUsage::Assignment) {
3033 auto assign = x->new_ptr<Assign_t>();
3034 assign->values.push_back(toAst<Exp_t>(classVar, Exp, x));
3035 auto assignment = x->new_ptr<ExpListAssign_t>();
3036 assignment->expList.set(expList);
3037 assignment->action.set(assign);
3038 transformAssignment(assignment, tmp);
3039 }
3040 if (extend) {
3041 _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nll(classDecl);
3042 }
3043 _buf << indent() << classVar << " = setmetatable({" << nll(classDecl);
3044 if (!builtins.empty()) {
3045 _buf << join(builtins) << ","sv << nll(classDecl);
3046 } else {
3047 if (extend) {
3048 _buf << indent(1) << "__init = function(self, ...)"sv << nll(classDecl);
3049 _buf << indent(2) << "return _class_0.__parent.__init(self, ...)"sv << nll(classDecl);
3050 _buf << indent(1) << "end,"sv << nll(classDecl);
3051 } else {
3052 _buf << indent(1) << "__init = function() end,"sv << nll(classDecl);
3053 }
3054 }
3055 _buf << indent(1) << "__base = "sv << baseVar;
3056 if (!className.empty()) {
3057 _buf << ","sv << nll(classDecl) << indent(1) << "__name = "sv << className << (extend ? s(","sv) : Empty) << nll(classDecl);
3058 } else {
3059 _buf << nll(classDecl);
3060 }
3061 if (extend) {
3062 _buf << indent(1) << "__parent = "sv << parentVar << nll(classDecl);
3063 }
3064 _buf << indent() << "}, {"sv << nll(classDecl);
3065 if (extend) {
3066 _buf << indent(1) << "__index = function(cls, name)"sv << nll(classDecl);
3067 _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nll(classDecl);
3068 _buf << indent(2) << "if val == nil then"sv << nll(classDecl);
3069 _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nll(classDecl);
3070 _buf << indent(3) << "if parent then"sv << nll(classDecl);
3071 _buf << indent(4) << "return parent[name]"sv << nll(classDecl);
3072 _buf << indent(3) << "end"sv << nll(classDecl);
3073 _buf << indent(2) << "else"sv << nll(classDecl);
3074 _buf << indent(3) << "return val"sv << nll(classDecl);
3075 _buf << indent(2) << "end"sv << nll(classDecl);
3076 _buf << indent(1) << "end,"sv << nll(classDecl);
3077 } else {
3078 _buf << indent(1) << "__index = "sv << baseVar << ","sv << nll(classDecl);
3079 }
3080 _buf << indent(1) << "__call = function(cls, ...)"sv << nll(classDecl);
3081 pushScope();
3082 auto selfVar = getUnusedName("_self_"sv);
3083 addToScope(selfVar);
3084 _buf << indent(1) << "local " << selfVar << " = setmetatable({}, "sv << baseVar << ")"sv << nll(classDecl);
3085 _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nll(classDecl);
3086 _buf << indent(1) << "return "sv << selfVar << nll(classDecl);
3087 popScope();
3088 _buf << indent(1) << "end"sv << nll(classDecl);
3089 _buf << indent() << "})"sv << nll(classDecl);
3090 _buf << indent() << baseVar << ".__class = "sv << classVar << nll(classDecl);
3091 if (!statements.empty()) _buf << indent() << "local self = "sv << classVar << nll(classDecl);
3092 _buf << join(statements);
3093 if (extend) {
3094 _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nll(classDecl);
3095 _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nll(classDecl);
3096 _buf << indent() << "end"sv << nll(classDecl);
3097 }
3098 if (!assignItem.empty()) {
3099 _buf << indent() << assignItem << " = "sv << classVar << nll(classDecl);
3100 }
3101 switch (usage) {
3102 case ExpUsage::Return: {
3103 _buf << indent() << "return "sv << classVar << nlr(classDecl);
3104 break;
3105 }
3106 case ExpUsage::Assignment: {
3107 _buf << tmp.back();
3108 break;
3109 }
3110 default: break;
3111 }
3112 temp.push_back(clearBuf());
3113 popScope();
3114 temp.push_back(indent() + s("end"sv) + nlr(classDecl));
3115 out.push_back(join(temp));
3116 }
3117
3118 size_t transform_class_member_list(class_member_list_t* class_member_list, std::list<ClassMember>& out, const std::string& classVar) {
3119 str_list temp;
3120 size_t count = 0;
3121 for (auto keyValue : class_member_list->values.objects()) {
3122 MemType type = MemType::Common;
3123 BLOCK_START
3124 auto normal_pair = ast_cast<normal_pair_t>(keyValue);
3125 BREAK_IF(!normal_pair);
3126 auto keyName = normal_pair->key.as<KeyName_t>();
3127 BREAK_IF(!keyName);
3128 std::string newSuperCall;
3129 auto selfName = keyName->name.as<SelfName_t>();
3130 if (selfName) {
3131 type = MemType::Property;
3132 auto name = ast_cast<self_name_t>(selfName->name);
3133 if (!name) throw std::logic_error(debugInfo("Invalid class poperty name."sv, selfName->name));
3134 newSuperCall = classVar + s(".__parent."sv) + toString(name->name);
3135 } else {
3136 auto x = keyName;
3137 auto nameNode = keyName->name.as<Name_t>();
3138 if (!nameNode) break;
3139 auto name = toString(nameNode);
3140 if (name == "new"sv) {
3141 type = MemType::Builtin;
3142 keyName->name.set(toAst<Name_t>("__init"sv, Name, x));
3143 newSuperCall = classVar + s(".__parent.__init"sv);
3144 } else {
3145 newSuperCall = classVar + s(".__parent.__base."sv) + name;
3146 }
3147 }
3148 normal_pair->value->traverse([&](ast_node* node) {
3149 if (node->getId() == "ClassDecl"_id) return traversal::Return;
3150 if (auto chainValue = ast_cast<ChainValue_t>(node)) {
3151 if (auto callable = ast_cast<Callable_t>(chainValue->items.front())) {
3152 auto var = callable->item.get();
3153 if (toString(var) == "super"sv) {
3154 auto insertSelfToArguments = [&](ast_node* item) {
3155 auto x = item;
3156 switch (item->getId()) {
3157 case "InvokeArgs"_id: {
3158 auto invoke = static_cast<InvokeArgs_t*>(item);
3159 invoke->args.push_front(toAst<Exp_t>("self"sv, Exp, x));
3160 return true;
3161 }
3162 case "Invoke"_id: {
3163 auto invoke = static_cast<Invoke_t*>(item);
3164 invoke->args.push_front(toAst<Exp_t>("self"sv, Exp, x));
3165 return true;
3166 }
3167 default:
3168 return false;
3169 }
3170 };
3171 const auto& chainList = chainValue->items.objects();
3172 if (chainList.size() >= 2) {
3173 auto it = chainList.begin();
3174 auto secondItem = *(++it);
3175 if (!insertSelfToArguments(secondItem)) {
3176 if (auto colonChainItem = ast_cast<ColonChainItem_t>(secondItem)) {
3177 if (chainList.size() > 2 && insertSelfToArguments(*(++it))) {
3178 colonChainItem->switchToDot = true;
3179 }
3180 }
3181 newSuperCall = classVar + s(".__parent"sv);
3182 }
3183 } else {
3184 newSuperCall = classVar + s(".__parent"sv);
3185 }
3186 auto newChain = toAst<ChainValue_t>(newSuperCall, ChainValue, chainValue);
3187 chainValue->items.pop_front();
3188 const auto& items = newChain->items.objects();
3189 for (auto it = items.rbegin(); it != items.rend(); ++it) {
3190 chainValue->items.push_front(*it);
3191 }
3192 }
3193 }
3194 }
3195 return traversal::Continue;
3196 });
3197 BLOCK_END
3198 pushScope();
3199 if (type == MemType::Property) {
3200 decIndentOffset();
3201 }
3202 switch (keyValue->getId()) {
3203 case "variable_pair"_id:
3204 transform_variable_pair(static_cast<variable_pair_t*>(keyValue), temp);
3205 break;
3206 case "normal_pair"_id:
3207 transform_normal_pair(static_cast<normal_pair_t*>(keyValue), temp);
3208 break;
3209 }
3210 if (type == MemType::Property) {
3211 incIndentOffset();
3212 }
3213 popScope();
3214 out.push_back({temp.back(), type, keyValue});
3215 temp.clear();
3216 ++count;
3217 }
3218 return count;
3219 }
3220
3221 void transformAssignable(Assignable_t* assignable, str_list& out) {
3222 auto item = assignable->item.get();
3223 switch (item->getId()) {
3224 case "AssignableChain"_id: transformAssignableChain(static_cast<AssignableChain_t*>(item), out); break;
3225 case "Variable"_id: transformVariable(static_cast<Variable_t*>(item), out); break;
3226 case "SelfName"_id: transformSelfName(static_cast<SelfName_t*>(item), out, false); break;
3227 default: break;
3228 }
3229 }
3230
3231 void transformWithClosure(With_t* with, str_list& out) {
3232 str_list temp;
3233 temp.push_back(s("(function()"sv) + nll(with));
3234 pushScope();
3235 transformWith(with, temp, nullptr, true);
3236 popScope();
3237 temp.push_back(indent() + s("end)()"sv));
3238 out.push_back(join(temp));
3239 }
3240
3241 void transformWith(With_t* with, str_list& out, ExpList_t* assignList = nullptr, bool returnValue = false) {
3242 auto x = with;
3243 str_list temp;
3244 std::string withVar;
3245 bool scoped = false;
3246 if (with->assigns) {
3247 checkAssignable(with->valueList);
3248 auto vars = getAssignVars(with);
3249 if (vars.front().empty()) {
3250 if (_config.reuseVariable && with->assigns->values.objects().size() == 1) {
3251 auto var = singleVariableFrom(with->assigns->values.objects().front());
3252 if (!var.empty()) {
3253 withVar = var;
3254 }
3255 }
3256 if (withVar.empty()) {
3257 withVar = getUnusedName("_with_");
3258 auto assignment = x->new_ptr<ExpListAssign_t>();
3259 assignment->expList.set(toAst<ExpList_t>(withVar, ExpList, x));
3260 auto assign = x->new_ptr<Assign_t>();
3261 assign->values.push_back(with->assigns->values.objects().front());
3262 assignment->action.set(assign);
3263 if (!returnValue) {
3264 scoped = true;
3265 temp.push_back(indent() + s("do"sv) + nll(with));
3266 pushScope();
3267 }
3268 transformAssignment(assignment, temp);
3269 }
3270 auto assignment = x->new_ptr<ExpListAssign_t>();
3271 assignment->expList.set(with->valueList);
3272 auto assign = x->new_ptr<Assign_t>();
3273 assign->values.push_back(toAst<Exp_t>(withVar, Exp, x));
3274 bool skipFirst = true;
3275 for (auto value : with->assigns->values.objects()) {
3276 if (skipFirst) {
3277 skipFirst = false;
3278 continue;
3279 }
3280 assign->values.push_back(value);
3281 }
3282 assignment->action.set(assign);
3283 transformAssignment(assignment, temp);
3284 } else {
3285 withVar = vars.front();
3286 auto assignment = x->new_ptr<ExpListAssign_t>();
3287 assignment->expList.set(with->valueList);
3288 assignment->action.set(with->assigns);
3289 if (!returnValue) {
3290 scoped = true;
3291 temp.push_back(indent() + s("do"sv) + nll(with));
3292 pushScope();
3293 }
3294 transformAssignment(assignment, temp);
3295 }
3296 } else {
3297 if (_config.reuseVariable) withVar = singleVariableFrom(with->valueList);
3298 if (withVar.empty()) {
3299 withVar = getUnusedName("_with_");
3300 auto assignment = x->new_ptr<ExpListAssign_t>();
3301 assignment->expList.set(toAst<ExpList_t>(withVar, ExpList, x));
3302 auto assign = x->new_ptr<Assign_t>();
3303 assign->values.dup(with->valueList->exprs);
3304 assignment->action.set(assign);
3305 if (!returnValue) {
3306 scoped = true;
3307 temp.push_back(indent() + s("do"sv) + nll(with));
3308 pushScope();
3309 }
3310 transformAssignment(assignment, temp);
3311 }
3312 }
3313 if (!scoped && !returnValue) {
3314 pushScope();
3315 scoped = traversal::Stop == with->body->traverse([&](ast_node* node) {
3316 if (auto statement = ast_cast<Statement_t>(node)) {
3317 ClassDecl_t* clsDecl = nullptr;
3318 if (auto assignment = assignmentFrom(statement)) {
3319 auto names = getAssignDefs(assignment->expList.get());
3320 if (!names.empty()) {
3321 return traversal::Stop;
3322 }
3323 auto info = extractDestructureInfo(assignment);
3324 if (!info.first.empty()) {
3325 for (const auto& destruct : info.first)
3326 for (const auto& item : destruct.items)
3327 if (item.isVariable && !isDefined(item.name))
3328 return traversal::Stop;
3329 }
3330 BLOCK_START
3331 auto assign = assignment->action.as<Assign_t>();
3332 BREAK_IF(!assign);
3333 BREAK_IF(assign->values.objects().size() != 1);
3334 auto exp = ast_cast<Exp_t>(assign->values.objects().front());
3335 BREAK_IF(!exp);
3336 if (auto value = singleValueFrom(exp)) {
3337 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
3338 }
3339 BLOCK_END
3340 } else if (auto expList = expListFrom(statement)) {
3341 auto value = singleValueFrom(expList);
3342 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
3343 }
3344 if (clsDecl) {
3345 auto variable = clsDecl->name.as<Variable_t>();
3346 if (!isDefined(toString(variable))) return traversal::Stop;
3347 }
3348 return traversal::Return;
3349 }
3350 return traversal::Continue;
3351 });
3352 popScope();
3353 if (scoped) {
3354 temp.push_back(indent() + s("do"sv) + nll(with));
3355 pushScope();
3356 }
3357 }
3358 _withVars.push(withVar);
3359 transformBody(with->body, temp);
3360 _withVars.pop();
3361 if (assignList) {
3362 auto assignment = x->new_ptr<ExpListAssign_t>();
3363 assignment->expList.set(assignList);
3364 auto assign = x->new_ptr<Assign_t>();
3365 assign->values.push_back(toAst<Exp_t>(withVar, Exp, x));
3366 assignment->action.set(assign);
3367 transformAssignment(assignment, temp);
3368 }
3369 if (returnValue) {
3370 auto stmt = lastStatementFrom(with->body);
3371 if (!stmt->content.is<Return_t>()) {
3372 temp.push_back(indent() + s("return "sv) + withVar + nll(with));
3373 }
3374 }
3375 if (scoped) {
3376 popScope();
3377 temp.push_back(indent() + s("end"sv) + nll(with));
3378 }
3379 out.push_back(join(temp));
3380 }
3381
3382 void transform_const_value(const_value_t* const_value, str_list& out) {
3383 out.push_back(toString(const_value));
3384 }
3385
3386 void transformExport(Export_t* exportNode, str_list& out) {
3387 auto x = exportNode;
3388 auto item = exportNode->item.get();
3389 switch (item->getId()) {
3390 case "ClassDecl"_id: {
3391 auto classDecl = static_cast<ClassDecl_t*>(item);
3392 if (classDecl->name && classDecl->name->item->getId() == "Variable"_id) {
3393 markVarExported(ExportMode::Any, true);
3394 addExportedVar(toString(classDecl->name->item));
3395 }
3396 transformClassDecl(classDecl, out);
3397 break;
3398 }
3399 case "export_op"_id:
3400 if (toString(item) == "*"sv) {
3401 markVarExported(ExportMode::Any, false);
3402 } else {
3403 markVarExported(ExportMode::Capital, false);
3404 }
3405 break;
3406 case "export_values"_id: {
3407 markVarExported(ExportMode::Any, true);
3408 auto values = exportNode->item.to<export_values_t>();
3409 if (values->valueList) {
3410 auto expList = x->new_ptr<ExpList_t>();
3411 for (auto name : values->nameList->names.objects()) {
3412 addExportedVar(toString(name));
3413 auto callable = x->new_ptr<Callable_t>();
3414 callable->item.set(name);
3415 auto chainValue = x->new_ptr<ChainValue_t>();
3416 chainValue->items.push_back(callable);
3417 auto value = x->new_ptr<Value_t>();
3418 value->item.set(chainValue);
3419 auto exp = x->new_ptr<Exp_t>();
3420 exp->value.set(value);
3421 expList->exprs.push_back(exp);
3422 }
3423 auto assignment = x->new_ptr<ExpListAssign_t>();
3424 assignment->expList.set(expList);
3425 auto assign = x->new_ptr<Assign_t>();
3426 assign->values.dup(values->valueList->exprs);
3427 assignment->action.set(assign);
3428 transformAssignment(assignment, out);
3429 } else {
3430 for (auto name : values->nameList->names.objects()) {
3431 addExportedVar(toString(name));
3432 }
3433 }
3434 break;
3435 }
3436 default:
3437 break;
3438 }
3439 }
3440
3441 void transformTable(ast_node* table, const node_container& pairs, str_list& out) {
3442 if (pairs.empty()) {
3443 out.push_back(s("{ }"sv));
3444 return;
3445 }
3446 str_list temp;
3447 pushScope();
3448 for (auto pair : pairs) {
3449 switch (pair->getId()) {
3450 case "Exp"_id: transformExp(static_cast<Exp_t*>(pair), temp); break;
3451 case "variable_pair"_id: transform_variable_pair(static_cast<variable_pair_t*>(pair), temp); break;
3452 case "normal_pair"_id: transform_normal_pair(static_cast<normal_pair_t*>(pair), temp); break;
3453 }
3454 temp.back() = indent() + temp.back() + (pair == pairs.back() ? Empty : s(","sv)) + nll(pair);
3455 }
3456 out.push_back(s("{"sv) + nll(table) + join(temp));
3457 popScope();
3458 out.back() += (indent() + s("}"sv));
3459 }
3460
3461 void transform_simple_table(simple_table_t* table, str_list& out) {
3462 transformTable(table, table->pairs.objects(), out);
3463 }
3464
3465 void transformTblComprehension(TblComprehension_t* comp, str_list& out) {
3466 str_list kv;
3467 std::string tbl = getUnusedName("_tbl_");
3468 addToScope(tbl);
3469 str_list temp;
3470 auto compInner = comp->forLoop.get();
3471 for (auto item : compInner->items.objects()) {
3472 switch (item->getId()) {
3473 case "CompForEach"_id:
3474 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
3475 break;
3476 case "CompFor"_id:
3477 transformCompFor(static_cast<CompFor_t*>(item), temp);
3478 break;
3479 case "Exp"_id:
3480 transformExp(static_cast<Exp_t*>(item), temp);
3481 temp.back() = indent() + s("if "sv) + temp.back() + s(" then"sv) + nll(item);
3482 pushScope();
3483 break;
3484 }
3485 }
3486 transformExp(comp->key, kv);
3487 if (comp->value) {
3488 transformExp(comp->value->value, kv);
3489 }
3490 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
3491 popScope();
3492 }
3493 _buf << indent() << "local "sv << tbl << " = { }"sv << nll(comp);
3494 _buf << join(temp);
3495 pushScope();
3496 if (!comp->value) {
3497 auto keyVar = getUnusedName("_key_");
3498 auto valVar = getUnusedName("_val_");
3499 _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nll(comp);
3500 kv.front() = keyVar;
3501 kv.push_back(valVar);
3502 }
3503 _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nll(comp);
3504 for (int ind = int(temp.size()) - 2; ind > -1 ; --ind) {
3505 _buf << indent(ind) << "end"sv << nll(comp);
3506 }
3507 popScope();
3508 _buf << indent() << "end"sv << nll(comp);
3509 out.push_back(tbl);
3510 out.push_back(clearBuf());
3511 }
3512
3513 void transformTblCompInPlace(TblComprehension_t* comp, ExpList_t* expList, str_list& out) {
3514 auto x = comp;
3515 str_list temp;
3516 auto ind = indent();
3517 pushScope();
3518 transformTblComprehension(comp, temp);
3519 auto assign = x->new_ptr<Assign_t>();
3520 assign->values.push_back(toAst<Exp_t>(temp.front(), Exp, x));
3521 auto assignment = x->new_ptr<ExpListAssign_t>();
3522 assignment->expList.set(expList);
3523 assignment->action.set(assign);
3524 transformAssignment(assignment, temp);
3525 out.push_back(
3526 ind + s("do"sv) + nll(comp) +
3527 *(++temp.begin()) +
3528 temp.back());
3529 popScope();
3530 out.back() = out.back() + indent() + s("end"sv) + nlr(comp);
3531 }
3532
3533 void transformTblCompReturn(TblComprehension_t* comp, str_list& out) {
3534 str_list temp;
3535 transformTblComprehension(comp, temp);
3536 out.push_back(temp.back() + indent() + s("return "sv) + temp.front() + nlr(comp));
3537 }
3538
3539 void transformTblCompClosure(TblComprehension_t* comp, str_list& out) {
3540 str_list temp;
3541 std::string before = s("(function()"sv) + nll(comp);
3542 pushScope();
3543 transformTblComprehension(comp, temp);
3544 const auto& tbVar = temp.front();
3545 const auto& compBody = temp.back();
3546 out.push_back(
3547 before +
3548 compBody +
3549 indent() + s("return "sv) + tbVar + nlr(comp));
3550 popScope();
3551 out.back() = out.back() + indent() + s("end)()"sv);
3552 }
3553
3554 void transformCompFor(CompFor_t* comp, str_list& out) {
3555 str_list temp;
3556 std::string varName = toString(comp->varName);
3557 transformExp(comp->startValue, temp);
3558 transformExp(comp->stopValue, temp);
3559 if (comp->stepValue) {
3560 transformExp(comp->stepValue->value, temp);
3561 } else {
3562 temp.emplace_back();
3563 }
3564 auto it = temp.begin();
3565 const auto& start = *it;
3566 const auto& stop = *(++it);
3567 const auto& step = *(++it);
3568 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : s(", "sv) + step) << " do"sv << nll(comp);
3569 out.push_back(clearBuf());
3570 pushScope();
3571 addToScope(varName);
3572 }
3573
3574 void transformTableBlock(TableBlock_t* table, str_list& out) {
3575 transformTable(table, table->values.objects(), out);
3576 }
3577
3578 void transformDo(Do_t* doNode, str_list& out, bool implicitReturn = false) {
3579 str_list temp;
3580 temp.push_back(indent() + s("do"sv) + nll(doNode));
3581 pushScope();
3582 transformBody(doNode->body, temp, implicitReturn);
3583 popScope();
3584 temp.push_back(indent() + s("end"sv) + nlr(doNode));
3585 out.push_back(join(temp));
3586 }
3587
3588 void transformDoClosure(Do_t* doNode, str_list& out) {
3589 str_list temp;
3590 temp.push_back(s("(function()"sv) + nll(doNode));
3591 pushScope();
3592 transformBody(doNode->body, temp, true);
3593 popScope();
3594 temp.push_back(indent() + s("end)()"sv));
3595 out.push_back(join(temp));
3596 }
3597
3598 void transformImport(Import_t* import, str_list& out) {
3599 str_list temp;
3600 auto x = import;
3601 auto objVar = singleVariableFrom(import->exp);
3602 ast_ptr<false, ExpListAssign_t> objAssign;
3603 if (objVar.empty()) {
3604 objVar = getUnusedName("_obj_"sv);
3605 auto expList = toAst<ExpList_t>(objVar, ExpList, x);
3606 auto assign = x->new_ptr<Assign_t>();
3607 assign->values.push_back(import->exp);
3608 auto assignment = x->new_ptr<ExpListAssign_t>();
3609 assignment->expList.set(expList);
3610 assignment->action.set(assign);
3611 objAssign.set(assignment);
3612 }
3613 auto expList = x->new_ptr<ExpList_t>();
3614 auto assign = x->new_ptr<Assign_t>();
3615 for (auto name : import->names.objects()) {
3616 switch (name->getId()) {
3617 case "Variable"_id: {
3618 auto var = ast_to<Variable_t>(name);
3619 {
3620 auto callable = toAst<Callable_t>(objVar, Callable, x);
3621 auto dotChainItem = x->new_ptr<DotChainItem_t>();
3622 dotChainItem->name.set(var->name);
3623 auto chainValue = x->new_ptr<ChainValue_t>();
3624 chainValue->items.push_back(callable);
3625 chainValue->items.push_back(dotChainItem);
3626 auto value = x->new_ptr<Value_t>();
3627 value->item.set(chainValue);
3628 auto exp = x->new_ptr<Exp_t>();
3629 exp->value.set(value);
3630 assign->values.push_back(exp);
3631 }
3632 auto callable = x->new_ptr<Callable_t>();
3633 callable->item.set(var);
3634 auto chainValue = x->new_ptr<ChainValue_t>();
3635 chainValue->items.push_back(callable);
3636 auto value = x->new_ptr<Value_t>();
3637 value->item.set(chainValue);
3638 auto exp = x->new_ptr<Exp_t>();
3639 exp->value.set(value);
3640 expList->exprs.push_back(exp);
3641 break;
3642 }
3643 case "colon_import_name"_id: {
3644 auto var = static_cast<colon_import_name_t*>(name)->name.get();
3645 {
3646 auto nameNode = var->name.get();
3647 auto callable = toAst<Callable_t>(objVar, Callable, x);
3648 auto colonChain = x->new_ptr<ColonChainItem_t>();
3649 colonChain->name.set(nameNode);
3650 auto chainValue = x->new_ptr<ChainValue_t>();
3651 chainValue->items.push_back(callable);
3652 chainValue->items.push_back(colonChain);
3653 auto value = x->new_ptr<Value_t>();
3654 value->item.set(chainValue);
3655 auto exp = x->new_ptr<Exp_t>();
3656 exp->value.set(value);
3657 assign->values.push_back(exp);
3658 }
3659 auto callable = x->new_ptr<Callable_t>();
3660 callable->item.set(var);
3661 auto chainValue = x->new_ptr<ChainValue_t>();
3662 chainValue->items.push_back(callable);
3663 auto value = x->new_ptr<Value_t>();
3664 value->item.set(chainValue);
3665 auto exp = x->new_ptr<Exp_t>();
3666 exp->value.set(value);
3667 expList->exprs.push_back(exp);
3668 break;
3669 }
3670 }
3671 }
3672 if (objAssign) {
3673 auto preDef = getPredefine(transformAssignDefs(expList));
3674 if (!preDef.empty()) {
3675 temp.push_back(preDef + nll(import));
3676 }
3677 temp.push_back(indent() + s("do"sv) + nll(import));
3678 pushScope();
3679 transformAssignment(objAssign, temp);
3680 }
3681 auto assignment = x->new_ptr<ExpListAssign_t>();
3682 assignment->expList.set(expList);
3683 assignment->action.set(assign);
3684 transformAssignment(assignment, temp);
3685 if (objAssign) {
3686 popScope();
3687 temp.push_back(indent() + s("end"sv) + nlr(import));
3688 }
3689 out.push_back(join(temp));
3690 }
3691
3692 void transformWhileInPlace(While_t* whileNode, str_list& out, ExpList_t* expList = nullptr) {
3693 auto x = whileNode;
3694 str_list temp;
3695 if (expList) {
3696 temp.push_back(indent() + s("do"sv) + nll(whileNode));
3697 }
3698 pushScope();
3699 auto accumVar = getUnusedName("_accum_"sv);
3700 addToScope(accumVar);
3701 auto lenVar = getUnusedName("_len_"sv);
3702 addToScope(lenVar);
3703 temp.push_back(indent() + s("local "sv) + accumVar + s(" = { }"sv) + nll(whileNode));
3704 temp.push_back(indent() + s("local "sv) + lenVar + s(" = 1"sv) + nll(whileNode));
3705 transformExp(whileNode->condition, temp);
3706 temp.back() = indent() + s("while "sv) + temp.back() + s(" do"sv) + nll(whileNode);
3707 pushScope();
3708 auto assignLeft = toAst<ExpList_t>(accumVar + s("["sv) + lenVar + s("]"sv), ExpList, x);
3709 assignLastExplist(assignLeft, whileNode->body);
3710 auto lenLine = lenVar + s(" = "sv) + lenVar + s(" + 1"sv) + nlr(whileNode);
3711 transformLoopBody(whileNode->body, temp, lenLine);
3712 popScope();
3713 temp.push_back(indent() + s("end"sv) + nlr(whileNode));
3714 if (expList) {
3715 auto assign = x->new_ptr<Assign_t>();
3716 assign->values.push_back(toAst<Exp_t>(accumVar, Exp, x));
3717 auto assignment = x->new_ptr<ExpListAssign_t>();
3718 assignment->expList.set(expList);
3719 assignment->action.set(assign);
3720 transformAssignment(assignment, temp);
3721 } else {
3722 temp.push_back(indent() + s("return "sv) + accumVar + nlr(whileNode));
3723 }
3724 popScope();
3725 if (expList) {
3726 temp.push_back(indent() + s("end"sv) + nlr(whileNode));
3727 }
3728 out.push_back(join(temp));
3729 }
3730
3731 void transformWhileClosure(While_t* whileNode, str_list& out) {
3732 auto x = whileNode;
3733 str_list temp;
3734 temp.push_back(s("(function() "sv) + nll(whileNode));
3735 pushScope();
3736 auto accumVar = getUnusedName("_accum_"sv);
3737 addToScope(accumVar);
3738 auto lenVar = getUnusedName("_len_"sv);
3739 addToScope(lenVar);
3740 temp.push_back(indent() + s("local "sv) + accumVar + s(" = { }"sv) + nll(whileNode));
3741 temp.push_back(indent() + s("local "sv) + lenVar + s(" = 1"sv) + nll(whileNode));
3742 transformExp(whileNode->condition, temp);
3743 temp.back() = indent() + s("while "sv) + temp.back() + s(" do"sv) + nll(whileNode);
3744 pushScope();
3745 auto assignLeft = toAst<ExpList_t>(accumVar + s("["sv) + lenVar + s("]"sv), ExpList, x);
3746 assignLastExplist(assignLeft, whileNode->body);
3747 auto lenLine = lenVar + s(" = "sv) + lenVar + s(" + 1"sv) + nlr(whileNode);
3748 transformLoopBody(whileNode->body, temp, lenLine);
3749 popScope();
3750 temp.push_back(indent() + s("end"sv) + nlr(whileNode));
3751 temp.push_back(indent() + s("return "sv) + accumVar + nlr(whileNode));
3752 popScope();
3753 temp.push_back(indent() + s("end)()"sv));
3754 out.push_back(join(temp));
3755 }
3756
3757 void transformWhile(While_t* whileNode, str_list& out) {
3758 str_list temp;
3759 pushScope();
3760 transformExp(whileNode->condition, temp);
3761 transformLoopBody(whileNode->body, temp, Empty);
3762 popScope();
3763 _buf << indent() << "while "sv << temp.front() << " do"sv << nll(whileNode);
3764 _buf << temp.back();
3765 _buf << indent() << "end"sv << nlr(whileNode);
3766 out.push_back(clearBuf());
3767 }
3768
3769 void transformSwitchClosure(Switch_t* switchNode, str_list& out) {
3770 str_list temp;
3771 temp.push_back(s("(function()"sv) + nll(switchNode));
3772 pushScope();
3773 transformSwitch(switchNode, temp, true);
3774 popScope();
3775 temp.push_back(indent() + s("end)()"sv));
3776 out.push_back(join(temp));
3777 }
3778
3779 void transformSwitch(Switch_t* switchNode, str_list& out, bool implicitReturn = false) {
3780 str_list temp;
3781 auto objVar = singleVariableFrom(switchNode->target);
3782 if (objVar.empty()) {
3783 objVar = getUnusedName("_exp_"sv);
3784 addToScope(objVar);
3785 transformExp(switchNode->target, temp);
3786 _buf << indent() << "local "sv << objVar << " = "sv << temp.back() << nll(switchNode);
3787 temp.back() = clearBuf();
3788 }
3789 const auto& branches = switchNode->branches.objects();
3790 for (auto branch_ : branches) {
3791 auto branch = static_cast<SwitchCase_t*>(branch_);
3792 temp.push_back(indent() + s(branches.front() == branch ? "if"sv : "elseif"sv));
3793 str_list tmp;
3794 const auto& exprs = branch->valueList->exprs.objects();
3795 for (auto exp_ : exprs) {
3796 auto exp = static_cast<Exp_t*>(exp_);
3797 transformExp(exp, tmp);
3798 if (!singleValueFrom(exp)) {
3799 tmp.back() = s("("sv) + tmp.back() + s(")"sv);
3800 }
3801 temp.back().append(s(" "sv) + tmp.back() + s(" == "sv) + objVar +
3802 s(exp == exprs.back() ? ""sv : " or"sv));
3803 }
3804 temp.back().append(s(" then"sv) + nll(branch));
3805 pushScope();
3806 transformBody(branch->body, temp, implicitReturn);
3807 popScope();
3808 }
3809 if (switchNode->lastBranch) {
3810 temp.push_back(indent() + s("else"sv) + nll(switchNode->lastBranch));
3811 pushScope();
3812 transformBody(switchNode->lastBranch, temp, implicitReturn);
3813 popScope();
3814 }
3815 temp.push_back(indent() + s("end"sv) + nlr(switchNode));
3816 out.push_back(join(temp));
3817 }
3818
3819 void transformLocal(Local_t* local, str_list& out) {
3820 if (!local->forceDecls.empty() || !local->decls.empty()) {
3821 str_list defs;
3822 for (const auto& decl : local->forceDecls) {
3823 forceAddToScope(decl);
3824 defs.push_back(decl);
3825 }
3826 for (const auto& decl : local->decls) {
3827 if (addToScope(decl)) {
3828 defs.push_back(decl);
3829 }
3830 }
3831 auto preDefine = getPredefine(defs);
3832 if (!preDefine.empty()) {
3833 out.push_back(preDefine + nll(local));
3834 }
3835 }
3836 }
3837
3838 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) {
3839 auto keyword = toString(breakLoop);
3840 if (keyword == "break"sv) {
3841 out.push_back(indent() + keyword + nll(breakLoop));
3842 return;
3843 }
3844 if (_continueVars.empty()) throw std::logic_error(debugInfo("Continue is not inside a loop."sv, breakLoop));
3845 _buf << indent() << _continueVars.top() << " = true"sv << nll(breakLoop);
3846 _buf << indent() << "break"sv << nll(breakLoop);
3847 out.push_back(clearBuf());
3848 }
3849};
3850
3851const std::string MoonCompliler::Empty;
3852
3853std::tuple<std::string,std::string,GlobalVars> moonCompile(const std::string& codes, const MoonConfig& config) {
3854 auto compiler = MoonCompliler{};
3855 auto result = compiler.complile(codes, config);
3856 auto globals = std::make_unique<std::list<GlobalVar>>();
3857 for (const auto& var : compiler.getGlobals()) {
3858 int line,col;
3859 std::tie(line,col) = var.second;
3860 globals->push_back({var.first, line, col});
3861 }
3862 return std::make_tuple(std::move(result.first),std::move(result.second),std::move(globals));
3863}
3864
3865} // namespace MoonP
diff --git a/src/MoonP/moon_compiler.h b/src/MoonP/moon_compiler.h
new file mode 100644
index 0000000..cb1990c
--- /dev/null
+++ b/src/MoonP/moon_compiler.h
@@ -0,0 +1,39 @@
1/* Copyright (c) 2020 Jin Li, http://www.luvfight.me
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
5The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
7THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
8
9#pragma once
10
11#include <string>
12#include <tuple>
13#include <list>
14#include <memory>
15
16namespace MoonP {
17
18const char* moonScriptVersion();
19
20struct MoonConfig {
21 bool lintGlobalVariable = false;
22 bool implicitReturnRoot = true;
23 bool reserveLineNumber = false;
24 bool spaceOverTab = false;
25 bool reuseVariable = false;
26 bool allowExprNotInTheEndOfBody = false;
27};
28
29struct GlobalVar {
30 std::string name;
31 int line;
32 int col;
33};
34
35using GlobalVars = std::unique_ptr<std::list<GlobalVar>>;
36
37std::tuple<std::string,std::string,GlobalVars> moonCompile(const std::string& codes, const MoonConfig& config = {});
38
39} // namespace MoonP
diff --git a/src/MoonP/moon_parser.cpp b/src/MoonP/moon_parser.cpp
new file mode 100644
index 0000000..7b5183e
--- /dev/null
+++ b/src/MoonP/moon_parser.cpp
@@ -0,0 +1,526 @@
1/* Copyright (c) 2020 Jin Li, http://www.luvfight.me
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
5The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
7THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
8
9#include "MoonP/moon_parser.h"
10
11namespace pl = parserlib;
12
13namespace MoonP {
14
15std::unordered_set<std::string> State::luaKeywords = {
16 "and", "break", "do", "else", "elseif",
17 "end", "false", "for", "function", "if",
18 "in", "local", "nil", "not", "or",
19 "repeat", "return", "then", "true", "until",
20 "while"
21};
22
23std::unordered_set<std::string> State::keywords = {
24 "and", "break", "do", "else", "elseif",
25 "end", "false", "for", "function", "if",
26 "in", "local", "nil", "not", "or",
27 "repeat", "return", "then", "true", "until",
28 "while", // Lua keywords
29 "class", "continue", "export", "extends", "from",
30 "import", "switch", "unless", "using", "when",
31 "with" // Moon keywords
32};
33
34rule plain_space = *set(" \t");
35rule Break = nl(-expr('\r') >> '\n');
36rule Any = Break | any();
37rule White = *(set(" \t") | Break);
38rule Stop = Break | eof();
39rule Comment = "--" >> *(not_(set("\r\n")) >> Any) >> and_(Stop);
40rule Indent = *set(" \t");
41rule Space = plain_space >> -Comment;
42rule SomeSpace = +set(" \t") >> -Comment;
43rule SpaceBreak = Space >> Break;
44rule EmptyLine = SpaceBreak;
45rule AlphaNum = range('a', 'z') | range('A', 'Z') | range('0', '9') | '_';
46rule Name = (range('a', 'z') | range('A', 'Z') | '_') >> *AlphaNum;
47rule Num =
48(
49 "0x" >>
50 +(range('0', '9') | range('a', 'f') | range('A', 'F')) >>
51 -(-set("uU") >> set("lL") >> set("lL"))
52) | (
53 +range('0', '9') >> -set("uU") >> set("lL") >> set("lL")
54) | (
55 (
56 (+range('0', '9') >> -('.' >> +range('0', '9'))) |
57 ('.' >> +range('0', '9'))
58 ) >> -(set("eE") >> -expr('-') >> +range('0', '9'))
59);
60rule Cut = false_();
61rule Seperator = true_();
62
63#define sym(str) (Space >> str)
64#define symx(str) expr(str)
65#define ensure(patt, finally) (((patt) >> (finally)) | ((finally) >> (Cut)))
66#define key(str) (Space >> str >> not_(AlphaNum))
67
68rule Variable = pl::user(Name, [](const item_t& item) {
69 State* st = reinterpret_cast<State*>(item.user_data);
70 for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it);
71 auto it = State::keywords.find(st->buffer);
72 st->buffer.clear();
73 return it == State::keywords.end();
74});
75
76rule LuaKeyword = pl::user(Name, [](const item_t& item) {
77 State* st = reinterpret_cast<State*>(item.user_data);
78 for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it);
79 auto it = State::luaKeywords.find(st->buffer);
80 st->buffer.clear();
81 return it != State::luaKeywords.end();
82});
83
84rule self = expr('@');
85rule self_name = '@' >> Name;
86rule self_class = expr("@@");
87rule self_class_name = "@@" >> Name;
88
89rule SelfName = Space >> (self_class_name | self_class | self_name | self);
90rule KeyName = SelfName | Space >> Name;
91rule VarArg = Space >> "...";
92
93rule check_indent = pl::user(Indent, [](const item_t& item) {
94 int indent = 0;
95 for (input_it i = item.begin; i != item.end; ++i) {
96 switch (*i) {
97 case ' ': indent++; break;
98 case '\t': indent += 4; break;
99 }
100 }
101 State* st = reinterpret_cast<State*>(item.user_data);
102 return st->indents.top() == indent;
103});
104rule CheckIndent = and_(check_indent);
105
106rule advance = pl::user(Indent, [](const item_t& item) {
107 int indent = 0;
108 for (input_it i = item.begin; i != item.end; ++i) {
109 switch (*i) {
110 case ' ': indent++; break;
111 case '\t': indent += 4; break;
112 }
113 }
114 State* st = reinterpret_cast<State*>(item.user_data);
115 int top = st->indents.top();
116 if (top != -1 && indent > top) {
117 st->indents.push(indent);
118 return true;
119 }
120 return false;
121});
122rule Advance = and_(advance);
123
124rule push_indent = pl::user(Indent, [](const item_t& item) {
125 int indent = 0;
126 for (input_it i = item.begin; i != item.end; ++i) {
127 switch (*i) {
128 case ' ': indent++; break;
129 case '\t': indent += 4; break;
130 }
131 }
132 State* st = reinterpret_cast<State*>(item.user_data);
133 st->indents.push(indent);
134 return true;
135});
136rule PushIndent = and_(push_indent);
137
138rule PreventIndent = pl::user(true_(), [](const item_t& item) {
139 State* st = reinterpret_cast<State*>(item.user_data);
140 st->indents.push(-1);
141 return true;
142});
143
144rule PopIndent = pl::user(true_(), [](const item_t& item) {
145 State* st = reinterpret_cast<State*>(item.user_data);
146 st->indents.pop();
147 return true;
148});
149
150extern rule Block;
151
152rule InBlock = Advance >> Block >> PopIndent;
153
154extern rule NameList;
155
156rule local_flag = expr('*') | expr('^');
157rule Local = key("local") >> ((Space >> local_flag) | NameList);
158
159rule colon_import_name = sym('\\') >> Space >> Variable;
160rule ImportName = colon_import_name | Space >> Variable;
161rule ImportNameList = Seperator >> *SpaceBreak >> ImportName >> *((+SpaceBreak | sym(',') >> *SpaceBreak) >> ImportName);
162
163extern rule Exp;
164
165rule Import = key("import") >> ImportNameList >> *SpaceBreak >> key("from") >> Exp;
166rule BreakLoop = (expr("break") | expr("continue")) >> not_(AlphaNum);
167
168extern rule ExpListLow, ExpList, Assign;
169
170rule Return = key("return") >> -ExpListLow;
171rule WithExp = ExpList >> -Assign;
172
173extern rule DisableDo, PopDo, Body;
174
175rule With = key("with") >> DisableDo >> ensure(WithExp, PopDo) >> -key("do") >> Body;
176rule SwitchCase = key("when") >> ExpList >> -key("then") >> Body;
177rule SwitchElse = key("else") >> Body;
178
179rule SwitchBlock = *EmptyLine >>
180 Advance >> Seperator >>
181 SwitchCase >>
182 *(+SpaceBreak >> SwitchCase) >>
183 -(+SpaceBreak >> SwitchElse) >>
184 PopIndent;
185
186rule Switch = key("switch") >>
187 DisableDo >> ensure(Exp, PopDo) >>
188 -key("do") >> -Space >> Break >> SwitchBlock;
189
190rule IfCond = Exp >> -Assign;
191rule IfElseIf = -(Break >> *EmptyLine >> CheckIndent) >> key("elseif") >> IfCond >> -key("then") >> Body;
192rule IfElse = -(Break >> *EmptyLine >> CheckIndent) >> key("else") >> Body;
193rule If = key("if") >> Seperator >> IfCond >> -key("then") >> Body >> *IfElseIf >> -IfElse;
194rule Unless = key("unless") >> Seperator >> IfCond >> -key("then") >> Body >> *IfElseIf >> -IfElse;
195
196rule While = key("while") >> DisableDo >> ensure(Exp, PopDo) >> -key("do") >> Body;
197
198rule for_step_value = sym(',') >> Exp;
199rule for_args = Space >> Variable >> sym('=') >> Exp >> sym(',') >> Exp >> -for_step_value;
200
201rule For = key("for") >> DisableDo >>
202 ensure(for_args, PopDo) >>
203 -key("do") >> Body;
204
205extern rule AssignableNameList;
206
207extern rule star_exp;
208
209rule for_in = star_exp | ExpList;
210
211rule ForEach = key("for") >> AssignableNameList >> key("in") >>
212 DisableDo >> ensure(for_in, PopDo) >>
213 -key("do") >> Body;
214
215rule Do = pl::user(key("do") >> Body, [](const item_t& item)
216{
217 State* st = reinterpret_cast<State*>(item.user_data);
218 return st->doStack.empty() || st->doStack.top();
219});
220
221rule DisableDo = pl::user(true_(), [](const item_t& item)
222{
223 State* st = reinterpret_cast<State*>(item.user_data);
224 st->doStack.push(false);
225 return true;
226});
227
228rule PopDo = pl::user(true_(), [](const item_t& item)
229{
230 State* st = reinterpret_cast<State*>(item.user_data);
231 st->doStack.pop();
232 return true;
233});
234
235extern rule CompInner;
236
237rule Comprehension = sym('[') >> Exp >> CompInner >> sym(']');
238rule comp_value = sym(',') >> Exp;
239rule TblComprehension = sym('{') >> (Exp >> -comp_value) >> CompInner >> sym('}');
240
241extern rule CompForEach, CompFor, CompClause;
242
243rule CompInner = Seperator >> (CompForEach | CompFor) >> *CompClause;
244rule star_exp = sym('*') >> Exp;
245rule CompForEach = key("for") >> AssignableNameList >> key("in") >> (star_exp | Exp);
246rule CompFor = key("for") >> Space >> Variable >> sym('=') >> Exp >> sym(',') >> Exp >> -for_step_value;
247rule CompClause = CompFor | CompForEach | key("when") >> Exp;
248
249extern rule TableBlock;
250
251rule Assign = sym('=') >> Seperator >> (With | If | Switch | TableBlock | Exp >> *((sym(',') | sym(';')) >> Exp));
252
253rule update_op =
254 expr("..") |
255 expr("+") |
256 expr("-") |
257 expr("*") |
258 expr("/") |
259 expr("%") |
260 expr("or") |
261 expr("and") |
262 expr("&") |
263 expr("|") |
264 expr(">>") |
265 expr("<<");
266
267rule Update = Space >> update_op >> expr("=") >> Exp;
268
269rule BinaryOperator =
270 (expr("or") >> not_(AlphaNum)) |
271 (expr("and") >> not_(AlphaNum)) |
272 expr("<=") |
273 expr(">=") |
274 expr("~=") |
275 expr("!=") |
276 expr("==") |
277 expr("..") |
278 expr("<<") |
279 expr(">>") |
280 expr("//") |
281 set("+-*/%^><|&");
282
283extern rule AssignableChain;
284
285rule Assignable = AssignableChain | Space >> Variable | SelfName;
286
287extern rule Value;
288
289rule exp_op_value = Space >> BinaryOperator >> *SpaceBreak >> Value;
290rule Exp = Value >> *exp_op_value;
291
292extern rule Chain, Callable, InvokeArgs;
293
294rule ChainValue = Seperator >> (Chain | Callable) >> -InvokeArgs;
295
296extern rule KeyValue, String, SimpleValue;
297
298rule simple_table = Seperator >> KeyValue >> *(sym(',') >> KeyValue);
299rule Value = SimpleValue | simple_table | ChainValue | String;
300
301extern rule LuaString;
302
303rule single_string_inner = expr("\\'") | "\\\\" | not_(expr('\'')) >> Any;
304rule SingleString = symx('\'') >> *single_string_inner >> sym('\'');
305rule interp = symx("#{") >> Exp >> sym('}');
306rule double_string_plain = expr("\\\"") | "\\\\" | not_(expr('"')) >> Any;
307rule double_string_inner = +(not_(interp) >> double_string_plain);
308rule double_string_content = double_string_inner | interp;
309rule DoubleString = symx('"') >> Seperator >> *double_string_content >> sym('"');
310rule String = Space >> (DoubleString | SingleString | LuaString);
311
312rule lua_string_open = '[' >> *expr('=') >> '[';
313rule lua_string_close = ']' >> *expr('=') >> ']';
314
315rule LuaStringOpen = pl::user(lua_string_open, [](const item_t& item)
316{
317 size_t count = std::distance(item.begin, item.end);
318 State* st = reinterpret_cast<State*>(item.user_data);
319 st->stringOpen = count;
320 return true;
321});
322
323rule LuaStringClose = pl::user(lua_string_close, [](const item_t& item)
324{
325 size_t count = std::distance(item.begin, item.end);
326 State* st = reinterpret_cast<State*>(item.user_data);
327 return st->stringOpen == count;
328});
329
330rule LuaStringContent = *(not_(LuaStringClose) >> (Break | Any));
331
332rule LuaString = pl::user(LuaStringOpen >> -Break >> LuaStringContent >> LuaStringClose, [](const item_t& item)
333{
334 State* st = reinterpret_cast<State*>(item.user_data);
335 st->stringOpen = -1;
336 return true;
337});
338
339rule Parens = sym('(') >> *SpaceBreak >> Exp >> *SpaceBreak >> sym(')');
340rule Callable = Space >> Variable | SelfName | VarArg | Parens;
341rule FnArgsExpList = Exp >> *((Break | sym(',')) >> White >> Exp);
342
343rule FnArgs = (symx('(') >> *SpaceBreak >> -FnArgsExpList >> *SpaceBreak >> sym(')')) |
344 (sym('!') >> not_(expr('=')));
345
346extern rule ChainItems, DotChainItem, ColonChain;
347
348rule chain_call = (Callable | String) >> ChainItems;
349rule chain_item = and_(set(".\\")) >> ChainItems;
350rule chain_dot_chain = DotChainItem >> -ChainItems;
351
352rule Chain = chain_call | chain_item |
353 Space >> (chain_dot_chain | ColonChain);
354
355rule AssignableChain = Seperator >> Chain;
356
357extern rule ChainItem;
358
359rule chain_with_colon = +ChainItem >> -ColonChain;
360rule ChainItems = chain_with_colon | ColonChain;
361
362extern rule Invoke, Slice;
363
364rule Index = symx('[') >> Exp >> sym(']');
365rule ChainItem = Invoke | DotChainItem | Slice | Index;
366rule DotChainItem = symx('.') >> Name;
367rule ColonChainItem = symx('\\') >> (LuaKeyword | Name);
368rule invoke_chain = Invoke >> -ChainItems;
369rule ColonChain = ColonChainItem >> -invoke_chain;
370
371rule default_value = true_();
372rule Slice =
373 symx('[') >>
374 (Exp | default_value) >>
375 sym(',') >>
376 (Exp | default_value) >>
377 (sym(',') >> Exp | default_value) >>
378 sym(']');
379
380rule Invoke = Seperator >> (
381 FnArgs |
382 SingleString |
383 DoubleString |
384 and_(expr('[')) >> LuaString);
385
386extern rule TableValueList, TableLitLine;
387
388rule TableValue = KeyValue | Exp;
389
390rule table_lit_lines = SpaceBreak >> TableLitLine >> *(-sym(',') >> SpaceBreak >> TableLitLine) >> -sym(',');
391
392rule TableLit =
393 sym('{') >> Seperator >>
394 -TableValueList >>
395 -sym(',') >>
396 -table_lit_lines >>
397 White >> sym('}');
398
399rule TableValueList = TableValue >> *(sym(',') >> TableValue);
400
401rule TableLitLine =
402(
403 PushIndent >> (TableValueList >> PopIndent | PopIndent)
404) | (
405 Space
406);
407
408extern rule KeyValueLine;
409
410rule TableBlockInner = Seperator >> KeyValueLine >> *(+(SpaceBreak) >> KeyValueLine);
411rule TableBlock = +(SpaceBreak) >> Advance >> ensure(TableBlockInner, PopIndent);
412
413extern rule Statement;
414
415rule class_member_list = Seperator >> KeyValue >> *(sym(',') >> KeyValue);
416rule ClassLine = CheckIndent >> (class_member_list | Statement) >> -sym(',');
417rule ClassBlock = +(SpaceBreak) >> Advance >>Seperator >> ClassLine >> *(+(SpaceBreak) >> ClassLine) >> PopIndent;
418
419rule ClassDecl =
420 key("class") >> not_(expr(':')) >>
421 -Assignable >>
422 -(key("extends") >> PreventIndent >> ensure(Exp, PopIndent)) >>
423 -ClassBlock;
424
425rule export_values = NameList >> -(sym('=') >> ExpListLow);
426rule export_op = expr('*') | expr('^');
427rule Export = key("export") >> (ClassDecl | (Space >> export_op) | export_values);
428
429rule variable_pair = sym(':') >> not_(SomeSpace) >> Space >> Variable;
430
431rule normal_pair =
432(
433 KeyName |
434 sym('[') >> Exp >> sym(']') |
435 Space >> DoubleString |
436 Space >> SingleString
437) >>
438symx(':') >>
439(Exp | TableBlock | +(SpaceBreak) >> Exp);
440
441rule KeyValue = variable_pair | normal_pair;
442
443rule KeyValueList = KeyValue >> *(sym(',') >> KeyValue);
444rule KeyValueLine = CheckIndent >> KeyValueList >> -sym(',');
445
446rule FnArgDef = (Space >> Variable | SelfName) >> -(sym('=') >> Exp);
447
448rule FnArgDefList = Seperator >>
449(
450 (
451 FnArgDef >>
452 *((sym(',') | Break) >> White >> FnArgDef) >>
453 -((sym(',') | Break) >> White >> VarArg)
454 ) | (
455 VarArg
456 )
457);
458
459rule outer_var_shadow = key("using") >> (NameList | Space >> expr("nil"));
460
461rule FnArgsDef = sym('(') >> White >> -FnArgDefList >> -outer_var_shadow >> White >> sym(')');
462rule fn_arrow = expr("->") | expr("=>");
463rule FunLit = -FnArgsDef >> Space >> fn_arrow >> -Body;
464
465rule NameList = Seperator >> Space >> Variable >> *(sym(',') >> Space >> Variable);
466rule NameOrDestructure = Space >> Variable | TableLit;
467rule AssignableNameList = Seperator >> NameOrDestructure >> *(sym(',') >> NameOrDestructure);
468
469rule ExpList = Seperator >> Exp >> *(sym(',') >> Exp);
470rule ExpListLow = Seperator >> Exp >> *((sym(',') | sym(';')) >> Exp);
471
472rule ArgLine = CheckIndent >> Exp >> *(sym(',') >> Exp);
473rule ArgBlock = ArgLine >> *(sym(',') >> SpaceBreak >> ArgLine) >> PopIndent;
474
475rule invoke_args_with_table =
476 sym(',') >>
477 (
478 TableBlock |
479 SpaceBreak >> Advance >> ArgBlock >> -TableBlock
480 );
481
482rule InvokeArgs =
483 not_(expr('-')) >> Seperator >>
484 (
485 Exp >> *(sym(',') >> Exp) >> -(invoke_args_with_table | TableBlock) |
486 TableBlock
487 );
488
489rule const_value = (expr("nil") | expr("true") | expr("false")) >> not_(AlphaNum);
490rule minus_exp = expr('-') >> not_(SomeSpace) >> Exp;
491rule sharp_exp = expr('#') >> Exp;
492rule tilde_exp = expr('~') >> Exp;
493rule not_exp = expr("not") >> not_(AlphaNum) >> Exp;
494rule unary_exp = minus_exp | sharp_exp | tilde_exp | not_exp;
495
496rule SimpleValue =
497 (Space >> const_value) |
498 If | Unless | Switch | With | ClassDecl | ForEach | For | While | Do |
499 (Space >> unary_exp) |
500 TblComprehension | TableLit | Comprehension | FunLit |
501 (Space >> Num);
502
503rule ExpListAssign = ExpList >> -(Update | Assign);
504
505rule if_else_line = key("if") >> Exp >> (key("else") >> Exp | default_value);
506rule unless_line = key("unless") >> Exp;
507
508rule statement_appendix = (if_else_line | unless_line | CompInner) >> Space;
509rule Statement =
510(
511 Import | While | For | ForEach |
512 Return | Local | Export | Space >> BreakLoop |
513 ExpListAssign
514) >> Space >>
515-statement_appendix;
516
517rule Body = -Space >> Break >> *EmptyLine >> InBlock | Statement;
518
519rule empty_line_stop = Space >> and_(Stop);
520rule Line = CheckIndent >> Statement | empty_line_stop;
521rule Block = Seperator >> Line >> *(+Break >> Line);
522
523rule Shebang = expr("#!") >> *(not_(Stop) >> Any);
524rule File = White >> -Shebang >> Block >> eof();
525
526} // namespace MoonP
diff --git a/src/MoonP/moon_parser.h b/src/MoonP/moon_parser.h
new file mode 100644
index 0000000..fc4ee55
--- /dev/null
+++ b/src/MoonP/moon_parser.h
@@ -0,0 +1,35 @@
1/* Copyright (c) 2020 Jin Li, http://www.luvfight.me
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
5The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
7THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
8
9#pragma once
10
11#include <string>
12#include <codecvt>
13#include <unordered_set>
14#include <stack>
15#include <algorithm>
16#include <vector>
17#include "MoonP/ast.hpp"
18using namespace parserlib;
19
20namespace MoonP {
21
22struct State {
23 State() {
24 indents.push(0);
25 stringOpen = -1;
26 }
27 std::string buffer;
28 size_t stringOpen;
29 std::stack<int> indents;
30 std::stack<bool> doStack;
31 static std::unordered_set<std::string> luaKeywords;
32 static std::unordered_set<std::string> keywords;
33};
34
35} // namespace MoonP
diff --git a/src/MoonP/parser.cpp b/src/MoonP/parser.cpp
new file mode 100644
index 0000000..19c0068
--- /dev/null
+++ b/src/MoonP/parser.cpp
@@ -0,0 +1,1439 @@
1/* Copyright (c) 2012, Achilleas Margaritis, modified by Jin Li
2All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
6 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
9THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
10
11#include <cstdlib>
12#include <cstring>
13#include <cassert>
14#include <stdexcept>
15#include <unordered_map>
16#include <unordered_set>
17
18#include "MoonP/parser.hpp"
19
20
21namespace parserlib {
22
23
24//internal map from rules to parse procs
25typedef std::unordered_map<rule *, parse_proc> _parse_proc_map_t;
26
27//on exit, it deletes the parse proc map
28static _parse_proc_map_t& _get_parse_proc_map() {
29 static _parse_proc_map_t _parse_proc_map;
30 return _parse_proc_map;
31}
32
33
34//get the parse proc from the map
35static parse_proc _get_parse_proc(rule *r) {
36 _parse_proc_map_t& _parse_proc_map = _get_parse_proc_map();
37 _parse_proc_map_t::iterator it = _parse_proc_map.find(r);
38 if (it == _parse_proc_map.end()) return 0;
39 return it->second;
40}
41
42
43//internal private class that manages access to the public classes' internals.
44class _private {
45public:
46 //get the internal expression object from the expression.
47 static _expr *get_expr(const expr &e) {
48 return e.m_expr;
49 }
50
51 //create new expression from given expression
52 static expr construct_expr(_expr *e) {
53 return e;
54 }
55
56 //get the internal expression object from the rule.
57 static _expr *get_expr(rule &r) {
58 return r.m_expr;
59 }
60
61 //get the internal parse proc from the rule.
62 static parse_proc get_parse_proc(rule &r) {
63 return r.m_parse_proc;
64 }
65};
66
67
68class _context;
69
70
71//parser state
72class _state {
73public:
74 //position
75 pos m_pos;
76
77 //size of match vector
78 size_t m_matches;
79
80 //constructor
81 _state(_context &con);
82};
83
84
85//match
86class _match {
87public:
88 //rule matched
89 rule *m_rule;
90
91 //begin position
92 pos m_begin;
93
94 //end position
95 pos m_end;
96
97 //null constructor
98 _match() {}
99
100 //constructor from parameters
101 _match(rule *r, const pos &b, const pos &e) :
102 m_rule(r),
103 m_begin(b),
104 m_end(e)
105 {
106 }
107};
108
109
110//match vector
111typedef std::vector<_match> _match_vector;
112
113
114//parsing context
115class _context {
116public:
117 //user data
118 void* m_user_data;
119
120 //current position
121 pos m_pos;
122
123 //error position
124 pos m_error_pos;
125
126 //input begin
127 input::iterator m_begin;
128
129 //input end
130 input::iterator m_end;
131
132 //matches
133 _match_vector m_matches;
134
135 //constructor
136 _context(input &i, void* ud) :
137 m_user_data(ud),
138 m_pos(i),
139 m_error_pos(i),
140 m_begin(i.begin()),
141 m_end(i.end())
142 {
143 }
144
145 //check if the end is reached
146 bool end() const {
147 return m_pos.m_it == m_end;
148 }
149
150 //get the current symbol
151 input::value_type symbol() const {
152 assert(!end());
153 return *m_pos.m_it;
154 }
155
156 //set the longest possible error
157 void set_error_pos() {
158 if (m_pos.m_it > m_error_pos.m_it) {
159 m_error_pos = m_pos;
160 }
161 }
162
163 //next column
164 void next_col() {
165 ++m_pos.m_it;
166 ++m_pos.m_col;
167 }
168
169 //next line
170 void next_line() {
171 ++m_pos.m_line;
172 m_pos.m_col = 1;
173 }
174
175 //restore the state
176 void restore(const _state &st) {
177 m_pos = st.m_pos;
178 m_matches.resize(st.m_matches);
179 }
180
181 //parse non-term rule.
182 bool parse_non_term(rule &r);
183
184 //parse term rule.
185 bool parse_term(rule &r);
186
187 //execute all the parse procs
188 void do_parse_procs(void *d) const {
189 for(_match_vector::const_iterator it = m_matches.begin();
190 it != m_matches.end();
191 ++it)
192 {
193 const _match &m = *it;
194 parse_proc p = _private::get_parse_proc(*m.m_rule);
195 p(m.m_begin, m.m_end, d);
196 }
197 }
198
199private:
200 //parse non-term rule.
201 bool _parse_non_term(rule &r);
202
203 //parse term rule.
204 bool _parse_term(rule &r);
205};
206
207
208//base class for expressions
209class _expr {
210public:
211 //destructor.
212 virtual ~_expr() {
213 }
214
215 //parse with whitespace
216 virtual bool parse_non_term(_context &con) const = 0;
217
218 //parse terminal
219 virtual bool parse_term(_context &con) const = 0;
220};
221
222
223//single character expression.
224class _char : public _expr {
225public:
226 //constructor.
227 _char(char c) :
228 m_char(c)
229 {
230 }
231
232 //parse with whitespace
233 virtual bool parse_non_term(_context &con) const {
234 return _parse(con);
235 }
236
237 //parse terminal
238 virtual bool parse_term(_context &con) const {
239 return _parse(con);
240 }
241
242private:
243 //character
244 input::value_type m_char;
245
246 //internal parse
247 bool _parse(_context &con) const {
248 if (!con.end()) {
249 input::value_type ch = con.symbol();
250 if (ch == m_char) {
251 con.next_col();
252 return true;
253 }
254 }
255 con.set_error_pos();
256 return false;
257 }
258};
259
260
261//string expression.
262class _string : public _expr {
263public:
264 //constructor from ansi string.
265 _string(const char *s) :
266 m_string(Converter{}.from_bytes(s))
267 {
268 }
269
270 //parse with whitespace
271 virtual bool parse_non_term(_context &con) const {
272 return _parse(con);
273 }
274
275 //parse terminal
276 virtual bool parse_term(_context &con) const {
277 return _parse(con);
278 }
279
280private:
281 //string
282 input m_string;
283
284 //parse the string
285 bool _parse(_context &con) const {
286 for(input::const_iterator it = m_string.begin(),
287 end = m_string.end();;)
288 {
289 if (it == end) return true;
290 if (con.end()) break;
291 if (con.symbol() != *it) break;
292 ++it;
293 con.next_col();
294 }
295 con.set_error_pos();
296 return false;
297 }
298};
299
300
301//set expression.
302class _set : public _expr {
303public:
304 //constructor from ansi string.
305 _set(const char *s) {
306 auto str = Converter{}.from_bytes(s);
307 for (auto ch : str) {
308 _add(ch);
309 }
310 }
311
312 //constructor from range.
313 _set(int min, int max) {
314 assert(min >= 0);
315 assert(min <= max);
316 m_quick_set.resize((size_t)max + 1U);
317 for(; min <= max; ++min) {
318 m_quick_set[(size_t)min] = true;
319 }
320 }
321
322 //parse with whitespace
323 virtual bool parse_non_term(_context &con) const {
324 return _parse(con);
325 }
326
327 //parse terminal
328 virtual bool parse_term(_context &con) const {
329 return _parse(con);
330 }
331
332private:
333 //set is kept as an array of flags, for quick access
334 std::vector<bool> m_quick_set;
335 std::unordered_set<size_t> m_large_set;
336
337 //add character
338 void _add(size_t i) {
339 if (i <= m_quick_set.size() || i <= 255) {
340 if (i >= m_quick_set.size()) {
341 m_quick_set.resize(i + 1);
342 }
343 m_quick_set[i] = true;
344 } else {
345 m_large_set.insert(i);
346 }
347 }
348
349 //internal parse
350 bool _parse(_context &con) const {
351 if (!con.end()) {
352 size_t ch = con.symbol();
353 if (ch < m_quick_set.size()) {
354 if (m_quick_set[ch]) {
355 con.next_col();
356 return true;
357 }
358 } else if (m_large_set.find(ch) != m_large_set.end()) {
359 con.next_col();
360 return true;
361 }
362 }
363 con.set_error_pos();
364 return false;
365 }
366};
367
368
369//base class for unary expressions
370class _unary : public _expr {
371public:
372 //constructor.
373 _unary(_expr *e) :
374 m_expr(e)
375 {
376 }
377
378 //destructor.
379 virtual ~_unary() {
380 delete m_expr;
381 }
382
383protected:
384 //expression
385 _expr *m_expr;
386};
387
388
389//terminal
390class _term : public _unary {
391public:
392 //constructor.
393 _term(_expr *e) :
394 _unary(e)
395 {
396 }
397
398 //parse with whitespace
399 virtual bool parse_non_term(_context &con) const {
400 return m_expr->parse_term(con);
401 }
402
403 //parse terminal
404 virtual bool parse_term(_context &con) const {
405 return m_expr->parse_term(con);
406 }
407};
408
409
410//user
411class _user : public _unary {
412public:
413 //constructor.
414 _user(_expr *e, const user_handler &callback) :
415 _unary(e),
416 m_handler(callback)
417 {
418 }
419
420 //parse with whitespace
421 virtual bool parse_non_term(_context &con) const {
422 pos pos = con.m_pos;
423 if (m_expr->parse_non_term(con)) {
424 item_t item = {pos.m_it, con.m_pos.m_it, con.m_user_data};
425 return m_handler(item);
426 }
427 return false;
428 }
429
430 //parse terminal
431 virtual bool parse_term(_context &con) const {
432 pos pos = con.m_pos;
433 if (m_expr->parse_term(con)) {
434 item_t item = {pos.m_it, con.m_pos.m_it, con.m_user_data};
435 return m_handler(item);
436 }
437 return false;
438 }
439private:
440 user_handler m_handler;
441};
442
443
444//loop 0
445class _loop0 : public _unary {
446public:
447 //constructor.
448 _loop0(_expr *e) :
449 _unary(e)
450 {
451 }
452
453 //parse with whitespace
454 virtual bool parse_non_term(_context &con) const {
455 //if parsing of the first fails, restore the context and stop
456 _state st(con);
457 if (!m_expr->parse_non_term(con)) {
458 con.restore(st);
459 return true;
460 }
461
462 //parse the rest
463 for(;;) {
464 _state st(con);
465 if (!m_expr->parse_non_term(con)) {
466 con.restore(st);
467 break;
468 }
469 }
470
471 return true;
472 }
473
474 //parse terminal
475 virtual bool parse_term(_context &con) const {
476 //if parsing of the first fails, restore the context and stop
477 _state st(con);
478 if (!m_expr->parse_term(con)) {
479 con.restore(st);
480 return true;
481 }
482
483 //parse the rest until no more parsing is possible
484 for(;;) {
485 _state st(con);
486 if (!m_expr->parse_term(con)) {
487 con.restore(st);
488 break;
489 }
490 }
491
492 return true;
493 }
494};
495
496
497//loop 1
498class _loop1 : public _unary {
499public:
500 //constructor.
501 _loop1(_expr *e) :
502 _unary(e)
503 {
504 }
505
506 //parse with whitespace
507 virtual bool parse_non_term(_context &con) const {
508 //parse the first; if the first fails, stop
509 if (!m_expr->parse_non_term(con)) return false;
510
511 //parse the rest until no more parsing is possible
512 for(;;) {
513 _state st(con);
514 if (!m_expr->parse_non_term(con)) {
515 con.restore(st);
516 break;
517 }
518 }
519
520 return true;
521 }
522
523 //parse terminal
524 virtual bool parse_term(_context &con) const {
525 //parse the first; if the first fails, stop
526 if (!m_expr->parse_term(con)) return false;
527
528 //parse the rest until no more parsing is possible
529 for(;;) {
530 _state st(con);
531 if (!m_expr->parse_term(con)) {
532 con.restore(st);
533 break;
534 }
535 }
536
537 return true;
538 }
539};
540
541
542//optional
543class _optional : public _unary {
544public:
545 //constructor.
546 _optional(_expr *e) :
547 _unary(e)
548 {
549 }
550
551 //parse with whitespace
552 virtual bool parse_non_term(_context &con) const {
553 _state st(con);
554 if (!m_expr->parse_non_term(con)) con.restore(st);
555 return true;
556 }
557
558 //parse terminal
559 virtual bool parse_term(_context &con) const {
560 _state st(con);
561 if (!m_expr->parse_term(con)) con.restore(st);
562 return true;
563 }
564};
565
566
567//and
568class _and : public _unary {
569public:
570 //constructor.
571 _and(_expr *e) :
572 _unary(e)
573 {
574 }
575
576 //parse with whitespace
577 virtual bool parse_non_term(_context &con) const {
578 _state st(con);
579 bool ok = m_expr->parse_non_term(con);
580 con.restore(st);
581 return ok;
582 }
583
584 //parse terminal
585 virtual bool parse_term(_context &con) const {
586 _state st(con);
587 bool ok = m_expr->parse_term(con);
588 con.restore(st);
589 return ok;
590 }
591};
592
593
594//not
595class _not : public _unary {
596public:
597 //constructor.
598 _not(_expr *e) :
599 _unary(e)
600 {
601 }
602
603 //parse with whitespace
604 virtual bool parse_non_term(_context &con) const {
605 _state st(con);
606 bool ok = !m_expr->parse_non_term(con);
607 con.restore(st);
608 return ok;
609 }
610
611 //parse terminal
612 virtual bool parse_term(_context &con) const {
613 _state st(con);
614 bool ok = !m_expr->parse_term(con);
615 con.restore(st);
616 return ok;
617 }
618};
619
620
621//newline
622class _nl : public _unary {
623public:
624 //constructor.
625 _nl(_expr *e) :
626 _unary(e)
627 {
628 }
629
630 //parse with whitespace
631 virtual bool parse_non_term(_context &con) const {
632 if (!m_expr->parse_non_term(con)) return false;
633 con.next_line();
634 return true;
635 }
636
637 //parse terminal
638 virtual bool parse_term(_context &con) const {
639 if (!m_expr->parse_term(con)) return false;
640 con.next_line();
641 return true;
642 }
643};
644
645
646//base class for binary expressions
647class _binary : public _expr {
648public:
649 //constructor.
650 _binary(_expr *left, _expr *right) :
651 m_left(left), m_right(right)
652 {
653 }
654
655 //destructor.
656 virtual ~_binary() {
657 delete m_left;
658 delete m_right;
659 }
660
661protected:
662 //left and right expressions
663 _expr *m_left, *m_right;
664};
665
666
667//sequence
668class _seq : public _binary {
669public:
670 //constructor.
671 _seq(_expr *left, _expr *right) :
672 _binary(left, right)
673 {
674 }
675
676 //parse with whitespace
677 virtual bool parse_non_term(_context &con) const {
678 if (!m_left->parse_non_term(con)) return false;
679 return m_right->parse_non_term(con);
680 }
681
682 //parse terminal
683 virtual bool parse_term(_context &con) const {
684 if (!m_left->parse_term(con)) return false;
685 return m_right->parse_term(con);
686 }
687};
688
689
690//choice
691class _choice : public _binary {
692public:
693 //constructor.
694 _choice(_expr *left, _expr *right) :
695 _binary(left, right)
696 {
697 }
698
699 //parse with whitespace
700 virtual bool parse_non_term(_context &con) const {
701 _state st(con);
702 if (m_left->parse_non_term(con)) return true;
703 con.restore(st);
704 return m_right->parse_non_term(con);
705 }
706
707 //parse terminal
708 virtual bool parse_term(_context &con) const {
709 _state st(con);
710 if (m_left->parse_term(con)) return true;
711 con.restore(st);
712 return m_right->parse_term(con);
713 }
714};
715
716
717//reference to rule
718class _ref : public _expr {
719public:
720 //constructor.
721 _ref(rule &r) :
722 m_rule(r)
723 {
724 }
725
726 //parse with whitespace
727 virtual bool parse_non_term(_context &con) const {
728 return con.parse_non_term(m_rule);
729 }
730
731 //parse terminal
732 virtual bool parse_term(_context &con) const {
733 return con.parse_term(m_rule);
734 }
735
736private:
737 //reference
738 rule &m_rule;
739};
740
741
742//eof
743class _eof : public _expr {
744public:
745 //parse with whitespace
746 virtual bool parse_non_term(_context &con) const {
747 return parse_term(con);
748 }
749
750 //parse terminal
751 virtual bool parse_term(_context &con) const {
752 return con.end();
753 }
754};
755
756
757//any
758class _any : public _expr {
759public:
760 //parse with whitespace
761 virtual bool parse_non_term(_context &con) const {
762 return parse_term(con);
763 }
764
765 //parse terminal
766 virtual bool parse_term(_context &con) const {
767 if (!con.end()) {
768 con.next_col();
769 return true;
770 }
771 con.set_error_pos();
772 return false;
773 }
774};
775
776
777//true
778class _true : public _expr {
779public:
780 //parse with whitespace
781 virtual bool parse_non_term(_context &) const {
782 return true;
783 }
784
785 //parse terminal
786 virtual bool parse_term(_context &) const {
787 return true;
788 }
789};
790
791
792//false
793class _false: public _expr {
794public:
795 //parse with whitespace
796 virtual bool parse_non_term(_context &) const {
797 return false;
798 }
799
800 //parse terminal
801 virtual bool parse_term(_context &) const {
802 return false;
803 }
804};
805
806//exception thrown when left recursion terminates successfully
807struct _lr_ok {
808 rule *m_rule;
809 _lr_ok(rule *r) : m_rule(r) {}
810};
811
812
813//constructor
814_state::_state(_context &con) :
815 m_pos(con.m_pos),
816 m_matches(con.m_matches.size())
817{
818}
819
820
821//parse non-term rule.
822bool _context::parse_non_term(rule &r) {
823 //save the state of the rule
824 rule::_state old_state = r.m_state;
825
826 //success/failure result
827 bool ok;
828
829 //compute the new position
830 size_t new_pos = m_pos.m_it - m_begin;
831
832 //check if we have left recursion
833 bool lr = new_pos == r.m_state.m_pos;
834
835 //update the rule's state
836 r.m_state.m_pos = new_pos;
837
838 //handle the mode of the rule
839 switch (r.m_state.m_mode) {
840 //normal parse
841 case rule::_PARSE:
842 if (lr) {
843 //first try to parse the rule by rejecting it, so alternative branches are examined
844 r.m_state.m_mode = rule::_REJECT;
845 ok = _parse_non_term(r);
846
847 //if the first try is successful, try accepting the rule,
848 //so other elements of the sequence are parsed
849 if (ok) {
850 r.m_state.m_mode = rule::_ACCEPT;
851
852 //loop until no more parsing can be done
853 for(;;) {
854 //store the correct state, in order to backtrack if the call fails
855 _state st(*this);
856
857 //update the rule position to the current position,
858 //because at this state the rule is resolving the left recursion
859 r.m_state.m_pos = m_pos.m_it - m_begin;
860
861 //if parsing fails, restore the last good state and stop
862 if (!_parse_non_term(r)) {
863 restore(st);
864 break;
865 }
866 }
867
868 //since the left recursion was resolved successfully,
869 //return via a non-local exit
870 r.m_state = old_state;
871 throw _lr_ok(r.this_ptr());
872 }
873 }
874 else {
875 try {
876 ok = _parse_non_term(r);
877 }
878 catch (const _lr_ok &ex) {
879 //since left recursions may be mutual, we must test which rule's left recursion
880 //was ended successfully
881 if (ex.m_rule == r.this_ptr()) {
882 ok = true;
883 }
884 else {
885 r.m_state = old_state;
886 throw;
887 }
888 }
889 }
890 break;
891
892 //reject the left recursive rule
893 case rule::_REJECT:
894 if (lr) {
895 ok = false;
896 }
897 else {
898 r.m_state.m_mode = rule::_PARSE;
899 ok = _parse_non_term(r);
900 r.m_state.m_mode = rule::_REJECT;
901 }
902 break;
903
904 //accept the left recursive rule
905 case rule::_ACCEPT:
906 if (lr) {
907 ok = true;
908 }
909 else {
910 r.m_state.m_mode = rule::_PARSE;
911 ok = _parse_non_term(r);
912 r.m_state.m_mode = rule::_ACCEPT;
913 }
914 break;
915 }
916
917 //restore the rule's state
918 r.m_state = old_state;
919
920 return ok;
921}
922
923
924//parse term rule.
925bool _context::parse_term(rule &r) {
926 //save the state of the rule
927 rule::_state old_state = r.m_state;
928
929 //success/failure result
930 bool ok;
931
932 //compute the new position
933 size_t new_pos = m_pos.m_it - m_begin;
934
935 //check if we have left recursion
936 bool lr = new_pos == r.m_state.m_pos;
937
938 //update the rule's state
939 r.m_state.m_pos = new_pos;
940
941 //handle the mode of the rule
942 switch (r.m_state.m_mode) {
943 //normal parse
944 case rule::_PARSE:
945 if (lr) {
946 //first try to parse the rule by rejecting it, so alternative branches are examined
947 r.m_state.m_mode = rule::_REJECT;
948 ok = _parse_term(r);
949
950 //if the first try is successful, try accepting the rule,
951 //so other elements of the sequence are parsed
952 if (ok) {
953 r.m_state.m_mode = rule::_ACCEPT;
954
955 //loop until no more parsing can be done
956 for(;;) {
957 //store the correct state, in order to backtrack if the call fails
958 _state st(*this);
959
960 //update the rule position to the current position,
961 //because at this state the rule is resolving the left recursion
962 r.m_state.m_pos = m_pos.m_it - m_begin;
963
964 //if parsing fails, restore the last good state and stop
965 if (!_parse_term(r)) {
966 restore(st);
967 break;
968 }
969 }
970
971 //since the left recursion was resolved successfully,
972 //return via a non-local exit
973 r.m_state = old_state;
974 throw _lr_ok(r.this_ptr());
975 }
976 }
977 else {
978 try {
979 ok = _parse_term(r);
980 }
981 catch (const _lr_ok &ex) {
982 //since left recursions may be mutual, we must test which rule's left recursion
983 //was ended successfully
984 if (ex.m_rule == r.this_ptr()) {
985 ok = true;
986 }
987 else {
988 r.m_state = old_state;
989 throw;
990 }
991 }
992 }
993 break;
994
995 //reject the left recursive rule
996 case rule::_REJECT:
997 if (lr) {
998 ok = false;
999 }
1000 else {
1001 r.m_state.m_mode = rule::_PARSE;
1002 ok = _parse_term(r);
1003 r.m_state.m_mode = rule::_REJECT;
1004 }
1005 break;
1006
1007 //accept the left recursive rule
1008 case rule::_ACCEPT:
1009 if (lr) {
1010 ok = true;
1011 }
1012 else {
1013 r.m_state.m_mode = rule::_PARSE;
1014 ok = _parse_term(r);
1015 r.m_state.m_mode = rule::_ACCEPT;
1016 }
1017 break;
1018 }
1019
1020 //restore the rule's state
1021 r.m_state = old_state;
1022
1023 return ok;
1024}
1025
1026
1027//parse non-term rule internal.
1028bool _context::_parse_non_term(rule &r) {
1029 bool ok;
1030 if (_private::get_parse_proc(r)) {
1031 pos b = m_pos;
1032 ok = _private::get_expr(r)->parse_non_term(*this);
1033 if (ok) {
1034 m_matches.push_back(_match(r.this_ptr(), b, m_pos));
1035 }
1036 }
1037 else {
1038 ok = _private::get_expr(r)->parse_non_term(*this);
1039 }
1040 return ok;
1041}
1042
1043
1044//parse term rule internal.
1045bool _context::_parse_term(rule &r) {
1046 bool ok;
1047 if (_private::get_parse_proc(r)) {
1048 pos b = m_pos;
1049 ok = _private::get_expr(r)->parse_term(*this);
1050 if (ok) {
1051 m_matches.push_back(_match(r.this_ptr(), b, m_pos));
1052 }
1053 }
1054 else {
1055 ok = _private::get_expr(r)->parse_term(*this);
1056 }
1057 return ok;
1058}
1059
1060
1061//get syntax error
1062static error _syntax_error(_context &con) {
1063 return error(con.m_error_pos, con.m_error_pos, ERROR_SYNTAX_ERROR);
1064}
1065
1066
1067//get eof error
1068static error _eof_error(_context &con) {
1069 return error(con.m_error_pos, con.m_error_pos, ERROR_INVALID_EOF);
1070}
1071
1072
1073/** constructor from input.
1074 @param i input.
1075 */
1076pos::pos(input &i) :
1077 m_it(i.begin()),
1078 m_line(1),
1079 m_col(1)
1080{
1081}
1082
1083
1084/** character terminal constructor.
1085 @param c character.
1086 */
1087expr::expr(char c) :
1088 m_expr(new _char(c))
1089{
1090}
1091
1092
1093/** null-terminated string terminal constructor.
1094 @param s null-terminated string.
1095 */
1096expr::expr(const char *s) :
1097 m_expr(new _string(s))
1098{
1099}
1100
1101
1102/** rule reference constructor.
1103 @param r rule.
1104 */
1105expr::expr(rule &r) :
1106 m_expr(new _ref(r))
1107{
1108}
1109
1110
1111/** creates a zero-or-more loop out of this expression.
1112 @return a zero-or-more loop expression.
1113 */
1114expr expr::operator *() const {
1115 return _private::construct_expr(new _loop0(m_expr));
1116}
1117
1118
1119/** creates a one-or-more loop out of this expression.
1120 @return a one-or-more loop expression.
1121 */
1122expr expr::operator +() const {
1123 return _private::construct_expr(new _loop1(m_expr));
1124}
1125
1126
1127/** creates an optional out of this expression.
1128 @return an optional expression.
1129 */
1130expr expr::operator -() const {
1131 return _private::construct_expr(new _optional(m_expr));
1132}
1133
1134
1135/** creates an AND-expression.
1136 @return an AND-expression.
1137 */
1138expr expr::operator &() const {
1139 return _private::construct_expr((new _and(m_expr)));
1140}
1141
1142
1143/** creates a NOT-expression.
1144 @return a NOT-expression.
1145 */
1146expr expr::operator !() const {
1147 return _private::construct_expr(new _not(m_expr));
1148}
1149
1150
1151/** constructor.
1152 @param b begin position.
1153 @param e end position.
1154 */
1155input_range::input_range(const pos &b, const pos &e) :
1156m_begin(b),
1157m_end(e) {}
1158
1159
1160/** constructor.
1161 @param b begin position.
1162 @param e end position.
1163 @param t error type.
1164 */
1165error::error(const pos &b, const pos &e, int t) :
1166input_range(b, e),
1167m_type(t) {}
1168
1169
1170/** compare on begin position.
1171 @param e the other error to compare this with.
1172 @return true if this comes before the previous error, false otherwise.
1173 */
1174bool error::operator < (const error &e) const {
1175 return m_begin.m_it < e.m_begin.m_it;
1176}
1177
1178
1179/** character terminal constructor.
1180 @param c character.
1181 */
1182rule::rule(char c) :
1183 m_expr(new _char(c))
1184{
1185 m_parse_proc = _get_parse_proc(this);
1186}
1187
1188
1189/** null-terminated string terminal constructor.
1190 @param s null-terminated string.
1191 */
1192rule::rule(const char *s) :
1193 m_expr(new _string(s))
1194{
1195 m_parse_proc = _get_parse_proc(this);
1196}
1197
1198
1199/** constructor from expression.
1200 @param e expression.
1201 */
1202rule::rule(const expr &e) :
1203 m_expr(_private::get_expr(e))
1204{
1205 m_parse_proc = _get_parse_proc(this);
1206}
1207
1208
1209/** constructor from rule.
1210 @param r rule.
1211 */
1212rule::rule(rule &r) :
1213 m_expr(new _ref(r)),
1214 m_parse_proc(0)
1215{
1216 m_parse_proc = _get_parse_proc(this);
1217}
1218
1219
1220/** invalid constructor from rule (required by gcc).
1221 @exception std::logic_error always thrown.
1222 */
1223rule::rule(const rule &) {
1224 throw std::logic_error("invalid operation");
1225}
1226
1227
1228/** deletes the internal object that represents the expression.
1229 */
1230rule::~rule() {
1231 delete m_expr;
1232}
1233
1234
1235/** creates a zero-or-more loop out of this rule.
1236 @return a zero-or-more loop rule.
1237 */
1238expr rule::operator *() {
1239 return _private::construct_expr(new _loop0(new _ref(*this)));
1240}
1241
1242
1243/** creates a one-or-more loop out of this rule.
1244 @return a one-or-more loop rule.
1245 */
1246expr rule::operator +() {
1247 return _private::construct_expr(new _loop1(new _ref(*this)));
1248}
1249
1250
1251/** creates an optional out of this rule.
1252 @return an optional rule.
1253 */
1254expr rule::operator -() {
1255 return _private::construct_expr(new _optional(new _ref(*this)));
1256}
1257
1258
1259/** creates an AND-expression out of this rule.
1260 @return an AND-expression out of this rule.
1261 */
1262expr rule::operator &() {
1263 return _private::construct_expr(new _and(new _ref(*this)));
1264}
1265
1266
1267/** creates a NOT-expression out of this rule.
1268 @return a NOT-expression out of this rule.
1269 */
1270expr rule::operator !() {
1271 return _private::construct_expr(new _not(new _ref(*this)));
1272}
1273
1274
1275/** sets the parse procedure.
1276 @param p procedure.
1277 */
1278void rule::set_parse_proc(parse_proc p) {
1279 assert(p);
1280 m_parse_proc = p;
1281 _parse_proc_map_t& _parse_proc_map = _get_parse_proc_map();
1282 _parse_proc_map[this] = p;
1283}
1284
1285
1286/** creates a sequence of expressions.
1287 @param left left operand.
1288 @param right right operand.
1289 @return an expression which parses a sequence.
1290 */
1291expr operator >> (const expr &left, const expr &right) {
1292 return _private::construct_expr(
1293 new _seq(_private::get_expr(left), _private::get_expr(right)));
1294}
1295
1296
1297/** creates a choice of expressions.
1298 @param left left operand.
1299 @param right right operand.
1300 @return an expression which parses a choice.
1301 */
1302expr operator | (const expr &left, const expr &right) {
1303 return _private::construct_expr(
1304 new _choice(_private::get_expr(left), _private::get_expr(right)));
1305}
1306
1307
1308/** converts a parser expression into a terminal.
1309 @param e expression.
1310 @return an expression which parses a terminal.
1311 */
1312expr term(const expr &e) {
1313 return _private::construct_expr(
1314 new _term(_private::get_expr(e)));
1315}
1316
1317
1318/** creates a set expression from a null-terminated string.
1319 @param s null-terminated string with characters of the set.
1320 @return an expression which parses a single character out of a set.
1321 */
1322expr set(const char *s) {
1323 return _private::construct_expr(new _set(s));
1324}
1325
1326
1327/** creates a range expression.
1328 @param min min character.
1329 @param max max character.
1330 @return an expression which parses a single character out of range.
1331 */
1332expr range(int min, int max) {
1333 return _private::construct_expr(new _set(min, max));
1334}
1335
1336
1337/** creates an expression which increments the line counter
1338 and resets the column counter when the given expression
1339 is parsed successfully; used for newline characters.
1340 @param e expression to wrap into a newline parser.
1341 @return an expression that handles newlines.
1342 */
1343expr nl(const expr &e) {
1344 return _private::construct_expr(new _nl(_private::get_expr(e)));
1345}
1346
1347
1348/** creates an expression which tests for the end of input.
1349 @return an expression that handles the end of input.
1350 */
1351expr eof() {
1352 return _private::construct_expr(new _eof());
1353}
1354
1355
1356/** creates a not expression.
1357 @param e expression.
1358 @return the appropriate expression.
1359 */
1360expr not_(const expr &e) {
1361 return !e;
1362}
1363
1364
1365/** creates an and expression.
1366 @param e expression.
1367 @return the appropriate expression.
1368 */
1369expr and_(const expr &e) {
1370 return &e;
1371}
1372
1373
1374/** creates an expression that parses any character.
1375 @return the appropriate expression.
1376 */
1377expr any() {
1378 return _private::construct_expr(new _any());
1379}
1380
1381
1382/** parsing succeeds without consuming any input.
1383*/
1384expr true_() {
1385 return _private::construct_expr(new _true());
1386}
1387
1388
1389/** parsing fails without consuming any input.
1390*/
1391expr false_() {
1392 return _private::construct_expr(new _false());
1393}
1394
1395
1396/** parse with target expression and let user handle result.
1397*/
1398expr user(const expr &e, const user_handler& handler) {
1399 return _private::construct_expr(new _user(_private::get_expr(e), handler));
1400}
1401
1402
1403/** parses the given input.
1404 The parse procedures of each rule parsed are executed
1405 before this function returns, if parsing succeeds.
1406 @param i input.
1407 @param g root rule of grammar.
1408 @param el list of errors.
1409 @param d user data, passed to the parse procedures.
1410 @return true on parsing success, false on failure.
1411 */
1412bool parse(input &i, rule &g, error_list &el, void *d, void* ud) {
1413 //prepare context
1414 _context con(i, ud);
1415
1416 //parse grammar
1417 if (!con.parse_non_term(g)) {
1418 el.push_back(_syntax_error(con));
1419 return false;
1420 }
1421
1422 //if end is not reached, there was an error
1423 if (!con.end()) {
1424 if (con.m_error_pos.m_it < con.m_end) {
1425 el.push_back(_syntax_error(con));
1426 }
1427 else {
1428 el.push_back(_eof_error(con));
1429 }
1430 return false;
1431 }
1432
1433 //success; execute the parse procedures
1434 con.do_parse_procs(d);
1435 return true;
1436}
1437
1438
1439} //namespace parserlib
diff --git a/src/MoonP/parser.hpp b/src/MoonP/parser.hpp
new file mode 100644
index 0000000..9739465
--- /dev/null
+++ b/src/MoonP/parser.hpp
@@ -0,0 +1,435 @@
1/* Copyright (c) 2012, Achilleas Margaritis, modified by Jin Li
2All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
6 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
9THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
10
11#pragma once
12
13
14//gcc chokes without rule::rule(const rule &),
15//msvc complains when rule::rule(const rule &) is defined.
16#ifdef _MSC_VER
17#pragma warning (disable: 4521)
18#endif
19
20
21#include <vector>
22#include <string>
23#include <list>
24#include <functional>
25#include <codecvt>
26#include <locale>
27
28namespace parserlib {
29
30// const str hash helper functions
31inline constexpr size_t hash(char const* input)
32{
33 return *input ? *input + 33ull * hash(input + 1) : 5381;
34}
35inline size_t hash(const char* input, int size, int index)
36{
37 return index < size ? input[index] + 33ull * hash(input, size, index + 1) : 5381;
38}
39inline size_t constexpr operator"" _id(const char* s, size_t)
40{
41 return hash(s);
42}
43
44///type of the parser's input.
45typedef std::basic_string<wchar_t> input;
46typedef input::iterator input_it;
47typedef std::wstring_convert<std::codecvt_utf8<input::value_type>> Converter;
48
49class _private;
50class _expr;
51class _context;
52class rule;
53
54
55struct item_t
56{
57 input_it begin;
58 input_it end;
59 void* user_data;
60};
61typedef std::function<bool(const item_t&)> user_handler;
62
63
64///position into the input.
65class pos {
66public:
67 ///interator into the input.
68 input::iterator m_it;
69
70 ///line.
71 int m_line;
72
73 ///column.
74 int m_col;
75
76 ///null constructor.
77 pos():m_line(-1),m_col(0) {}
78
79 /** constructor from input.
80 @param i input.
81 */
82 pos(input &i);
83};
84
85
86/** a grammar expression.
87 */
88class expr {
89public:
90 /** character terminal constructor.
91 @param c character.
92 */
93 expr(char c);
94
95 /** null-terminated string terminal constructor.
96 @param s null-terminated string.
97 */
98 expr(const char *s);
99
100 /** rule reference constructor.
101 @param r rule.
102 */
103 expr(rule &r);
104
105 /** creates a zero-or-more loop out of this expression.
106 @return a zero-or-more loop expression.
107 */
108 expr operator *() const;
109
110 /** creates a one-or-more loop out of this expression.
111 @return a one-or-more loop expression.
112 */
113 expr operator +() const;
114
115 /** creates an optional out of this expression.
116 @return an optional expression.
117 */
118 expr operator -() const;
119
120 /** creates an AND-expression.
121 @return an AND-expression.
122 */
123 expr operator &() const;
124
125 /** creates a NOT-expression.
126 @return a NOT-expression.
127 */
128 expr operator !() const;
129
130private:
131 //internal expression
132 _expr *m_expr;
133
134 //internal constructor from internal expression
135 expr(_expr *e) : m_expr(e) {}
136
137 //assignment not allowed
138 expr &operator = (expr &);
139
140 friend class _private;
141};
142
143
144/** type of procedure to invoke when a rule is successfully parsed.
145 @param b begin position of input.
146 @param e end position of input.
147 @param d pointer to user data.
148 */
149typedef void (*parse_proc)(const pos &b, const pos &e, void *d);
150
151
152///input range.
153class input_range {
154public:
155 virtual ~input_range() {}
156
157 ///begin position.
158 pos m_begin;
159
160 ///end position.
161 pos m_end;
162
163 ///empty constructor.
164 input_range() {}
165
166 /** constructor.
167 @param b begin position.
168 @param e end position.
169 */
170 input_range(const pos &b, const pos &e);
171};
172
173
174///enum with error types.
175enum ERROR_TYPE {
176 ///syntax error
177 ERROR_SYNTAX_ERROR = 1,
178
179 ///invalid end of file
180 ERROR_INVALID_EOF,
181
182 ///first user error
183 ERROR_USER = 100
184};
185
186
187///error.
188class error : public input_range {
189public:
190 ///type
191 int m_type;
192
193 /** constructor.
194 @param b begin position.
195 @param e end position.
196 @param t type.
197 */
198 error(const pos &b, const pos &e, int t);
199
200 /** compare on begin position.
201 @param e the other error to compare this with.
202 @return true if this comes before the previous error, false otherwise.
203 */
204 bool operator < (const error &e) const;
205};
206
207
208///type of error list.
209typedef std::list<error> error_list;
210
211
212/** represents a rule.
213 */
214class rule {
215public:
216 /** character terminal constructor.
217 @param c character.
218 */
219 rule(char c);
220
221 /** null-terminated string terminal constructor.
222 @param s null-terminated string.
223 */
224 rule(const char *s);
225
226 /** constructor from expression.
227 @param e expression.
228 */
229 rule(const expr &e);
230
231 /** constructor from rule.
232 @param r rule.
233 */
234 rule(rule &r);
235
236 /** invalid constructor from rule (required by gcc).
237 @param r rule.
238 @exception std::logic_error always thrown.
239 */
240 rule(const rule &r);
241
242 /** deletes the internal object that represents the expression.
243 */
244 ~rule();
245
246 /** creates a zero-or-more loop out of this rule.
247 @return a zero-or-more loop rule.
248 */
249 expr operator *();
250
251 /** creates a one-or-more loop out of this rule.
252 @return a one-or-more loop rule.
253 */
254 expr operator +();
255
256 /** creates an optional out of this rule.
257 @return an optional rule.
258 */
259 expr operator -();
260
261 /** creates an AND-expression out of this rule.
262 @return an AND-expression out of this rule.
263 */
264 expr operator &();
265
266 /** creates a NOT-expression out of this rule.
267 @return a NOT-expression out of this rule.
268 */
269 expr operator !();
270
271 /** sets the parse procedure.
272 @param p procedure.
273 */
274 void set_parse_proc(parse_proc p);
275
276 /** get the this ptr (since operator & is overloaded).
277 @return pointer to this.
278 */
279 rule *this_ptr() { return this; }
280
281private:
282 //mode
283 enum _MODE {
284 _PARSE,
285 _REJECT,
286 _ACCEPT
287 };
288
289 //state
290 struct _state {
291 //position in source code, relative to start
292 size_t m_pos;
293
294 //mode
295 _MODE m_mode;
296
297 //constructor
298 _state(size_t pos = -1, _MODE mode = _PARSE) :
299 m_pos(pos), m_mode(mode) {}
300 };
301
302 //internal expression
303 _expr *m_expr;
304
305 //associated parse procedure.
306 parse_proc m_parse_proc;
307
308 //state
309 _state m_state;
310
311 //assignment not allowed
312 rule &operator = (rule &);
313
314 friend class _private;
315 friend class _context;
316};
317
318
319/** creates a sequence of expressions.
320 @param left left operand.
321 @param right right operand.
322 @return an expression which parses a sequence.
323 */
324expr operator >> (const expr &left, const expr &right);
325
326
327/** creates a choice of expressions.
328 @param left left operand.
329 @param right right operand.
330 @return an expression which parses a choice.
331 */
332expr operator | (const expr &left, const expr &right);
333
334
335/** converts a parser expression into a terminal.
336 @param e expression.
337 @return an expression which parses a terminal.
338 */
339expr term(const expr &e);
340
341
342/** creates a set expression from a null-terminated string.
343 @param s null-terminated string with characters of the set.
344 @return an expression which parses a single character out of a set.
345 */
346expr set(const char *s);
347
348
349/** creates a range expression.
350 @param min min character.
351 @param max max character.
352 @return an expression which parses a single character out of range.
353 */
354expr range(int min, int max);
355
356
357/** creates an expression which increments the line counter
358 and resets the column counter when the given expression
359 is parsed successfully; used for newline characters.
360 @param e expression to wrap into a newline parser.
361 @return an expression that handles newlines.
362 */
363expr nl(const expr &e);
364
365
366/** creates an expression which tests for the end of input.
367 @return an expression that handles the end of input.
368 */
369expr eof();
370
371
372/** creates a not expression.
373 @param e expression.
374 @return the appropriate expression.
375 */
376expr not_(const expr &e);
377
378
379/** creates an and expression.
380 @param e expression.
381 @return the appropriate expression.
382 */
383expr and_(const expr &e);
384
385
386/** creates an expression that parses any character.
387 @return the appropriate expression.
388 */
389expr any();
390
391
392/** parsing succeeds without consuming any input.
393 */
394expr true_();
395
396
397/** parsing fails without consuming any input.
398*/
399expr false_();
400
401
402/** parse with target expression and let user handle result.
403*/
404expr user(const expr &e, const user_handler& handler);
405
406
407/** parses the given input.
408 The parse procedures of each rule parsed are executed
409 before this function returns, if parsing succeeds.
410 @param i input.
411 @param g root rule of grammar.
412 @param el list of errors.
413 @param d user data, passed to the parse procedures.
414 @return true on parsing success, false on failure.
415 */
416bool parse(input &i, rule &g, error_list &el, void *d, void* ud);
417
418
419/** output the specific input range to the specific stream.
420 @param stream stream.
421 @param ir input range.
422 @return the stream.
423 */
424template <class T> T &operator << (T &stream, const input_range &ir) {
425 for(input::const_iterator it = ir.m_begin.m_it;
426 it != ir.m_end.m_it;
427 ++it)
428 {
429 stream << (typename T::char_type)*it;
430 }
431 return stream;
432}
433
434
435} //namespace parserlib
diff --git a/src/moonc.cpp b/src/moonc.cpp
new file mode 100644
index 0000000..d9d3ce3
--- /dev/null
+++ b/src/moonc.cpp
@@ -0,0 +1,178 @@
1/* Copyright (c) 2020 Jin Li, http://www.luvfight.me
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
5The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
7THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
8#include <iostream>
9#include <iomanip>
10#include <fstream>
11#include <chrono>
12#include "MoonP/moon_compiler.h"
13#include "MoonP/parser.hpp"
14#include "MoonP/moon_ast.h"
15
16int main(int narg, const char** args) {
17 const char* help =
18"Usage: moonc [options|files] ...\n\n"
19" -h Print this message\n"
20" -t path Specify where to place compiled files\n"
21" -o file Write output to file\n"
22" -p Write output to standard out\n"
23" -b Dump compile time (doesn't write output)\n"
24" -l Write line numbers from source codes\n"
25" -a Allow expression list not in the end of body block\n"
26" -s Use space over tab\n"
27" -v Print version\n";
28 if (narg == 0) {
29 std::cout << help;
30 return 0;
31 }
32 MoonP::MoonConfig config;
33 bool writeToFile = true;
34 bool dumpCompileTime = false;
35 std::string targetPath;
36 std::string resultFile;
37 std::list<std::string> files;
38 for (int i = 1; i < narg; ++i) {
39 switch (hash(args[i])) {
40 case "-a"_id:
41 config.allowExprNotInTheEndOfBody = true;
42 break;
43 case "-s"_id:
44 config.spaceOverTab = true;
45 break;
46 case "-l"_id:
47 config.reserveLineNumber = true;
48 break;
49 case "-r"_id:
50 config.reuseVariable = true;
51 break;
52 case "-p"_id:
53 writeToFile = false;
54 break;
55 case "-t"_id:
56 ++i;
57 if (i < narg) {
58 targetPath = args[i];
59 } else {
60 std::cout << help;
61 return 1;
62 }
63 break;
64 case "-b"_id:
65 dumpCompileTime = true;
66 break;
67 case "-h"_id:
68 std::cout << help;
69 return 0;
70 case "-v"_id:
71 std::cout << "Moonscript version: " << MoonP::moonScriptVersion() << '\n';
72 break;
73 case "-o"_id:
74 ++i;
75 if (i < narg) {
76 resultFile = args[i];
77 } else {
78 std::cout << help;
79 return 1;
80 }
81 break;
82 default:
83 files.push_back(args[i]);
84 break;
85 }
86 }
87 if (files.empty()) {
88 std::cout << help;
89 return 0;
90 }
91 if (!resultFile.empty() && files.size() > 1) {
92 std::cout << "Error: -o can not be used with multiple input files.\n";
93 std::cout << help;
94 }
95 for (const auto& file : files) {
96 std::ifstream input(file, input.in);
97 if (input) {
98 std::string s(
99 (std::istreambuf_iterator<char>(input)),
100 std::istreambuf_iterator<char>());
101 if (dumpCompileTime) {
102 auto start = std::chrono::high_resolution_clock::now();
103 auto result = MoonP::moonCompile(s, config);
104 auto end = std::chrono::high_resolution_clock::now();
105 if (!std::get<0>(result).empty()) {
106 std::chrono::duration<double> diff = end - start;
107 error_list el;
108 MoonP::State st;
109 start = std::chrono::high_resolution_clock::now();
110 auto input = Converter{}.from_bytes(s);
111 parserlib::parse<MoonP::File_t>(input, MoonP::File, el, &st);
112 end = std::chrono::high_resolution_clock::now();
113 std::chrono::duration<double> parseDiff = end - start;
114 std::cout << file << " \n";
115 std::cout << "Parse time: " << std::setprecision(5) << parseDiff.count() * 1000 << " ms\n";
116 std::cout << "Compile time: " << std::setprecision(5) << (diff.count() - parseDiff.count()) * 1000 << " ms\n\n";
117 } else {
118 std::cout << "Fail to compile: " << file << ".\n";
119 std::cout << std::get<1>(result) << '\n';
120 return 1;
121 }
122 continue;
123 }
124 auto result = MoonP::moonCompile(s, config);
125 if (!std::get<0>(result).empty()) {
126 if (!writeToFile) {
127 std::cout << std::get<0>(result) << '\n';
128 } else {
129 std::string targetFile;
130 if (resultFile.empty()) {
131 std::string ext;
132 targetFile = file;
133 size_t pos = file.rfind('.');
134 if (pos != std::string::npos) {
135 ext = file.substr(pos + 1);
136 for (size_t i = 0; i < ext.length(); i++) {
137 ext[i] = static_cast<char>(tolower(ext[i]));
138 }
139 targetFile = file.substr(0, pos) + ".lua";
140 }
141 if (!targetPath.empty()) {
142 std::string name;
143 pos = targetFile.find_last_of("/\\");
144 if (pos == std::string::npos) {
145 name = targetFile;
146 } else {
147 name = targetFile.substr(pos + 1);
148 }
149 if (targetPath.back() != '/' && targetPath.back() != '\\') {
150 targetPath.append("/");
151 }
152 targetFile = targetPath + name;
153 }
154 } else {
155 targetFile = resultFile;
156 }
157 std::ofstream output(targetFile, output.trunc | output.out);
158 if (output) {
159 const auto& codes = std::get<0>(result);
160 output.write(codes.c_str(), codes.size());
161 std::cout << "Built " << file << '\n';
162 } else {
163 std::cout << "Fail to write file: " << targetFile << ".\n";
164 return 1;
165 }
166 }
167 } else {
168 std::cout << "Fail to compile: " << file << ".\n";
169 std::cout << std::get<1>(result) << '\n';
170 return 1;
171 }
172 } else {
173 std::cout << "Fail to read file: " << file << ".\n";
174 return 1;
175 }
176 }
177 return 0;
178}