aboutsummaryrefslogtreecommitdiff
path: root/src/MoonP
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2021-02-17 11:22:07 +0800
committerLi Jin <dragon-fly@qq.com>2021-02-17 11:22:07 +0800
commit7066392d1c974065181d95d93274136dcd625d43 (patch)
treecf51eafc2c52cbc12246a306bca172d799193d30 /src/MoonP
parent90cd12ad9ef465f3e435e1bd034dcfbe4e19d016 (diff)
downloadyuescript-7066392d1c974065181d95d93274136dcd625d43.tar.gz
yuescript-7066392d1c974065181d95d93274136dcd625d43.tar.bz2
yuescript-7066392d1c974065181d95d93274136dcd625d43.zip
stop reusing variables, rename project.
Diffstat (limited to 'src/MoonP')
-rw-r--r--src/MoonP/ast.cpp147
-rw-r--r--src/MoonP/ast.hpp571
-rw-r--r--src/MoonP/moon_ast.h750
-rw-r--r--src/MoonP/moon_compiler.cpp5622
-rw-r--r--src/MoonP/moon_compiler.h63
-rw-r--r--src/MoonP/moon_parser.cpp719
-rw-r--r--src/MoonP/moon_parser.h317
-rw-r--r--src/MoonP/moonplus.cpp139
-rw-r--r--src/MoonP/moonplus.h251
-rw-r--r--src/MoonP/parser.cpp1412
-rw-r--r--src/MoonP/parser.hpp422
-rw-r--r--src/MoonP/stacktraceplus.h528
12 files changed, 0 insertions, 10941 deletions
diff --git a/src/MoonP/ast.cpp b/src/MoonP/ast.cpp
deleted file mode 100644
index 4929021..0000000
--- a/src/MoonP/ast.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
1/* Copyright (c) 2012, Achilleas Margaritis, modified by Jin Li
2All rights reserved.
3
4Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
6Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
8Redistributions 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.
9
10THIS 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.*/
11
12#include <cassert>
13
14#include "MoonP/ast.hpp"
15
16
17namespace parserlib {
18
19
20traversal ast_node::traverse(const std::function<traversal (ast_node*)>& func) {
21 return func(this);
22}
23
24ast_node* ast_node::getByTypeIds(int* begin, int* end) {
25 ast_node* current = this;
26 auto it = begin;
27 while (it != end) {
28 ast_node* findNode = nullptr;
29 int i = *it;
30 current->visitChild([&](ast_node* node) {
31 if (node->getId() == i) {
32 findNode = node;
33 return true;
34 }
35 return false;
36 });
37 if (findNode) {
38 current = findNode;
39 } else {
40 current = nullptr;
41 break;
42 }
43 ++it;
44 }
45 return current;
46}
47
48bool ast_node::visitChild(const std::function<bool (ast_node*)>&) {
49 return false;
50}
51
52
53/** Asks all members to construct themselves from the stack.
54 The members are asked to construct themselves in reverse order.
55 from a node stack.
56 @param st stack.
57*/
58void ast_container::construct(ast_stack &st) {
59 for(ast_member_vector::reverse_iterator it = m_members.rbegin();
60 it != m_members.rend();
61 ++it)
62 {
63 ast_member* member = *it;
64 member->construct(st);
65 }
66}
67
68traversal ast_container::traverse(const std::function<traversal (ast_node*)>& func) {
69 traversal action = func(this);
70 switch (action) {
71 case traversal::Stop: return traversal::Stop;
72 case traversal::Return: return traversal::Continue;
73 default: break;
74 }
75 const auto& members = this->members();
76 for (auto member : members) {
77 switch (member->get_type()) {
78 case ast_holder_type::Pointer: {
79 _ast_ptr* ptr = static_cast<_ast_ptr*>(member);
80 if (ptr->get() && ptr->get()->traverse(func) == traversal::Stop) {
81 return traversal::Stop;
82 }
83 break;
84 }
85 case ast_holder_type::List: {
86 _ast_list* list = static_cast<_ast_list*>(member);
87 for (auto obj : list->objects()) {
88 if (obj->traverse(func) == traversal::Stop) {
89 return traversal::Stop;
90 }
91 }
92 break;
93 }
94 }
95 }
96 return traversal::Continue;
97}
98
99bool ast_container::visitChild(const std::function<bool (ast_node*)>& func) {
100 const auto& members = this->members();
101 for (auto member : members) {
102 switch (member->get_type()) {
103 case ast_holder_type::Pointer: {
104 _ast_ptr* ptr = static_cast<_ast_ptr*>(member);
105 if (ptr->get()) {
106 if (func(ptr->get())) return true;
107 }
108 break;
109 }
110 case ast_holder_type::List: {
111 _ast_list* list = static_cast<_ast_list*>(member);
112 for (auto obj : list->objects()) {
113 if (obj) {
114 if (func(obj)) return true;
115 }
116 }
117 break;
118 }
119 }
120 }
121 return false;
122}
123
124
125/** parses the given input.
126 @param i input.
127 @param g root rule of grammar.
128 @param el list of errors.
129 @param ud user data, passed to the parse procedures.
130 @return pointer to ast node created, or null if there was an error.
131 The return object must be deleted by the caller.
132*/
133ast_node* parse(input& i, rule& g, error_list& el, void* ud) {
134 ast_stack st;
135 if (!parse(i, g, el, &st, ud)) {
136 for (auto node : st) {
137 delete node;
138 }
139 st.clear();
140 return nullptr;
141 }
142 assert(st.size() == 1);
143 return st.front();
144}
145
146
147} //namespace parserlib
diff --git a/src/MoonP/ast.hpp b/src/MoonP/ast.hpp
deleted file mode 100644
index 104202d..0000000
--- a/src/MoonP/ast.hpp
+++ /dev/null
@@ -1,571 +0,0 @@
1/* Copyright (c) 2012, Achilleas Margaritis, modified by Jin Li
2All rights reserved.
3
4Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
6Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
8Redistributions 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.
9
10THIS 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.*/
11
12#pragma once
13
14
15#include <cassert>
16#include <list>
17#include <stdexcept>
18#include <type_traits>
19
20#include "MoonP/parser.hpp"
21
22
23namespace parserlib {
24
25
26class ast_node;
27template <bool Required, class T> class ast_ptr;
28template <bool Required, class T> class ast_list;
29template <class T> class ast;
30
31
32/** type of AST node stack.
33*/
34typedef std::vector<ast_node*> ast_stack;
35typedef std::list<ast_node*> node_container;
36
37
38template<size_t Num> struct Counter { enum { value = Counter<Num-1>::value }; };
39template<> struct Counter<0> { enum { value = 0 }; };
40
41#define COUNTER_READ Counter<__LINE__>::value
42#define COUNTER_INC template<> struct Counter<__LINE__> { enum { value = Counter<__LINE__-1>::value + 1}; }
43
44class ast_node;
45template<class T>
46constexpr typename std::enable_if<std::is_base_of<ast_node,T>::value,int>::type
47id();
48
49enum class traversal {
50 Continue,
51 Return,
52 Stop
53};
54
55/** Base class for AST nodes.
56*/
57class ast_node : public input_range {
58public:
59 ast_node() : _ref(0) {}
60
61 void retain() {
62 ++_ref;
63 }
64
65 void release() {
66 --_ref;
67 if (_ref == 0) {
68 delete this;
69 }
70 }
71
72 /** interface for filling the contents of the node
73 from a node stack.
74 @param st stack.
75 */
76 virtual void construct(ast_stack&) {}
77
78 /** interface for visiting AST tree use.
79 */
80 virtual traversal traverse(const std::function<traversal (ast_node*)>& func);
81
82 template <typename... Ts>
83 struct select_last {
84 using type = typename decltype((std::enable_if<true,Ts>{}, ...))::type;
85 };
86 template <typename... Ts>
87 using select_last_t = typename select_last<Ts...>::type;
88
89 template <class ...Args>
90 select_last_t<Args...>* getByPath() {
91 int types[] = {id<Args>()...};
92 return static_cast<select_last_t<Args...>*>(getByTypeIds(std::begin(types), std::end(types)));
93 }
94
95 virtual bool visitChild(const std::function<bool (ast_node*)>& func);
96
97 virtual int getId() const = 0;
98
99 template<class T>
100 inline ast_ptr<false, T> new_ptr() const {
101 auto item = new T;
102 item->m_begin.m_line = m_begin.m_line;
103 item->m_end.m_line = m_begin.m_line;
104 return ast_ptr<false, T>(item);
105 }
106private:
107 int _ref;
108 ast_node* getByTypeIds(int* begin, int* end);
109};
110
111template<class T>
112constexpr typename std::enable_if<std::is_base_of<ast_node,T>::value,int>::type
113id() { return 0; }
114
115template<class T>
116T* ast_cast(ast_node* node) {
117 return node && id<T>() == node->getId() ? static_cast<T*>(node) : nullptr;
118}
119
120template<class T>
121T* ast_to(ast_node* node) {
122 assert(node->getId() == id<T>());
123 return static_cast<T*>(node);
124}
125
126template <class ...Args>
127bool ast_is(ast_node* node) {
128 if (!node) return false;
129 bool result = false;
130 int i = node->getId();
131 using swallow = bool[];
132 (void)swallow{result || (result = id<Args>() == i)...};
133 return result;
134}
135
136class ast_member;
137
138/** type of ast member vector.
139*/
140typedef std::vector<ast_member*> ast_member_vector;
141
142
143/** base class for AST nodes with children.
144*/
145class ast_container : public ast_node {
146public:
147 void add_members(std::initializer_list<ast_member*> members) {
148 for (auto member : members) {
149 m_members.push_back(member);
150 }
151 }
152
153 /** returns the vector of AST members.
154 @return the vector of AST members.
155 */
156 const ast_member_vector& members() const {
157 return m_members;
158 }
159
160 /** Asks all members to construct themselves from the stack.
161 The members are asked to construct themselves in reverse order.
162 from a node stack.
163 @param st stack.
164 */
165 virtual void construct(ast_stack& st) override;
166
167 virtual traversal traverse(const std::function<traversal (ast_node*)>& func) override;
168
169 virtual bool visitChild(const std::function<bool (ast_node*)>& func) override;
170private:
171 ast_member_vector m_members;
172
173 friend class ast_member;
174};
175
176enum class ast_holder_type {
177 Pointer,
178 List
179};
180
181/** Base class for children of ast_container.
182*/
183class ast_member {
184public:
185 virtual ~ast_member() {}
186
187 /** interface for filling the the member from a node stack.
188 @param st stack.
189 */
190 virtual void construct(ast_stack& st) = 0;
191
192 virtual bool accept(ast_node* node) = 0;
193
194 virtual ast_holder_type get_type() const = 0;
195};
196
197
198class _ast_ptr : public ast_member {
199public:
200 _ast_ptr(ast_node* node) : m_ptr(node) {
201 if (node) node->retain();
202 }
203
204 virtual ~_ast_ptr() {
205 if (m_ptr) {
206 m_ptr->release();
207 m_ptr = nullptr;
208 }
209 }
210
211 ast_node* get() const {
212 return m_ptr;
213 }
214
215 template <class T>
216 T* as() const {
217 return ast_cast<T>(m_ptr);
218 }
219
220 template <class T>
221 T* to() const {
222 assert(m_ptr && m_ptr->getId() == id<T>());
223 return static_cast<T*>(m_ptr);
224 }
225
226 template <class T>
227 bool is() const {
228 return m_ptr && m_ptr->getId() == id<T>();
229 }
230
231 void set(ast_node* node) {
232 if (node == m_ptr) {
233 return;
234 } else if (!node) {
235 if (m_ptr) m_ptr->release();
236 m_ptr = nullptr;
237 } else {
238 assert(accept(node));
239 if (m_ptr) m_ptr->release();
240 m_ptr = node;
241 node->retain();
242 }
243 }
244
245 virtual ast_holder_type get_type() const override {
246 return ast_holder_type::Pointer;
247 }
248protected:
249 ast_node* m_ptr;
250};
251
252/** pointer to an AST object.
253 It assumes ownership of the object.
254 It pops an object of the given type from the stack.
255 @tparam Required if true, the object is required.
256 @tparam T type of object to control.
257*/
258template <bool Required, class T> class ast_ptr : public _ast_ptr {
259public:
260 ast_ptr(T* node = nullptr) : _ast_ptr(node) {}
261
262 ast_ptr(const ast_ptr& other) : _ast_ptr(other.get()) {}
263
264 ast_ptr& operator=(const ast_ptr& other) {
265 set(other.get());
266 return *this;
267 }
268
269 /** gets the underlying ptr value.
270 @return the underlying ptr value.
271 */
272 T* get() const {
273 return static_cast<T*>(m_ptr);
274 }
275
276 /** auto conversion to the underlying object ptr.
277 @return the underlying ptr value.
278 */
279 operator T*() const {
280 return static_cast<T*>(m_ptr);
281 }
282
283 /** member access.
284 @return the underlying ptr value.
285 */
286 T* operator->() const {
287 assert(m_ptr);
288 return static_cast<T*>(m_ptr);
289 }
290
291 /** Pops a node from the stack.
292 @param st stack.
293 @exception std::logic_error thrown if the node is not of the appropriate type;
294 thrown only if Required == true or if the stack is empty.
295 */
296 virtual void construct(ast_stack& st) override {
297 // check the stack node
298 if (st.empty()) {
299 if (!Required) return;
300 throw std::logic_error("Invalid AST stack.");
301 }
302 ast_node* node = st.back();
303 if (!ast_ptr::accept(node)) {
304 // if the object is not required, simply return
305 if (!Required) return;
306 // else if the object is mandatory, throw an exception
307 throw std::logic_error("Invalid AST node.");
308 }
309 st.pop_back();
310 m_ptr = node;
311 node->retain();
312 }
313private:
314 virtual bool accept(ast_node* node) override {
315 return node && (std::is_same<ast_node,T>() || id<T>() == node->getId());
316 }
317};
318
319template <bool Required, class ...Args> class ast_sel : public _ast_ptr {
320public:
321 ast_sel() : _ast_ptr(nullptr) {}
322
323 ast_sel(const ast_sel& other) : _ast_ptr(other.get()) {}
324
325 ast_sel& operator=(const ast_sel& other) {
326 set(other.get());
327 return *this;
328 }
329
330 operator ast_node*() const {
331 return m_ptr;
332 }
333
334 ast_node* operator->() const {
335 assert(m_ptr);
336 return m_ptr;
337 }
338
339 virtual void construct(ast_stack& st) override {
340 if (st.empty()) {
341 if (!Required) return;
342 throw std::logic_error("Invalid AST stack.");
343 }
344 ast_node* node = st.back();
345 if (!ast_sel::accept(node)) {
346 if (!Required) return;
347 throw std::logic_error("Invalid AST node.");
348 }
349 st.pop_back();
350 m_ptr = node;
351 node->retain();
352 }
353private:
354 virtual bool accept(ast_node* node) override {
355 if (!node) return false;
356 using swallow = bool[];
357 bool result = false;
358 (void)swallow{result || (result = id<Args>() == node->getId())...};
359 return result;
360 }
361};
362
363class _ast_list : public ast_member {
364public:
365 ~_ast_list() {
366 clear();
367 }
368
369 inline ast_node* back() const {
370 return m_objects.back();
371 }
372
373 inline ast_node* front() const {
374 return m_objects.front();
375 }
376
377 inline size_t size() const {
378 return m_objects.size();
379 }
380
381 inline bool empty() const {
382 return m_objects.empty();
383 }
384
385 void push_back(ast_node* node) {
386 assert(node && accept(node));
387 m_objects.push_back(node);
388 node->retain();
389 }
390
391 void push_front(ast_node* node) {
392 assert(node && accept(node));
393 m_objects.push_front(node);
394 node->retain();
395 }
396
397 void pop_front() {
398 auto node = m_objects.front();
399 m_objects.pop_front();
400 node->release();
401 }
402
403 void pop_back() {
404 auto node = m_objects.back();
405 m_objects.pop_back();
406 node->release();
407 }
408
409 bool swap(ast_node* node, ast_node* other) {
410 for (auto it = m_objects.begin(); it != m_objects.end(); ++it) {
411 if (*it == node) {
412 *it = other;
413 other->retain();
414 node->release();
415 return true;
416 }
417 }
418 return false;
419 }
420
421 const node_container& objects() const {
422 return m_objects;
423 }
424
425 void clear() {
426 for(ast_node* obj : m_objects) {
427 if (obj) obj->release();
428 }
429 m_objects.clear();
430 }
431
432 void dup(const _ast_list& src) {
433 for(ast_node* obj : src.m_objects) {
434 m_objects.push_back(obj);
435 obj->retain();
436 }
437 }
438
439 virtual ast_holder_type get_type() const override {
440 return ast_holder_type::List;
441 }
442protected:
443 node_container m_objects;
444};
445
446/** A list of objects.
447 It pops objects of the given type from the ast stack, until no more objects can be popped.
448 It assumes ownership of objects.
449 @tparam Required if true, the object is required.
450 @tparam T type of object to control.
451*/
452template <bool Required, class T> class ast_list : public _ast_list {
453public:
454 ast_list() { }
455
456 ast_list(const ast_list& other) {
457 dup(other);
458 }
459
460 ast_list& operator=(const ast_list& other) {
461 clear();
462 dup(other);
463 return *this;
464 }
465
466 /** Pops objects of type T from the stack until no more objects can be popped.
467 @param st stack.
468 */
469 virtual void construct(ast_stack &st) override {
470 while (!st.empty()) {
471 ast_node* node = st.back();
472 // if the object was not not of the appropriate type,
473 // end the list parsing
474 if (!ast_list::accept(node)) {
475 if (Required && m_objects.empty()) {
476 throw std::logic_error("Invalid AST node.");
477 }
478 return;
479 }
480 st.pop_back();
481 // insert the object in the list, in reverse order
482 m_objects.push_front(node);
483 node->retain();
484 }
485 if (Required && m_objects.empty()) {
486 throw std::logic_error("Invalid AST stack.");
487 }
488 }
489private:
490 virtual bool accept(ast_node* node) override {
491 return node && (std::is_same<ast_node,T>() || id<T>() == node->getId());
492 }
493};
494
495template <bool Required, class ...Args> class ast_sel_list : public _ast_list {
496public:
497 ast_sel_list() { }
498
499 ast_sel_list(const ast_sel_list& other) {
500 dup(other);
501 }
502
503 ast_sel_list& operator=(const ast_sel_list& other) {
504 clear();
505 dup(other);
506 return *this;
507 }
508
509 virtual void construct(ast_stack &st) override {
510 while (!st.empty()) {
511 ast_node* node = st.back();
512 if (!ast_sel_list::accept(node)) {
513 if (Required && m_objects.empty()) {
514 throw std::logic_error("Invalid AST node.");
515 }
516 return;
517 }
518 st.pop_back();
519 m_objects.push_front(node);
520 node->retain();
521 }
522 if (Required && m_objects.empty()) {
523 throw std::logic_error("Invalid AST stack.");
524 }
525 }
526private:
527 virtual bool accept(ast_node* node) override {
528 if (!node) return false;
529 using swallow = bool[];
530 bool result = false;
531 (void)swallow{result || (result = id<Args>() == node->getId())...};
532 return result;
533 }
534};
535
536/** AST function which creates an object of type T
537 and pushes it to the node stack.
538*/
539template <class T> class ast {
540public:
541 /** constructor.
542 @param r rule to attach the AST function to.
543 */
544 ast(rule& r) {
545 r.set_parse_proc(&_parse_proc);
546 }
547private:
548 //parse proc
549 static void _parse_proc(const pos& b, const pos& e, void* d) {
550 ast_stack* st = reinterpret_cast<ast_stack*>(d);
551 T* obj = new T;
552 obj->m_begin = b;
553 obj->m_end = e;
554 obj->construct(*st);
555 st->push_back(obj);
556 }
557};
558
559
560/** parses the given input.
561 @param i input.
562 @param g root rule of grammar.
563 @param el list of errors.
564 @param ud user data, passed to the parse procedures.
565 @return pointer to ast node created, or null if there was an error.
566 The return object must be deleted by the caller.
567*/
568ast_node* parse(input& i, rule& g, error_list& el, void* ud);
569
570
571} //namespace parserlib
diff --git a/src/MoonP/moon_ast.h b/src/MoonP/moon_ast.h
deleted file mode 100644
index 6b738d4..0000000
--- a/src/MoonP/moon_ast.h
+++ /dev/null
@@ -1,750 +0,0 @@
1/* Copyright (c) 2021 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/ast.hpp"
12
13namespace parserlib {
14
15#define AST_LEAF(type) \
16COUNTER_INC; \
17class type##_t : public ast_node \
18{ \
19public: \
20 virtual int getId() const override { return COUNTER_READ; }
21
22#define AST_NODE(type) \
23COUNTER_INC; \
24class type##_t : public ast_container \
25{ \
26public: \
27 virtual int getId() const override { return COUNTER_READ; }
28
29#define AST_MEMBER(type, ...) \
30 type##_t() { \
31 add_members({__VA_ARGS__}); \
32 }
33
34#define AST_END(type) \
35}; \
36template<> constexpr int id<type##_t>() { return COUNTER_READ; }
37
38AST_LEAF(Num)
39AST_END(Num)
40
41AST_LEAF(Name)
42AST_END(Name)
43
44AST_NODE(Variable)
45 ast_ptr<true, Name_t> name;
46 AST_MEMBER(Variable, &name)
47AST_END(Variable)
48
49AST_NODE(LabelName)
50 ast_ptr<true, Name_t> name;
51 AST_MEMBER(LabelName, &name)
52AST_END(LabelName)
53
54AST_NODE(LuaKeyword)
55 ast_ptr<true, Name_t> name;
56 AST_MEMBER(LuaKeyword, &name)
57AST_END(LuaKeyword)
58
59AST_LEAF(self)
60AST_END(self)
61
62AST_NODE(self_name)
63 ast_ptr<true, Name_t> name;
64 AST_MEMBER(self_name, &name)
65AST_END(self_name)
66
67AST_LEAF(self_class)
68AST_END(self_class)
69
70AST_NODE(self_class_name)
71 ast_ptr<true, Name_t> name;
72 AST_MEMBER(self_class_name, &name)
73AST_END(self_class_name)
74
75AST_NODE(SelfName)
76 ast_sel<true, self_class_name_t, self_class_t, self_name_t, self_t> name;
77 AST_MEMBER(SelfName, &name)
78AST_END(SelfName)
79
80AST_NODE(KeyName)
81 ast_sel<true, SelfName_t, Name_t> name;
82 AST_MEMBER(KeyName, &name)
83AST_END(KeyName)
84
85AST_LEAF(VarArg)
86AST_END(VarArg)
87
88AST_LEAF(local_flag)
89AST_END(local_flag)
90
91AST_LEAF(Seperator)
92AST_END(Seperator)
93
94AST_NODE(NameList)
95 ast_ptr<true, Seperator_t> sep;
96 ast_list<true, Variable_t> names;
97 AST_MEMBER(NameList, &sep, &names)
98AST_END(NameList)
99
100class ExpListLow_t;
101class TableBlock_t;
102
103AST_NODE(local_values)
104 ast_ptr<true, NameList_t> nameList;
105 ast_sel<false, TableBlock_t, ExpListLow_t> valueList;
106 AST_MEMBER(local_values, &nameList, &valueList)
107AST_END(local_values)
108
109AST_NODE(Local)
110 ast_sel<true, local_flag_t, local_values_t> item;
111 std::list<std::string> forceDecls;
112 std::list<std::string> decls;
113 bool collected = false;
114 bool defined = false;
115 AST_MEMBER(Local, &item)
116AST_END(Local)
117
118class Assign_t;
119
120AST_NODE(LocalAttrib)
121 ast_ptr<true, Name_t> attrib;
122 ast_ptr<true, NameList_t> nameList;
123 ast_ptr<true, Assign_t> assign;
124 AST_MEMBER(LocalAttrib, &attrib, &nameList, &assign)
125AST_END(LocalAttrib)
126
127AST_NODE(colon_import_name)
128 ast_ptr<true, Variable_t> name;
129 AST_MEMBER(colon_import_name, &name)
130AST_END(colon_import_name)
131
132class Exp_t;
133class TableLit_t;
134
135AST_LEAF(import_literal_inner)
136AST_END(import_literal_inner)
137
138AST_NODE(ImportLiteral)
139 ast_ptr<true, Seperator_t> sep;
140 ast_sel_list<true, import_literal_inner_t> inners;
141 AST_MEMBER(ImportLiteral, &sep, &inners)
142AST_END(ImportLiteral)
143
144AST_NODE(ImportFrom)
145 ast_ptr<true, Seperator_t> sep;
146 ast_sel_list<true, colon_import_name_t, Variable_t> names;
147 ast_ptr<true, Exp_t> exp;
148 AST_MEMBER(ImportFrom, &sep, &names, &exp)
149AST_END(ImportFrom)
150
151class MacroName_t;
152
153AST_NODE(macro_name_pair)
154 ast_ptr<true, MacroName_t> key;
155 ast_ptr<true, MacroName_t> value;
156 AST_MEMBER(macro_name_pair, &key, &value)
157AST_END(macro_name_pair)
158
159AST_LEAF(import_all_macro)
160AST_END(import_all_macro)
161
162class variable_pair_t;
163class normal_pair_t;
164
165AST_NODE(ImportTabLit)
166 ast_ptr<true, Seperator_t> sep;
167 ast_sel_list<false, variable_pair_t, normal_pair_t, MacroName_t, macro_name_pair_t, import_all_macro_t> items;
168 AST_MEMBER(ImportTabLit, &sep, &items)
169AST_END(ImportTabLit)
170
171AST_NODE(ImportAs)
172 ast_ptr<true, ImportLiteral_t> literal;
173 ast_sel<false, Variable_t, ImportTabLit_t> target;
174 AST_MEMBER(ImportAs, &literal, &target)
175AST_END(ImportAs)
176
177AST_NODE(Import)
178 ast_sel<true, ImportAs_t, ImportFrom_t> content;
179 AST_MEMBER(Import, &content)
180AST_END(Import)
181
182AST_NODE(Label)
183 ast_ptr<true, LabelName_t> label;
184 AST_MEMBER(Label, &label)
185AST_END(Label)
186
187AST_NODE(Goto)
188 ast_ptr<true, LabelName_t> label;
189 AST_MEMBER(Goto, &label)
190AST_END(Goto)
191
192class FnArgsDef_t;
193
194AST_LEAF(fn_arrow_back)
195AST_END(fn_arrow_back)
196
197class ChainValue_t;
198
199AST_NODE(Backcall)
200 ast_ptr<false, FnArgsDef_t> argsDef;
201 ast_ptr<true, fn_arrow_back_t> arrow;
202 ast_ptr<true, ChainValue_t> value;
203 AST_MEMBER(Backcall, &argsDef, &arrow, &value)
204AST_END(Backcall)
205
206AST_NODE(ExpListLow)
207 ast_ptr<true, Seperator_t> sep;
208 ast_list<true, Exp_t> exprs;
209 AST_MEMBER(ExpListLow, &sep, &exprs)
210AST_END(ExpListLow)
211
212AST_NODE(ExpList)
213 ast_ptr<true, Seperator_t> sep;
214 ast_list<true, Exp_t> exprs;
215 AST_MEMBER(ExpList, &sep, &exprs)
216AST_END(ExpList)
217
218AST_NODE(Return)
219 bool allowBlockMacroReturn = false;
220 ast_ptr<false, ExpListLow_t> valueList;
221 AST_MEMBER(Return, &valueList)
222AST_END(Return)
223
224class existential_op_t;
225class Assign_t;
226class Block_t;
227class Statement_t;
228
229AST_NODE(With)
230 ast_ptr<false, existential_op_t> eop;
231 ast_ptr<true, ExpList_t> valueList;
232 ast_ptr<false, Assign_t> assigns;
233 ast_sel<true, Block_t, Statement_t> body;
234 AST_MEMBER(With, &eop, &valueList, &assigns, &body)
235AST_END(With)
236
237AST_NODE(SwitchCase)
238 ast_ptr<true, ExpList_t> valueList;
239 ast_sel<true, Block_t, Statement_t> body;
240 AST_MEMBER(SwitchCase, &valueList, &body)
241AST_END(SwitchCase)
242
243AST_NODE(Switch)
244 ast_ptr<true, Exp_t> target;
245 ast_ptr<true, Seperator_t> sep;
246 ast_list<true, SwitchCase_t> branches;
247 ast_sel<false, Block_t, Statement_t> lastBranch;
248 AST_MEMBER(Switch, &target, &sep, &branches, &lastBranch)
249AST_END(Switch)
250
251AST_NODE(IfCond)
252 ast_ptr<true, Exp_t> condition;
253 ast_ptr<false, Assign_t> assign;
254 AST_MEMBER(IfCond, &condition, &assign)
255AST_END(IfCond)
256
257AST_NODE(If)
258 ast_ptr<true, Seperator_t> sep;
259 ast_sel_list<true, IfCond_t, Block_t, Statement_t> nodes;
260 AST_MEMBER(If, &sep, &nodes)
261AST_END(If)
262
263AST_NODE(Unless)
264 ast_ptr<true, Seperator_t> sep;
265 ast_sel_list<true, IfCond_t, Block_t, Statement_t> nodes;
266 AST_MEMBER(Unless, &sep, &nodes)
267AST_END(Unless)
268
269AST_NODE(While)
270 ast_ptr<true, Exp_t> condition;
271 ast_sel<true, Block_t, Statement_t> body;
272 AST_MEMBER(While, &condition, &body)
273AST_END(While)
274
275class Body_t;
276
277AST_NODE(Repeat)
278 ast_ptr<true, Body_t> body;
279 ast_ptr<true, Exp_t> condition;
280 AST_MEMBER(Repeat, &body, &condition)
281AST_END(Repeat)
282
283AST_NODE(for_step_value)
284 ast_ptr<true, Exp_t> value;
285 AST_MEMBER(for_step_value, &value)
286AST_END(for_step_value)
287
288AST_NODE(For)
289 ast_ptr<true, Variable_t> varName;
290 ast_ptr<true, Exp_t> startValue;
291 ast_ptr<true, Exp_t> stopValue;
292 ast_ptr<false, for_step_value_t> stepValue;
293 ast_sel<true, Block_t, Statement_t> body;
294 AST_MEMBER(For, &varName, &startValue, &stopValue, &stepValue, &body)
295AST_END(For)
296
297class AssignableNameList_t;
298class star_exp_t;
299
300AST_NODE(ForEach)
301 ast_ptr<true, AssignableNameList_t> nameList;
302 ast_sel<true, star_exp_t, ExpList_t> loopValue;
303 ast_sel<true, Block_t, Statement_t> body;
304 AST_MEMBER(ForEach, &nameList, &loopValue, &body)
305AST_END(ForEach)
306
307AST_NODE(Do)
308 ast_ptr<true, Body_t> body;
309 AST_MEMBER(Do, &body)
310AST_END(Do)
311
312class CompInner_t;
313class Statement_t;
314
315AST_NODE(Comprehension)
316 ast_sel<true, Exp_t, Statement_t> value;
317 ast_ptr<true, CompInner_t> forLoop;
318 AST_MEMBER(Comprehension, &value, &forLoop)
319AST_END(Comprehension)
320
321AST_NODE(comp_value)
322 ast_ptr<true, Exp_t> value;
323 AST_MEMBER(comp_value, &value)
324AST_END(comp_value)
325
326AST_NODE(TblComprehension)
327 ast_ptr<true, Exp_t> key;
328 ast_ptr<false, comp_value_t> value;
329 ast_ptr<true, CompInner_t> forLoop;
330 AST_MEMBER(TblComprehension, &key, &value, &forLoop)
331AST_END(TblComprehension)
332
333AST_NODE(star_exp)
334 ast_ptr<true, Exp_t> value;
335 AST_MEMBER(star_exp, &value)
336AST_END(star_exp)
337
338AST_NODE(CompForEach)
339 ast_ptr<true, AssignableNameList_t> nameList;
340 ast_sel<true, star_exp_t, Exp_t> loopValue;
341 AST_MEMBER(CompForEach, &nameList, &loopValue)
342AST_END(CompForEach)
343
344AST_NODE(CompFor)
345 ast_ptr<true, Variable_t> varName;
346 ast_ptr<true, Exp_t> startValue;
347 ast_ptr<true, Exp_t> stopValue;
348 ast_ptr<false, for_step_value_t> stepValue;
349 AST_MEMBER(CompFor, &varName, &startValue, &stopValue, &stepValue)
350AST_END(CompFor)
351
352AST_NODE(CompInner)
353 ast_ptr<true, Seperator_t> sep;
354 ast_sel_list<true, CompFor_t, CompForEach_t, Exp_t> items;
355 AST_MEMBER(CompInner, &sep, &items)
356AST_END(CompInner)
357
358class TableBlock_t;
359
360AST_NODE(Assign)
361 ast_ptr<true, Seperator_t> sep;
362 ast_sel_list<true, With_t, If_t, Switch_t, TableBlock_t, Exp_t> values;
363 AST_MEMBER(Assign, &sep, &values)
364AST_END(Assign)
365
366AST_LEAF(update_op)
367AST_END(update_op)
368
369AST_NODE(Update)
370 ast_ptr<true, update_op_t> op;
371 ast_ptr<true, Exp_t> value;
372 AST_MEMBER(Update, &op, &value)
373AST_END(Update)
374
375AST_LEAF(BinaryOperator)
376AST_END(BinaryOperator)
377
378AST_LEAF(unary_operator)
379AST_END(unary_operator)
380
381class AssignableChain_t;
382
383AST_NODE(Assignable)
384 ast_sel<true, AssignableChain_t, Variable_t, SelfName_t> item;
385 AST_MEMBER(Assignable, &item)
386AST_END(Assignable)
387
388class unary_exp_t;
389
390AST_NODE(exp_op_value)
391 ast_ptr<true, BinaryOperator_t> op;
392 ast_list<true, unary_exp_t> backcalls;
393 AST_MEMBER(exp_op_value, &op, &backcalls)
394AST_END(exp_op_value)
395
396AST_NODE(Exp)
397 ast_ptr<true, Seperator_t> sep;
398 ast_list<true, unary_exp_t> backcalls;
399 ast_list<false, exp_op_value_t> opValues;
400 AST_MEMBER(Exp, &sep, &backcalls, &opValues)
401AST_END(Exp)
402
403class Parens_t;
404class MacroName_t;
405
406AST_NODE(Callable)
407 ast_sel<true, Variable_t, SelfName_t, VarArg_t, Parens_t, MacroName_t> item;
408 AST_MEMBER(Callable, &item)
409AST_END(Callable)
410
411AST_NODE(variable_pair)
412 ast_ptr<true, Variable_t> name;
413 AST_MEMBER(variable_pair, &name)
414AST_END(variable_pair)
415
416class DoubleString_t;
417class SingleString_t;
418class LuaString_t;
419
420AST_NODE(normal_pair)
421 ast_sel<true, KeyName_t, Exp_t, DoubleString_t, SingleString_t, LuaString_t> key;
422 ast_sel<true, Exp_t, TableBlock_t> value;
423 AST_MEMBER(normal_pair, &key, &value)
424AST_END(normal_pair)
425
426AST_NODE(simple_table)
427 ast_ptr<true, Seperator_t> sep;
428 ast_sel_list<true, variable_pair_t, normal_pair_t> pairs;
429 AST_MEMBER(simple_table, &sep, &pairs)
430AST_END(simple_table)
431
432class String_t;
433class const_value_t;
434class ClassDecl_t;
435class unary_value_t;
436class TableLit_t;
437class FunLit_t;
438
439AST_NODE(SimpleValue)
440 ast_sel<true, const_value_t,
441 If_t, Unless_t, Switch_t, With_t, ClassDecl_t,
442 ForEach_t, For_t, While_t, Do_t,
443 unary_value_t,
444 TblComprehension_t, TableLit_t, Comprehension_t,
445 FunLit_t, Num_t> value;
446 AST_MEMBER(SimpleValue, &value)
447AST_END(SimpleValue)
448
449AST_LEAF(LuaStringOpen)
450AST_END(LuaStringOpen)
451
452AST_LEAF(LuaStringContent)
453AST_END(LuaStringContent)
454
455AST_LEAF(LuaStringClose)
456AST_END(LuaStringClose)
457
458AST_NODE(LuaString)
459 ast_ptr<true, LuaStringOpen_t> open;
460 ast_ptr<true, LuaStringContent_t> content;
461 ast_ptr<true, LuaStringClose_t> close;
462 AST_MEMBER(LuaString, &open, &content, &close)
463AST_END(LuaString)
464
465AST_LEAF(SingleString)
466AST_END(SingleString)
467
468AST_LEAF(double_string_inner)
469AST_END(double_string_inner)
470
471AST_NODE(double_string_content)
472 ast_sel<true, double_string_inner_t, Exp_t> content;
473 AST_MEMBER(double_string_content, &content)
474AST_END(double_string_content)
475
476AST_NODE(DoubleString)
477 ast_ptr<true, Seperator_t> sep;
478 ast_list<false, double_string_content_t> segments;
479 AST_MEMBER(DoubleString, &sep, &segments)
480AST_END(DoubleString)
481
482AST_NODE(String)
483 ast_sel<true, DoubleString_t, SingleString_t, LuaString_t> str;
484 AST_MEMBER(String, &str)
485AST_END(String)
486
487AST_NODE(DotChainItem)
488 ast_ptr<true, Name_t> name;
489 AST_MEMBER(DotChainItem, &name)
490AST_END(DotChainItem)
491
492AST_NODE(ColonChainItem)
493 ast_sel<true, LuaKeyword_t, Name_t> name;
494 bool switchToDot = false;
495 AST_MEMBER(ColonChainItem, &name)
496AST_END(ColonChainItem)
497
498class default_value_t;
499
500AST_NODE(Slice)
501 ast_sel<true, Exp_t, default_value_t> startValue;
502 ast_sel<true, Exp_t, default_value_t> stopValue;
503 ast_sel<true, Exp_t, default_value_t> stepValue;
504 AST_MEMBER(Slice, &startValue, &stopValue, &stepValue)
505AST_END(Slice)
506
507AST_NODE(Parens)
508 ast_ptr<true, Exp_t> expr;
509 AST_MEMBER(Parens, &expr)
510AST_END(Parens)
511
512AST_NODE(Invoke)
513 ast_ptr<true, Seperator_t> sep;
514 ast_sel_list<false, Exp_t, SingleString_t, DoubleString_t, LuaString_t, TableLit_t> args;
515 AST_MEMBER(Invoke, &sep, &args)
516AST_END(Invoke)
517
518AST_LEAF(existential_op)
519AST_END(existential_op)
520
521class InvokeArgs_t;
522
523AST_NODE(ChainValue)
524 ast_ptr<true, Seperator_t> sep;
525 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, existential_op_t> items;
526 AST_MEMBER(ChainValue, &sep, &items)
527AST_END(ChainValue)
528
529AST_NODE(AssignableChain)
530 ast_ptr<true, Seperator_t> sep;
531 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Exp_t, String_t> items;
532 AST_MEMBER(AssignableChain, &sep, &items)
533AST_END(AssignableChain)
534
535AST_NODE(Value)
536 ast_sel<true, SimpleValue_t, simple_table_t, ChainValue_t, String_t> item;
537 AST_MEMBER(Value, &item)
538AST_END(Value)
539
540AST_LEAF(default_value)
541AST_END(default_value)
542
543AST_NODE(TableLit)
544 ast_ptr<true, Seperator_t> sep;
545 ast_sel_list<false, variable_pair_t, normal_pair_t, Exp_t> values;
546 AST_MEMBER(TableLit, &sep, &values)
547AST_END(TableLit)
548
549AST_NODE(TableBlockIndent)
550 ast_ptr<true, Seperator_t> sep;
551 ast_sel_list<false, variable_pair_t, normal_pair_t, TableBlockIndent_t> values;
552 AST_MEMBER(TableBlockIndent, &sep, &values)
553AST_END(TableBlockIndent)
554
555AST_NODE(TableBlock)
556 ast_ptr<true, Seperator_t> sep;
557 ast_sel_list<false, variable_pair_t, normal_pair_t, TableBlockIndent_t, Exp_t, TableBlock_t> values;
558 AST_MEMBER(TableBlock, &sep, &values)
559AST_END(TableBlock)
560
561AST_NODE(class_member_list)
562 ast_ptr<true, Seperator_t> sep;
563 ast_sel_list<true, variable_pair_t, normal_pair_t> values;
564 AST_MEMBER(class_member_list, &sep, &values)
565AST_END(class_member_list)
566
567AST_NODE(ClassBlock)
568 ast_ptr<true, Seperator_t> sep;
569 ast_sel_list<true, class_member_list_t, Statement_t> contents;
570 AST_MEMBER(ClassBlock, &sep, &contents)
571AST_END(ClassBlock)
572
573AST_NODE(ClassDecl)
574 ast_ptr<false, Assignable_t> name;
575 ast_ptr<false, Exp_t> extend;
576 ast_ptr<false, ClassBlock_t> body;
577 AST_MEMBER(ClassDecl, &name, &extend, &body)
578AST_END(ClassDecl)
579
580AST_NODE(global_values)
581 ast_ptr<true, NameList_t> nameList;
582 ast_sel<false, TableBlock_t, ExpListLow_t> valueList;
583 AST_MEMBER(global_values, &nameList, &valueList)
584AST_END(global_values)
585
586AST_LEAF(global_op)
587AST_END(global_op)
588
589AST_NODE(Global)
590 ast_sel<true, ClassDecl_t, global_op_t, global_values_t> item;
591 AST_MEMBER(Global, &item)
592AST_END(Global)
593
594AST_LEAF(export_default)
595AST_END(export_default)
596
597class Macro_t;
598
599AST_NODE(Export)
600 ast_ptr<false, export_default_t> def;
601 ast_sel<true, ExpList_t, Exp_t, Macro_t> target;
602 ast_ptr<false, Assign_t> assign;
603 AST_MEMBER(Export, &def, &target, &assign)
604AST_END(Export)
605
606AST_NODE(FnArgDef)
607 ast_sel<true, Variable_t, SelfName_t> name;
608 ast_ptr<false, Exp_t> defaultValue;
609 AST_MEMBER(FnArgDef, &name, &defaultValue)
610AST_END(FnArgDef)
611
612AST_NODE(FnArgDefList)
613 ast_ptr<true, Seperator_t> sep;
614 ast_list<false, FnArgDef_t> definitions;
615 ast_ptr<false, VarArg_t> varArg;
616 AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg)
617AST_END(FnArgDefList)
618
619AST_NODE(outer_var_shadow)
620 ast_ptr<false, NameList_t> varList;
621 AST_MEMBER(outer_var_shadow, &varList)
622AST_END(outer_var_shadow)
623
624AST_NODE(FnArgsDef)
625 ast_ptr<false, FnArgDefList_t> defList;
626 ast_ptr<false, outer_var_shadow_t> shadowOption;
627 AST_MEMBER(FnArgsDef, &defList, &shadowOption)
628AST_END(FnArgsDef)
629
630AST_LEAF(fn_arrow)
631AST_END(fn_arrow)
632
633AST_NODE(FunLit)
634 ast_ptr<false, FnArgsDef_t> argsDef;
635 ast_ptr<true, fn_arrow_t> arrow;
636 ast_ptr<false, Body_t> body;
637 AST_MEMBER(FunLit, &argsDef, &arrow, &body)
638AST_END(FunLit)
639
640AST_NODE(MacroName)
641 ast_ptr<false, Name_t> name;
642 AST_MEMBER(MacroName, &name)
643AST_END(MacroName)
644
645AST_NODE(MacroLit)
646 ast_ptr<false, FnArgDefList_t> argsDef;
647 ast_ptr<true, Body_t> body;
648 AST_MEMBER(MacroLit, &argsDef, &body)
649AST_END(MacroLit)
650
651AST_NODE(Macro)
652 ast_ptr<true, Name_t> name;
653 ast_ptr<true, MacroLit_t> macroLit;
654 AST_MEMBER(Macro, &name, &macroLit)
655AST_END(Macro)
656
657AST_NODE(NameOrDestructure)
658 ast_sel<true, Variable_t, TableLit_t> item;
659 AST_MEMBER(NameOrDestructure, &item)
660AST_END(NameOrDestructure)
661
662AST_NODE(AssignableNameList)
663 ast_ptr<true, Seperator_t> sep;
664 ast_list<true, NameOrDestructure_t> items;
665 AST_MEMBER(AssignableNameList, &sep, &items)
666AST_END(AssignableNameList)
667
668AST_NODE(InvokeArgs)
669 ast_ptr<true, Seperator_t> sep;
670 ast_sel_list<true, Exp_t, TableBlock_t> args;
671 AST_MEMBER(InvokeArgs, &sep, &args)
672AST_END(InvokeArgs)
673
674AST_LEAF(const_value)
675AST_END(const_value)
676
677AST_NODE(unary_value)
678 ast_list<true, unary_operator_t> ops;
679 ast_ptr<true, Value_t> value;
680 AST_MEMBER(unary_value, &ops, &value)
681AST_END(unary_value)
682
683AST_NODE(unary_exp)
684 ast_list<false, unary_operator_t> ops;
685 ast_list<true, Value_t> expos;
686 AST_MEMBER(unary_exp, &ops, &expos)
687AST_END(unary_exp)
688
689AST_NODE(ExpListAssign)
690 ast_ptr<true, ExpList_t> expList;
691 ast_sel<false, Update_t, Assign_t> action;
692 AST_MEMBER(ExpListAssign, &expList, &action)
693AST_END(ExpListAssign)
694
695AST_NODE(if_line)
696 ast_ptr<true, Exp_t> condition;
697 ast_ptr<false, Assign_t> assign;
698 AST_MEMBER(if_line, &condition, &assign)
699AST_END(if_line)
700
701AST_NODE(unless_line)
702 ast_ptr<true, Exp_t> condition;
703 AST_MEMBER(unless_line, &condition)
704AST_END(unless_line)
705
706AST_LEAF(BreakLoop)
707AST_END(BreakLoop)
708
709AST_NODE(BackcallBody)
710 ast_ptr<true, Seperator_t> sep;
711 ast_list<true, unary_exp_t> values;
712 AST_MEMBER(BackcallBody, &sep, &values)
713AST_END(BackcallBody)
714
715AST_NODE(statement_appendix)
716 ast_sel<true, if_line_t, unless_line_t, CompInner_t> item;
717 AST_MEMBER(statement_appendix, &item)
718AST_END(statement_appendix)
719
720AST_LEAF(statement_sep)
721AST_END(statement_sep)
722
723AST_NODE(Statement)
724 ast_sel<true, Import_t, While_t, Repeat_t, For_t, ForEach_t,
725 Return_t, Local_t, Global_t, Export_t, Macro_t, BreakLoop_t,
726 Label_t, Goto_t, Backcall_t, LocalAttrib_t, BackcallBody_t, ExpListAssign_t> content;
727 ast_ptr<false, statement_appendix_t> appendix;
728 ast_ptr<false, statement_sep_t> needSep;
729 AST_MEMBER(Statement, &content, &appendix, &needSep)
730AST_END(Statement)
731
732class Block_t;
733
734AST_NODE(Body)
735 ast_sel<true, Block_t, Statement_t> content;
736 AST_MEMBER(Body, &content)
737AST_END(Body)
738
739AST_NODE(Block)
740 ast_ptr<true, Seperator_t> sep;
741 ast_list<false, Statement_t> statements;
742 AST_MEMBER(Block, &sep, &statements)
743AST_END(Block)
744
745AST_NODE(File)
746 ast_ptr<true, Block_t> block;
747 AST_MEMBER(File, &block)
748AST_END(File)
749
750} // namespace parserlib
diff --git a/src/MoonP/moon_compiler.cpp b/src/MoonP/moon_compiler.cpp
deleted file mode 100644
index 24e4a97..0000000
--- a/src/MoonP/moon_compiler.cpp
+++ /dev/null
@@ -1,5622 +0,0 @@
1/* Copyright (c) 2021 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 <memory>
15#include <cassert>
16
17#include "MoonP/moon_parser.h"
18#include "MoonP/moon_compiler.h"
19
20#ifndef MOONP_NO_MACRO
21
22extern "C" {
23#include "lua.h"
24#include "lauxlib.h"
25#include "lualib.h"
26} // extern "C"
27
28// name of table stored in lua registry
29#define MOONP_MODULE "__moon_modules__"
30
31#if LUA_VERSION_NUM > 501
32 #ifndef LUA_COMPAT_5_1
33 #define lua_objlen lua_rawlen
34 #endif // LUA_COMPAT_5_1
35#endif // LUA_VERSION_NUM
36
37#endif // MOONP_NO_MACRO
38
39namespace MoonP {
40using namespace std::string_view_literals;
41using namespace parserlib;
42
43#define BLOCK_START do {
44#define BLOCK_END } while (false);
45#define BREAK_IF(cond) if (cond) break
46
47#define _DEFER(code,line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto){code;})
48#define DEFER(code) _DEFER(code,__LINE__)
49
50typedef std::list<std::string> str_list;
51
52inline std::string s(std::string_view sv) {
53 return std::string(sv);
54}
55
56const std::string_view version = "0.6.3"sv;
57const std::string_view extension = "mp"sv;
58
59class MoonCompilerImpl {
60public:
61#ifndef MOONP_NO_MACRO
62 MoonCompilerImpl(lua_State* sharedState,
63 const std::function<void(void*)>& luaOpen,
64 bool sameModule,
65 std::string_view moduleName = {}):
66 L(sharedState),
67 _luaOpen(luaOpen),
68 _moduleName(moduleName) {
69 BLOCK_START
70 BREAK_IF(!sameModule);
71 BREAK_IF(!L);
72 _sameModule = true;
73 int top = lua_gettop(L);
74 DEFER(lua_settop(L, top));
75 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE
76 lua_rawget(L, LUA_REGISTRYINDEX); // reg[MOONP_MODULE], tb
77 BREAK_IF(lua_istable(L, -1) == 0);
78 int idx = static_cast<int>(lua_objlen(L, -1)); // idx = #tb, tb
79 BREAK_IF(idx == 0);
80 _useModule = true;
81 BLOCK_END
82 }
83
84 ~MoonCompilerImpl() {
85 if (L && _stateOwner) {
86 lua_close(L);
87 L = nullptr;
88 }
89 }
90#endif // MOONP_NO_MACRO
91
92 CompileInfo compile(std::string_view codes, const MoonConfig& config) {
93 _config = config;
94#ifndef MOONP_NO_MACRO
95 if (L) passOptions();
96#endif // MOONP_NO_MACRO
97 _info = _parser.parse<File_t>(codes);
98 std::unique_ptr<GlobalVars> globals;
99 std::unique_ptr<Options> options;
100 if (!config.options.empty()) {
101 options = std::make_unique<Options>(config.options);
102 }
103 DEFER(clear());
104 if (_info.node) {
105 try {
106 str_list out;
107 pushScope();
108 _enableReturn.push(_info.moduleName.empty());
109 _varArgs.push(true);
110 transformBlock(_info.node.to<File_t>()->block, out,
111 config.implicitReturnRoot ? ExpUsage::Return : ExpUsage::Common,
112 nullptr, true);
113 popScope();
114 if (config.lintGlobalVariable) {
115 globals = std::make_unique<GlobalVars>();
116 for (const auto& var : _globals) {
117 int line,col;
118 std::tie(line,col) = var.second;
119 globals->push_back({var.first, line, col});
120 }
121 }
122#ifndef MOONP_NO_MACRO
123 if (L) {
124 int top = lua_gettop(L);
125 DEFER(lua_settop(L, top));
126 if (!options) {
127 options = std::make_unique<Options>();
128 }
129 pushMoonp("options"sv);
130 lua_pushnil(L); // options startKey
131 while (lua_next(L, -2) != 0) { // options key value
132 size_t len = 0;
133 auto pstr = lua_tolstring(L, -2, &len);
134 std::string key{pstr, len};
135 pstr = lua_tolstring(L, -1, &len);
136 std::string value{pstr, len};
137 (*options)[key] = value;
138 lua_pop(L, 1); // options key
139 }
140 }
141#endif // MOONP_NO_MACRO
142 return {std::move(out.back()), Empty, std::move(globals), std::move(options)};
143 } catch (const std::logic_error& error) {
144 return {Empty, error.what(), std::move(globals), std::move(options)};
145 }
146 } else {
147 return {Empty, std::move(_info.error), std::move(globals), std::move(options)};
148 }
149 }
150
151 void clear() {
152 _indentOffset = 0;
153 _scopes.clear();
154 _codeCache.clear();
155 _buf.str("");
156 _buf.clear();
157 _joinBuf.str("");
158 _joinBuf.clear();
159 _globals.clear();
160 _info = {};
161 _varArgs = {};
162 _withVars = {};
163 _continueVars = {};
164 _enableReturn = {};
165#ifndef MOONP_NO_MACRO
166 if (_useModule) {
167 _useModule = false;
168 if (!_sameModule) {
169 int top = lua_gettop(L);
170 DEFER(lua_settop(L, top));
171 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE
172 lua_rawget(L, LUA_REGISTRYINDEX); // reg[MOONP_MODULE], tb
173 int idx = static_cast<int>(lua_objlen(L, -1));
174 lua_pushnil(L); // tb nil
175 lua_rawseti(L, -2, idx); // tb[idx] = nil, tb
176 }
177 }
178#endif // MOONP_NO_MACRO
179 }
180private:
181#ifndef MOONP_NO_MACRO
182 bool _stateOwner = false;
183 bool _useModule = false;
184 bool _sameModule = false;
185 lua_State* L = nullptr;
186 std::function<void(void*)> _luaOpen;
187#endif // MOONP_NO_MACRO
188 MoonConfig _config;
189 MoonParser _parser;
190 ParseInfo _info;
191 int _indentOffset = 0;
192 std::stack<bool> _varArgs;
193 std::stack<bool> _enableReturn;
194 std::stack<std::string> _withVars;
195 std::stack<std::string> _continueVars;
196 std::list<std::unique_ptr<input>> _codeCache;
197 std::unordered_map<std::string,std::pair<int,int>> _globals;
198 std::ostringstream _buf;
199 std::ostringstream _joinBuf;
200 const std::string _newLine = "\n";
201 std::string _moduleName;
202
203 enum class LocalMode {
204 None = 0,
205 Capital = 1,
206 Any = 2
207 };
208 enum class GlobalMode {
209 None = 0,
210 Capital = 1,
211 Any = 2
212 };
213 struct Scope {
214 GlobalMode mode = GlobalMode::None;
215 std::unique_ptr<std::unordered_set<std::string>> vars;
216 std::unique_ptr<std::unordered_set<std::string>> allows;
217 std::unique_ptr<std::unordered_set<std::string>> globals;
218 };
219 std::list<Scope> _scopes;
220 static const std::string Empty;
221
222 enum class MemType {
223 Builtin,
224 Common,
225 Property
226 };
227
228 struct ClassMember {
229 std::string item;
230 MemType type;
231 ast_node* node;
232 };
233
234 struct DestructItem {
235 bool isVariable = false;
236 std::string name;
237 std::string structure;
238 };
239
240 struct Destructure {
241 std::string value;
242 std::list<DestructItem> items;
243 };
244
245 enum class ExpUsage {
246 Return,
247 Assignment,
248 Common,
249 Closure
250 };
251
252 void pushScope() {
253 _scopes.emplace_back();
254 _scopes.back().vars = std::make_unique<std::unordered_set<std::string>>();
255 }
256
257 void popScope() {
258 _scopes.pop_back();
259 }
260
261 bool isDefined(const std::string& name) const {
262 bool isDefined = false;
263 int mode = int(std::isupper(name[0]) ? GlobalMode::Capital : GlobalMode::Any);
264 const auto& current = _scopes.back();
265 if (int(current.mode) >= mode) {
266 if (current.globals) {
267 if (current.globals->find(name) != current.globals->end()) {
268 isDefined = true;
269 current.vars->insert(name);
270 }
271 } else {
272 isDefined = true;
273 current.vars->insert(name);
274 }
275 }
276 decltype(_scopes.back().allows.get()) allows = nullptr;
277 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
278 if (it->allows) allows = it->allows.get();
279 }
280 bool checkShadowScopeOnly = false;
281 if (allows) {
282 checkShadowScopeOnly = allows->find(name) == allows->end();
283 }
284 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
285 auto vars = it->vars.get();
286 if (vars->find(name) != vars->end()) {
287 isDefined = true;
288 break;
289 }
290 if (checkShadowScopeOnly && it->allows) break;
291 }
292 return isDefined;
293 }
294
295 bool isSolidDefined(const std::string& name) const {
296 bool isDefined = false;
297 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
298 auto vars = it->vars.get();
299 if (vars->find(name) != vars->end()) {
300 isDefined = true;
301 break;
302 }
303 }
304 return isDefined;
305 }
306
307 void markVarShadowed() {
308 auto& scope = _scopes.back();
309 scope.allows = std::make_unique<std::unordered_set<std::string>>();
310 }
311
312 void markVarGlobal(GlobalMode mode, bool specified) {
313 auto& scope = _scopes.back();
314 scope.mode = mode;
315 if (specified && !scope.globals) {
316 scope.globals = std::make_unique<std::unordered_set<std::string>>();
317 }
318 }
319
320 void addGlobalVar(const std::string& name) {
321 auto& scope = _scopes.back();
322 scope.globals->insert(name);
323 }
324
325 void addToAllowList(const std::string& name) {
326 auto& scope = _scopes.back();
327 scope.allows->insert(name);
328 }
329
330 void forceAddToScope(const std::string& name) {
331 auto& scope = _scopes.back();
332 scope.vars->insert(name);
333 }
334
335 Scope& currentScope() {
336 return _scopes.back();
337 }
338
339 bool addToScope(const std::string& name) {
340 bool defined = isDefined(name);
341 if (!defined) {
342 auto& scope = currentScope();
343 scope.vars->insert(name);
344 }
345 return !defined;
346 }
347
348 std::string getUnusedName(std::string_view name) const {
349 int index = 0;
350 std::string newName;
351 do {
352 newName = s(name) + std::to_string(index);
353 index++;
354 } while (isSolidDefined(newName));
355 return newName;
356 }
357
358 const std::string nll(ast_node* node) const {
359 if (_config.reserveLineNumber) {
360 return s(" -- "sv) + std::to_string(node->m_begin.m_line + _config.lineOffset) + _newLine;
361 } else {
362 return _newLine;
363 }
364 }
365
366 const std::string nlr(ast_node* node) const {
367 if (_config.reserveLineNumber) {
368 return s(" -- "sv) + std::to_string(node->m_end.m_line + _config.lineOffset) + _newLine;
369 } else {
370 return _newLine;
371 }
372 }
373
374 void incIndentOffset() {
375 _indentOffset++;
376 }
377
378 void decIndentOffset() {
379 _indentOffset--;
380 }
381
382 std::string indent() const {
383 if (_config.useSpaceOverTab) {
384 return std::string((_scopes.size() - 1 + _indentOffset) * 2, ' ');
385 } else {
386 return std::string(_scopes.size() - 1 + _indentOffset, '\t');
387 }
388 }
389
390 std::string indent(int offset) const {
391 if (_config.useSpaceOverTab) {
392 return std::string((_scopes.size() - 1 + _indentOffset + offset) * 2, ' ');
393 } else {
394 return std::string(_scopes.size() - 1 + _indentOffset + offset, '\t');
395 }
396 }
397
398 std::string clearBuf() {
399 std::string str = _buf.str();
400 _buf.str("");
401 _buf.clear();
402 return str;
403 }
404
405 std::string join(const str_list& items) {
406 if (items.empty()) return Empty;
407 else if (items.size() == 1) return items.front();
408 for (const auto& item : items) {
409 _joinBuf << item;
410 }
411 auto result = _joinBuf.str();
412 _joinBuf.str("");
413 _joinBuf.clear();
414 return result;
415 }
416
417 std::string join(const str_list& items, std::string_view sep) {
418 if (items.empty()) return Empty;
419 else if (items.size() == 1) return items.front();
420 std::string sepStr = s(sep);
421 auto begin = ++items.begin();
422 _joinBuf << items.front();
423 for (auto it = begin; it != items.end(); ++it) {
424 _joinBuf << sepStr << *it;
425 }
426 auto result = _joinBuf.str();
427 _joinBuf.str("");
428 _joinBuf.clear();
429 return result;
430 }
431
432 unary_exp_t* singleUnaryExpFrom(ast_node* item) const {
433 Exp_t* exp = nullptr;
434 switch (item->getId()) {
435 case id<Exp_t>():
436 exp = static_cast<Exp_t*>(item);
437 break;
438 case id<ExpList_t>(): {
439 auto expList = static_cast<ExpList_t*>(item);
440 if (expList->exprs.size() == 1) {
441 exp = static_cast<Exp_t*>(expList->exprs.front());
442 }
443 break;
444 }
445 case id<ExpListLow_t>(): {
446 auto expList = static_cast<ExpListLow_t*>(item);
447 if (expList->exprs.size() == 1) {
448 exp = static_cast<Exp_t*>(expList->exprs.front());
449 }
450 break;
451 }
452 case id<unary_exp_t>(): {
453 auto unary = static_cast<unary_exp_t*>(item);
454 if (unary->expos.size() == 1) {
455 return unary;
456 }
457 return nullptr;
458 }
459 default: break;
460 }
461 if (!exp) return nullptr;
462 BLOCK_START
463 BREAK_IF(!exp->opValues.empty());
464 BREAK_IF(exp->backcalls.size() != 1);
465 auto unary = static_cast<unary_exp_t*>(exp->backcalls.back());
466 BREAK_IF(unary->expos.size() != 1);
467 return unary;
468 BLOCK_END
469 return nullptr;
470 }
471
472 Value_t* singleValueFrom(ast_node* item) const {
473 if (auto unary = singleUnaryExpFrom(item)) {
474 if (unary->ops.empty()) {
475 return static_cast<Value_t*>(unary->expos.back());
476 }
477 }
478 return nullptr;
479 }
480
481 ast_ptr<false, Exp_t> newExp(Value_t* value, ast_node* x) {
482 auto unary = x->new_ptr<unary_exp_t>();
483 unary->expos.push_back(value);
484 auto exp = x->new_ptr<Exp_t>();
485 exp->backcalls.push_back(unary);
486 return exp;
487 }
488
489 ast_ptr<false, Exp_t> newExp(Value_t* left, BinaryOperator_t* op, Value_t* right, ast_node* x) {
490 auto lunary = x->new_ptr<unary_exp_t>();
491 lunary->expos.push_back(left);
492 auto opValue = x->new_ptr<exp_op_value_t>();
493 {
494 auto runary = x->new_ptr<unary_exp_t>();
495 runary->expos.push_back(right);
496 opValue->op.set(op);
497 opValue->backcalls.push_back(runary);
498 }
499 auto exp = x->new_ptr<Exp_t>();
500 exp->backcalls.push_back(lunary);
501 exp->opValues.push_back(opValue);
502 return exp;
503 }
504
505 ast_ptr<false, Exp_t> newExp(unary_exp_t* unary, ast_node* x) {
506 auto exp = x->new_ptr<Exp_t>();
507 exp->backcalls.push_back(unary);
508 return exp;
509 }
510
511 SimpleValue_t* simpleSingleValueFrom(ast_node* expList) const {
512 auto value = singleValueFrom(expList);
513 if (value && value->item.is<SimpleValue_t>()) {
514 return static_cast<SimpleValue_t*>(value->item.get());
515 }
516 return nullptr;
517 }
518
519 Statement_t* lastStatementFrom(ast_node* body) const {
520 switch (body->getId()) {
521 case id<Block_t>():
522 return lastStatementFrom(static_cast<Block_t*>(body));
523 case id<Statement_t>(): {
524 return static_cast<Statement_t*>(body);
525 }
526 default: assert(false); break;
527 }
528 return nullptr;
529 }
530
531 Statement_t* lastStatementFrom(const node_container& stmts) const {
532 if (!stmts.empty()) {
533 auto it = stmts.end(); --it;
534 while (!static_cast<Statement_t*>(*it)->content && it != stmts.begin()) {
535 --it;
536 }
537 return static_cast<Statement_t*>(*it);
538 }
539 return nullptr;
540 }
541
542 Statement_t* lastStatementFrom(Body_t* body) const {
543 if (auto stmt = body->content.as<Statement_t>()) {
544 return stmt;
545 } else {
546 const auto& stmts = body->content.to<Block_t>()->statements.objects();
547 return lastStatementFrom(stmts);
548 }
549 }
550
551 Statement_t* lastStatementFrom(Block_t* block) const {
552 const auto& stmts = block->statements.objects();
553 return lastStatementFrom(stmts);
554 }
555
556 Exp_t* lastExpFromAssign(ast_node* action) {
557 switch (action->getId()) {
558 case id<Update_t>(): {
559 auto update = static_cast<Update_t*>(action);
560 return update->value;
561 }
562 case id<Assign_t>(): {
563 auto assign = static_cast<Assign_t*>(action);
564 return ast_cast<Exp_t>(assign->values.back());
565 }
566 }
567 return nullptr;
568 }
569
570 Exp_t* lastExpFromStatement(Statement_t* stmt) {
571 if (!stmt->content) return nullptr;
572 switch (stmt->content->getId()) {
573 case id<ExpListAssign_t>(): {
574 auto expListAssign = static_cast<ExpListAssign_t*>(stmt->content.get());
575 if (auto action = expListAssign->action.get()) {
576 return lastExpFromAssign(action);
577 } else {
578 return static_cast<Exp_t*>(expListAssign->expList->exprs.back());
579 }
580 }
581 case id<Export_t>(): {
582 auto exportNode = static_cast<Export_t*>(stmt->content.get());
583 if (auto action = exportNode->assign.get()) {
584 return lastExpFromAssign(action);
585 } else {
586 switch (exportNode->target->getId()) {
587 case id<Exp_t>(): return exportNode->target.to<Exp_t>();
588 case id<ExpList_t>(): return static_cast<Exp_t*>(exportNode->target.to<ExpList_t>()->exprs.back());
589 }
590 }
591 }
592 case id<Local_t>(): {
593 if (auto localValues = static_cast<Local_t*>(stmt->content.get())->item.as<local_values_t>()) {
594 if (auto expList = localValues->valueList.as<ExpListLow_t>()) {
595 return static_cast<Exp_t*>(expList->exprs.back());
596 }
597 }
598 }
599 case id<Global_t>(): {
600 if (auto globalValues = static_cast<Global_t*>(stmt->content.get())->item.as<global_values_t>()) {
601 if (auto expList = globalValues->valueList.as<ExpListLow_t>()) {
602 return static_cast<Exp_t*>(expList->exprs.back());
603 }
604 }
605 }
606 }
607 return nullptr;
608 }
609
610 template <class T>
611 ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) {
612 auto res = _parser.parse<T>(s(codes));
613 int line = parent->m_begin.m_line;
614 int col = parent->m_begin.m_line;
615 res.node->traverse([&](ast_node* node) {
616 node->m_begin.m_line = line;
617 node->m_end.m_line = line;
618 node->m_begin.m_col = col;
619 node->m_end.m_col = col;
620 return traversal::Continue;
621 });
622 _codeCache.push_back(std::move(res.codes));
623 return ast_ptr<false, T>(res.node.template to<T>());
624 }
625
626 bool isChainValueCall(ChainValue_t* chainValue) const {
627 return ast_is<InvokeArgs_t, Invoke_t>(chainValue->items.back());
628 }
629
630 enum class ChainType {
631 Common,
632 EndWithColon,
633 EndWithEOP,
634 HasEOP,
635 HasKeyword,
636 Macro
637 };
638
639 ChainType specialChainValue(ChainValue_t* chainValue) const {
640 if (isMacroChain(chainValue)) {
641 return ChainType::Macro;
642 }
643 if (ast_is<ColonChainItem_t>(chainValue->items.back())) {
644 return ChainType::EndWithColon;
645 }
646 if (ast_is<existential_op_t>(chainValue->items.back())) {
647 return ChainType::EndWithEOP;
648 }
649 ChainType type = ChainType::Common;
650 for (auto item : chainValue->items.objects()) {
651 if (auto colonChain = ast_cast<ColonChainItem_t>(item)) {
652 if (ast_is<LuaKeyword_t>(colonChain->name)) {
653 type = ChainType::HasKeyword;
654 }
655 } else if (ast_is<existential_op_t>(item)) {
656 return ChainType::HasEOP;
657 }
658 }
659 return type;
660 }
661
662 std::string singleVariableFrom(ChainValue_t* chainValue) {
663 BLOCK_START
664 BREAK_IF(!chainValue);
665 BREAK_IF(chainValue->items.size() != 1);
666 auto callable = ast_cast<Callable_t>(chainValue->items.front());
667 BREAK_IF(!callable);
668 ast_node* var = callable->item.as<Variable_t>();
669 if (!var) {
670 if (auto self = callable->item.as<SelfName_t>()) {
671 var = self->name.as<self_t>();
672 }
673 }
674 BREAK_IF(!var);
675 str_list tmp;
676 transformCallable(callable, tmp);
677 return tmp.back();
678 BLOCK_END
679 return Empty;
680 }
681
682 std::string singleVariableFrom(ast_node* expList) {
683 if (!ast_is<Exp_t, ExpList_t>(expList)) return Empty;
684 BLOCK_START
685 auto value = singleValueFrom(expList);
686 BREAK_IF(!value);
687 auto chainValue = value->item.as<ChainValue_t>();
688 BREAK_IF(!chainValue);
689 BREAK_IF(chainValue->items.size() != 1);
690 auto callable = ast_cast<Callable_t>(chainValue->items.front());
691 BREAK_IF(!callable || !(callable->item.is<Variable_t>() || callable->getByPath<SelfName_t,self_t>()));
692 str_list tmp;
693 transformCallable(callable, tmp);
694 return tmp.back();
695 BLOCK_END
696 return Empty;
697 }
698
699 Variable_t* variableFrom(Exp_t* exp) {
700 BLOCK_START
701 auto value = singleValueFrom(exp);
702 BREAK_IF(!value);
703 auto chainValue = value->item.as<ChainValue_t>();
704 BREAK_IF(!chainValue);
705 BREAK_IF(chainValue->items.size() != 1);
706 auto callable = ast_cast<Callable_t>(chainValue->items.front());
707 BREAK_IF(!callable);
708 return callable->item.as<Variable_t>();
709 BLOCK_END
710 return nullptr;
711 }
712
713 bool isAssignable(const node_container& chainItems) const {
714 if (chainItems.size() == 1) {
715 auto firstItem = chainItems.back();
716 if (auto callable = ast_cast<Callable_t>(firstItem)) {
717 switch (callable->item->getId()) {
718 case id<Variable_t>():
719 case id<SelfName_t>():
720 return true;
721 }
722 } else if (firstItem->getId() == id<DotChainItem_t>()) {
723 return true;
724 }
725 } else {
726 auto lastItem = chainItems.back();
727 switch (lastItem->getId()) {
728 case id<DotChainItem_t>():
729 case id<Exp_t>():
730 return true;
731 }
732 }
733 return false;
734 }
735
736 bool isAssignable(Exp_t* exp) const {
737 if (auto value = singleValueFrom(exp)) {
738 auto item = value->item.get();
739 switch (item->getId()) {
740 case id<simple_table_t>():
741 return true;
742 case id<SimpleValue_t>(): {
743 auto simpleValue = static_cast<SimpleValue_t*>(item);
744 if (simpleValue->value.is<TableLit_t>()) {
745 return true;
746 }
747 return false;
748 }
749 case id<ChainValue_t>(): {
750 auto chainValue = static_cast<ChainValue_t*>(item);
751 return isAssignable(chainValue->items.objects());
752 }
753 }
754 }
755 return false;
756 }
757
758 bool isAssignable(Assignable_t* assignable) const {
759 if (auto assignableChain = ast_cast<AssignableChain_t>(assignable->item)) {
760 return isAssignable(assignableChain->items.objects());
761 }
762 return true;
763 }
764
765 void checkAssignable(ExpList_t* expList) const {
766 for (auto exp_ : expList->exprs.objects()) {
767 Exp_t* exp = static_cast<Exp_t*>(exp_);
768 if (!isAssignable(exp)) {
769 throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, exp));
770 }
771 }
772 }
773
774 bool isPureBackcall(Exp_t* exp) const {
775 return exp->opValues.empty() && exp->backcalls.size() > 1;
776 }
777
778 bool isMacroChain(ChainValue_t* chainValue) const {
779 const auto& chainList = chainValue->items.objects();
780 BLOCK_START
781 auto callable = ast_cast<Callable_t>(chainList.front());
782 BREAK_IF(!callable);
783 BREAK_IF(!callable->item.is<MacroName_t>());
784 if (chainList.size() == 1 ||
785 !ast_is<Invoke_t,InvokeArgs_t>(*(++chainList.begin()))) {
786 throw std::logic_error(_info.errorMessage("macro expression must be followed by arguments list"sv, callable));
787 }
788 return true;
789 BLOCK_END
790 return false;
791 }
792
793 void transformStatement(Statement_t* statement, str_list& out) {
794 auto x = statement;
795 if (statement->appendix) {
796 if (auto assignment = assignmentFrom(statement)) {
797 auto preDefine = getPredefine(assignment);
798 if (!preDefine.empty()) out.push_back(preDefine + nll(statement));
799 } else if (auto local = statement->content.as<Local_t>()) {
800 if (!local->defined) {
801 local->defined = true;
802 transformLocalDef(local, out);
803 }
804 }
805 auto appendix = statement->appendix.get();
806 switch (appendix->item->getId()) {
807 case id<if_line_t>(): {
808 auto if_line = appendix->item.to<if_line_t>();
809 auto ifNode = x->new_ptr<If_t>();
810
811 auto ifCond = x->new_ptr<IfCond_t>();
812 ifCond->condition.set(if_line->condition);
813 ifCond->assign.set(if_line->assign);
814 ifNode->nodes.push_back(ifCond);
815
816 auto stmt = x->new_ptr<Statement_t>();
817 stmt->content.set(statement->content);
818 ifNode->nodes.push_back(stmt);
819
820 statement->appendix.set(nullptr);
821 auto simpleValue = x->new_ptr<SimpleValue_t>();
822 simpleValue->value.set(ifNode);
823 auto value = x->new_ptr<Value_t>();
824 value->item.set(simpleValue);
825 auto exp = newExp(value, x);
826 auto expList = x->new_ptr<ExpList_t>();
827 expList->exprs.push_back(exp);
828 auto expListAssign = x->new_ptr<ExpListAssign_t>();
829 expListAssign->expList.set(expList);
830 statement->content.set(expListAssign);
831 break;
832 }
833 case id<unless_line_t>(): {
834 auto unless_line = appendix->item.to<unless_line_t>();
835 auto unless = x->new_ptr<Unless_t>();
836
837 auto ifCond = x->new_ptr<IfCond_t>();
838 ifCond->condition.set(unless_line->condition);
839 unless->nodes.push_back(ifCond);
840
841 auto stmt = x->new_ptr<Statement_t>();
842 stmt->content.set(statement->content);
843 unless->nodes.push_back(stmt);
844
845 statement->appendix.set(nullptr);
846 auto simpleValue = x->new_ptr<SimpleValue_t>();
847 simpleValue->value.set(unless);
848 auto value = x->new_ptr<Value_t>();
849 value->item.set(simpleValue);
850 auto exp = newExp(value, x);
851 auto exprList = x->new_ptr<ExpList_t>();
852 exprList->exprs.push_back(exp);
853 auto expListAssign = x->new_ptr<ExpListAssign_t>();
854 expListAssign->expList.set(exprList);
855 statement->content.set(expListAssign);
856 break;
857 }
858 case id<CompInner_t>(): {
859 auto compInner = appendix->item.to<CompInner_t>();
860 auto comp = x->new_ptr<Comprehension_t>();
861 comp->forLoop.set(compInner);
862 auto stmt = x->new_ptr<Statement_t>();
863 stmt->content.set(statement->content);
864 comp->value.set(stmt);
865 auto simpleValue = x->new_ptr<SimpleValue_t>();
866 simpleValue->value.set(comp);
867 auto value = x->new_ptr<Value_t>();
868 value->item.set(simpleValue);
869 auto exp = newExp(value, x);
870 auto expList = x->new_ptr<ExpList_t>();
871 expList->exprs.push_back(exp);
872 auto expListAssign = x->new_ptr<ExpListAssign_t>();
873 expListAssign->expList.set(expList);
874 statement->content.set(expListAssign);
875 statement->appendix.set(nullptr);
876 break;
877 }
878 default: assert(false); break;
879 }
880 }
881 auto content = statement->content.get();
882 if (!content) {
883 out.push_back(Empty);
884 return;
885 }
886 switch (content->getId()) {
887 case id<Import_t>(): transformImport(static_cast<Import_t*>(content), out); break;
888 case id<While_t>(): transformWhile(static_cast<While_t*>(content), out); break;
889 case id<Repeat_t>(): transformRepeat(static_cast<Repeat_t*>(content), out); break;
890 case id<For_t>(): transformFor(static_cast<For_t*>(content), out); break;
891 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(content), out); break;
892 case id<Return_t>(): transformReturn(static_cast<Return_t*>(content), out); break;
893 case id<Local_t>(): transformLocal(static_cast<Local_t*>(content), out); break;
894 case id<Global_t>(): transformGlobal(static_cast<Global_t*>(content), out); break;
895 case id<Export_t>(): transformExport(static_cast<Export_t*>(content), out); break;
896 case id<Macro_t>(): transformMacro(static_cast<Macro_t*>(content), out, false); break;
897 case id<BreakLoop_t>(): transformBreakLoop(static_cast<BreakLoop_t*>(content), out); break;
898 case id<Label_t>(): transformLabel(static_cast<Label_t*>(content), out); break;
899 case id<Goto_t>(): transformGoto(static_cast<Goto_t*>(content), out); break;
900 case id<LocalAttrib_t>(): transformLocalAttrib(static_cast<LocalAttrib_t*>(content), out); break;
901 case id<BackcallBody_t>(): throw std::logic_error(_info.errorMessage("backcall chain must be following a value"sv, x)); break;
902 case id<ExpListAssign_t>(): {
903 auto expListAssign = static_cast<ExpListAssign_t*>(content);
904 if (expListAssign->action) {
905 transformAssignment(expListAssign, out);
906 } else {
907 auto expList = expListAssign->expList.get();
908 if (expList->exprs.objects().empty()) {
909 out.push_back(Empty);
910 break;
911 }
912 if (auto singleValue = singleValueFrom(expList)) {
913 if (auto simpleValue = singleValue->item.as<SimpleValue_t>()) {
914 auto value = simpleValue->value.get();
915 bool specialSingleValue = true;
916 switch (value->getId()) {
917 case id<If_t>(): transformIf(static_cast<If_t*>(value), out, ExpUsage::Common); break;
918 case id<ClassDecl_t>(): transformClassDecl(static_cast<ClassDecl_t*>(value), out, ExpUsage::Common); break;
919 case id<Unless_t>(): transformUnless(static_cast<Unless_t*>(value), out, ExpUsage::Common); break;
920 case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Common); break;
921 case id<With_t>(): transformWith(static_cast<With_t*>(value), out); break;
922 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break;
923 case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break;
924 case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break;
925 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break;
926 case id<Comprehension_t>(): transformCompCommon(static_cast<Comprehension_t*>(value), out); break;
927 default: specialSingleValue = false; break;
928 }
929 if (specialSingleValue) {
930 break;
931 }
932 }
933 if (auto chainValue = singleValue->item.as<ChainValue_t>()) {
934 if (isChainValueCall(chainValue)) {
935 transformChainValue(chainValue, out, ExpUsage::Common);
936 break;
937 }
938 }
939 } else if (expList->exprs.size() == 1){
940 auto exp = static_cast<Exp_t*>(expList->exprs.back());
941 if (isPureBackcall(exp)) {
942 transformExp(exp, out, ExpUsage::Common);
943 break;
944 }
945 }
946 throw std::logic_error(_info.errorMessage("expression list is not supported here"sv, expList));
947 }
948 break;
949 }
950 default: assert(false); break;
951 }
952 if (statement->needSep && !out.back().empty()) {
953 auto index = std::string::npos;
954 if (_config.reserveLineNumber) {
955 index = out.back().rfind(" -- "sv);
956 } else {
957 index = out.back().find_last_not_of('\n');
958 if (index != std::string::npos) index++;
959 }
960 if (index != std::string::npos) {
961 auto ending = out.back().substr(0, index);
962 auto ind = ending.find_last_of(" \t\n"sv);
963 if (ind != std::string::npos) {
964 ending = ending.substr(ind + 1);
965 }
966 if (Keywords.find(ending) == Keywords.end()) {
967 out.back().insert(index, ";"sv);
968 }
969 }
970 }
971 }
972
973 str_list getAssignVars(ExpListAssign_t* assignment) {
974 str_list vars;
975 if (!assignment->action.is<Assign_t>()) return vars;
976 for (auto exp : assignment->expList->exprs.objects()) {
977 auto var = singleVariableFrom(exp);
978 vars.push_back(var.empty() ? Empty : var);
979 }
980 return vars;
981 }
982
983 str_list getAssignVars(With_t* with) {
984 str_list vars;
985 for (auto exp : with->valueList->exprs.objects()) {
986 auto var = singleVariableFrom(exp);
987 vars.push_back(var.empty() ? Empty : var);
988 }
989 return vars;
990 }
991
992 str_list getAssignDefs(ExpList_t* expList) {
993 str_list preDefs;
994 for (auto exp_ : expList->exprs.objects()) {
995 auto exp = static_cast<Exp_t*>(exp_);
996 if (auto value = singleValueFrom(exp)) {
997 if (auto chain = value->item.as<ChainValue_t>()) {
998 BLOCK_START
999 BREAK_IF(chain->items.size() != 1);
1000 auto callable = ast_cast<Callable_t>(chain->items.front());
1001 BREAK_IF(!callable);
1002 std::string name;
1003 if (auto var = callable->item.as<Variable_t>()) {
1004 name = _parser.toString(var);
1005 } else if (auto self = callable->item.as<SelfName_t>()) {
1006 if (self->name.is<self_t>()) name = "self"sv;
1007 }
1008 BREAK_IF(name.empty());
1009 if (!isDefined(name)) {
1010 preDefs.push_back(name);
1011 }
1012 BLOCK_END
1013 }
1014 } else {
1015 throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, exp));
1016 }
1017 }
1018 return preDefs;
1019 }
1020
1021 str_list transformAssignDefs(ExpList_t* expList, bool markDefined = true) {
1022 str_list defs;
1023 for (auto exp_ : expList->exprs.objects()) {
1024 auto exp = static_cast<Exp_t*>(exp_);
1025 if (auto value = singleValueFrom(exp)) {
1026 if (auto chain = value->item.as<ChainValue_t>()) {
1027 BLOCK_START
1028 BREAK_IF(chain->items.size() != 1);
1029 auto callable = ast_cast<Callable_t>(chain->items.front());
1030 BREAK_IF(!callable);
1031 std::string name;
1032 if (auto var = callable->item.as<Variable_t>()) {
1033 name = _parser.toString(var);
1034 } else if (auto self = callable->item.as<SelfName_t>()) {
1035 if (self->name.is<self_t>()) name = "self"sv;
1036 }
1037 BREAK_IF(name.empty());
1038 if (!markDefined || addToScope(name)) {
1039 defs.push_back(name);
1040 }
1041 BLOCK_END
1042 }
1043 } else {
1044 throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, exp));
1045 }
1046 }
1047 return defs;
1048 }
1049
1050 std::string getPredefine(const str_list& defs) {
1051 if (defs.empty()) return Empty;
1052 return indent() + s("local "sv) + join(defs, ", "sv);
1053 }
1054
1055 std::string getDestrucureDefine(ExpListAssign_t* assignment) {
1056 auto info = extractDestructureInfo(assignment, true);
1057 if (!info.first.empty()) {
1058 for (const auto& destruct : info.first) {
1059 str_list defs;
1060 for (const auto& item : destruct.items) {
1061 if (item.isVariable && addToScope(item.name)) {
1062 defs.push_back(item.name);
1063 }
1064 }
1065 if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv);
1066 }
1067 }
1068 return clearBuf();
1069 }
1070
1071 std::string getPredefine(ExpListAssign_t* assignment) {
1072 auto preDefine = getDestrucureDefine(assignment);
1073 if (preDefine.empty()) {
1074 preDefine = getPredefine(transformAssignDefs(assignment->expList));
1075 }
1076 return preDefine;
1077 }
1078
1079 ExpList_t* expListFrom(Statement_t* statement) {
1080 if (auto expListAssign = statement->content.as<ExpListAssign_t>()) {
1081 if (!expListAssign->action) {
1082 return expListAssign->expList.get();
1083 }
1084 }
1085 return nullptr;
1086 }
1087
1088 ExpListAssign_t* assignmentFrom(Statement_t* statement) {
1089 if (auto expListAssign = statement->content.as<ExpListAssign_t>()) {
1090 if (expListAssign->action) {
1091 return expListAssign;
1092 }
1093 }
1094 return nullptr;
1095 }
1096
1097 void transformAssignment(ExpListAssign_t* assignment, str_list& out) {
1098 checkAssignable(assignment->expList);
1099 BLOCK_START
1100 auto assign = ast_cast<Assign_t>(assignment->action);
1101 BREAK_IF(!assign);
1102 BREAK_IF(assign->values.objects().size() != 1);
1103 auto value = assign->values.objects().back();
1104 if (ast_is<Exp_t>(value)) {
1105 if (auto val = simpleSingleValueFrom(value)) {
1106 value = val->value.get();
1107 }
1108 }
1109 switch (value->getId()) {
1110 case id<If_t>():
1111 case id<Unless_t>(): {
1112 auto expList = assignment->expList.get();
1113 str_list temp;
1114 auto defs = transformAssignDefs(expList);
1115 if (!defs.empty()) temp.push_back(getPredefine(defs) + nll(expList));
1116 switch (value->getId()) {
1117 case id<If_t>(): transformIf(static_cast<If_t*>(value), temp, ExpUsage::Assignment, expList); break;
1118 case id<Unless_t>(): transformUnless(static_cast<Unless_t*>(value), temp, ExpUsage::Assignment, expList); break;
1119 }
1120 out.push_back(join(temp));
1121 return;
1122 }
1123 case id<Switch_t>(): {
1124 auto switchNode = static_cast<Switch_t*>(value);
1125 auto assignList = assignment->expList.get();
1126 std::string preDefine = getPredefine(assignment);
1127 transformSwitch(switchNode, out, ExpUsage::Assignment, assignList);
1128 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1129 return;
1130 }
1131 case id<With_t>(): {
1132 auto withNode = static_cast<With_t*>(value);
1133 auto expList = assignment->expList.get();
1134 std::string preDefine = getPredefine(assignment);
1135 transformWith(withNode, out, expList);
1136 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1137 return;
1138 }
1139 case id<Do_t>(): {
1140 auto expList = assignment->expList.get();
1141 auto doNode = static_cast<Do_t*>(value);
1142 std::string preDefine = getPredefine(assignment);
1143 transformDo(doNode, out, ExpUsage::Assignment, expList);
1144 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1145 return;
1146 }
1147 case id<Comprehension_t>(): {
1148 auto expList = assignment->expList.get();
1149 std::string preDefine = getPredefine(assignment);
1150 transformComprehension(static_cast<Comprehension_t*>(value), out, ExpUsage::Assignment, expList);
1151 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1152 return;
1153 }
1154 case id<TblComprehension_t>(): {
1155 auto expList = assignment->expList.get();
1156 std::string preDefine = getPredefine(assignment);
1157 transformTblComprehension(static_cast<TblComprehension_t*>(value), out, ExpUsage::Assignment, expList);
1158 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1159 return;
1160 }
1161 case id<For_t>(): {
1162 auto expList = assignment->expList.get();
1163 std::string preDefine = getPredefine(assignment);
1164 transformForInPlace(static_cast<For_t*>(value), out, expList);
1165 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1166 return;
1167 }
1168 case id<ForEach_t>(): {
1169 auto expList = assignment->expList.get();
1170 std::string preDefine = getPredefine(assignment);
1171 transformForEachInPlace(static_cast<ForEach_t*>(value), out, expList);
1172 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1173 return;
1174 }
1175 case id<ClassDecl_t>(): {
1176 auto expList = assignment->expList.get();
1177 std::string preDefine = getPredefine(assignment);
1178 transformClassDecl(static_cast<ClassDecl_t*>(value), out, ExpUsage::Assignment, expList);
1179 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1180 return;
1181 }
1182 case id<While_t>(): {
1183 auto expList = assignment->expList.get();
1184 std::string preDefine = getPredefine(assignment);
1185 transformWhileInPlace(static_cast<While_t*>(value), out, expList);
1186 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1187 return;
1188 }
1189 }
1190 auto exp = ast_cast<Exp_t>(value);
1191 BREAK_IF(!exp);
1192 if (isPureBackcall(exp)) {
1193 auto expList = assignment->expList.get();
1194 transformExp(exp, out, ExpUsage::Assignment, expList);
1195 return;
1196 }
1197 auto singleVal = singleValueFrom(exp);
1198 BREAK_IF(!singleVal);
1199 if (auto chainValue = singleVal->item.as<ChainValue_t>()) {
1200 auto type = specialChainValue(chainValue);
1201 auto expList = assignment->expList.get();
1202 switch (type) {
1203 case ChainType::HasEOP:
1204 case ChainType::EndWithColon: {
1205 std::string preDefine = getPredefine(assignment);
1206 transformChainValue(chainValue, out, ExpUsage::Assignment, expList);
1207 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1208 return;
1209 }
1210 case ChainType::HasKeyword:
1211 case ChainType::Macro:
1212 transformChainValue(chainValue, out, ExpUsage::Assignment, expList);
1213 return;
1214 case ChainType::Common:
1215 case ChainType::EndWithEOP:
1216 break;
1217 }
1218 }
1219 BLOCK_END
1220 auto info = extractDestructureInfo(assignment);
1221 if (info.first.empty()) {
1222 transformAssignmentCommon(assignment, out);
1223 } else {
1224 str_list temp;
1225 for (const auto& destruct : info.first) {
1226 if (destruct.items.size() == 1) {
1227 auto& pair = destruct.items.front();
1228 _buf << indent();
1229 if (pair.isVariable && !isDefined(pair.name)) {
1230 _buf << s("local "sv);
1231 }
1232 _buf << pair.name << " = "sv << info.first.front().value << pair.structure << nll(assignment);
1233 addToScope(pair.name);
1234 temp.push_back(clearBuf());
1235 } else if (_parser.match<Name_t>(destruct.value)) {
1236 str_list defs, names, values;
1237 for (const auto& item : destruct.items) {
1238 if (item.isVariable && addToScope(item.name)) {
1239 defs.push_back(item.name);
1240 }
1241 names.push_back(item.name);
1242 values.push_back(item.structure);
1243 }
1244 for (auto& v : values) v.insert(0, destruct.value);
1245 if (defs.empty()) {
1246 _buf << indent() << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment);
1247 } else {
1248 _buf << indent() << "local "sv;
1249 if (defs.size() != names.size()) {
1250 _buf << join(defs,", "sv) << nll(assignment) << indent();
1251 }
1252 _buf << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment);
1253 }
1254 temp.push_back(clearBuf());
1255 } else {
1256 str_list defs, names, values;
1257 for (const auto& item : destruct.items) {
1258 if (item.isVariable && addToScope(item.name)) {
1259 defs.push_back(item.name);
1260 }
1261 names.push_back(item.name);
1262 values.push_back(item.structure);
1263 }
1264 if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv) << nll(assignment);
1265 _buf << indent() << "do"sv << nll(assignment);
1266 pushScope();
1267 auto objVar = getUnusedName("_obj_"sv);
1268 for (auto& v : values) v.insert(0, objVar);
1269 _buf << indent() << "local "sv << objVar << " = "sv << destruct.value << nll(assignment);
1270 _buf << indent() << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment);
1271 popScope();
1272 _buf << indent() << "end"sv << nll(assignment);
1273 temp.push_back(clearBuf());
1274 }
1275 }
1276 if (info.second) {
1277 transformAssignmentCommon(info.second, temp);
1278 }
1279 out.push_back(join(temp));
1280 }
1281 }
1282
1283 void transformAssignItem(ast_node* value, str_list& out) {
1284 switch (value->getId()) {
1285 case id<With_t>(): transformWithClosure(static_cast<With_t*>(value), out); break;
1286 case id<If_t>(): transformIf(static_cast<If_t*>(value), out, ExpUsage::Closure); break;
1287 case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Closure); break;
1288 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(value), out); break;
1289 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(value), out, ExpUsage::Closure); break;
1290 default: assert(false); break;
1291 }
1292 }
1293
1294 std::list<DestructItem> destructFromExp(ast_node* node) {
1295 const node_container* tableItems = nullptr;
1296 if (ast_is<Exp_t>(node)) {
1297 auto item = singleValueFrom(node)->item.get();
1298 if (!item) throw std::logic_error(_info.errorMessage("invalid destructure value"sv, node));
1299 auto tbA = item->getByPath<TableLit_t>();
1300 if (tbA) {
1301 tableItems = &tbA->values.objects();
1302 } else {
1303 auto tbB = ast_cast<simple_table_t>(item);
1304 if (tbB) tableItems = &tbB->pairs.objects();
1305 }
1306 } else if (auto table = ast_cast<TableBlock_t>(node)) {
1307 tableItems = &table->values.objects();
1308 }
1309 std::list<DestructItem> pairs;
1310 int index = 0;
1311 for (auto pair : *tableItems) {
1312 switch (pair->getId()) {
1313 case id<Exp_t>(): {
1314 ++index;
1315 if (!isAssignable(static_cast<Exp_t*>(pair))) {
1316 throw std::logic_error(_info.errorMessage("can't destructure value"sv, pair));
1317 }
1318 auto value = singleValueFrom(pair);
1319 auto item = value->item.get();
1320 if (ast_is<simple_table_t>(item) ||
1321 item->getByPath<TableLit_t>()) {
1322 auto subPairs = destructFromExp(pair);
1323 for (auto& p : subPairs) {
1324 pairs.push_back({p.isVariable, p.name,
1325 s("["sv) + std::to_string(index) + s("]"sv) + p.structure});
1326 }
1327 } else {
1328 bool lintGlobal = _config.lintGlobalVariable;
1329 _config.lintGlobalVariable = false;
1330 auto exp = static_cast<Exp_t*>(pair);
1331 auto varName = singleVariableFrom(exp);
1332 bool isVariable = !varName.empty();
1333 if (!isVariable) {
1334 str_list temp;
1335 transformExp(exp, temp, ExpUsage::Closure);
1336 varName = std::move(temp.back());
1337 }
1338 _config.lintGlobalVariable = lintGlobal;
1339 pairs.push_back({
1340 isVariable,
1341 varName,
1342 s("["sv) + std::to_string(index) + s("]"sv)
1343 });
1344 }
1345 break;
1346 }
1347 case id<variable_pair_t>(): {
1348 auto vp = static_cast<variable_pair_t*>(pair);
1349 auto name = _parser.toString(vp->name);
1350 if (Keywords.find(name) != Keywords.end()) {
1351 pairs.push_back({true, name, s("[\""sv) + name + s("\"]"sv)});
1352 } else {
1353 pairs.push_back({true, name, s("."sv) + name});
1354 }
1355 break;
1356 }
1357 case id<normal_pair_t>(): {
1358 auto np = static_cast<normal_pair_t*>(pair);
1359 auto key = np->key->getByPath<Name_t>();
1360 if (!key) throw std::logic_error(_info.errorMessage("invalid key for destructure"sv, np));
1361 if (auto exp = np->value.as<Exp_t>()) {
1362 if (!isAssignable(exp)) throw std::logic_error(_info.errorMessage("can't destructure value"sv, exp));
1363 auto item = singleValueFrom(exp)->item.get();
1364 if (ast_is<simple_table_t>(item) ||
1365 item->getByPath<TableLit_t>()) {
1366 auto subPairs = destructFromExp(exp);
1367 auto name = _parser.toString(key);
1368 for (auto& p : subPairs) {
1369 if (Keywords.find(name) != Keywords.end()) {
1370 pairs.push_back({p.isVariable, p.name,
1371 s("[\""sv) + name + s("\"]"sv) + p.structure});
1372 } else {
1373 pairs.push_back({p.isVariable, p.name,
1374 s("."sv) + name + p.structure});
1375 }
1376 }
1377 } else {
1378 bool lintGlobal = _config.lintGlobalVariable;
1379 _config.lintGlobalVariable = false;
1380 auto varName = singleVariableFrom(exp);
1381 bool isVariable = !varName.empty();
1382 if (!isVariable) {
1383 str_list temp;
1384 transformExp(exp, temp, ExpUsage::Closure);
1385 varName = std::move(temp.back());
1386 }
1387 _config.lintGlobalVariable = lintGlobal;
1388 auto name = _parser.toString(key);
1389 if (Keywords.find(name) != Keywords.end()) {
1390 pairs.push_back({
1391 isVariable,
1392 varName,
1393 s("[\""sv) + name + s("\"]"sv)
1394 });
1395 } else {
1396 pairs.push_back({
1397 isVariable,
1398 varName,
1399 s("."sv) + name
1400 });
1401 }
1402 }
1403 break;
1404 }
1405 if (np->value.is<TableBlock_t>()) {
1406 auto subPairs = destructFromExp(pair);
1407 for (auto& p : subPairs) {
1408 pairs.push_back({p.isVariable, p.name,
1409 s("."sv) + _parser.toString(key) + p.structure});
1410 }
1411 }
1412 break;
1413 }
1414 default: assert(false); break;
1415 }
1416 }
1417 return pairs;
1418 }
1419
1420 std::pair<std::list<Destructure>, ast_ptr<false, ExpListAssign_t>>
1421 extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly = false) {
1422 auto x = assignment;
1423 std::list<Destructure> destructs;
1424 if (!assignment->action.is<Assign_t>()) return { destructs, nullptr };
1425 auto exprs = assignment->expList->exprs.objects();
1426 auto values = assignment->action.to<Assign_t>()->values.objects();
1427 size_t size = std::max(exprs.size(),values.size());
1428 ast_ptr<false, Exp_t> var;
1429 if (exprs.size() < size) {
1430 var = toAst<Exp_t>("_"sv, x);
1431 while (exprs.size() < size) exprs.emplace_back(var);
1432 }
1433 ast_ptr<false, Exp_t> nullNode;
1434 if (values.size() < size) {
1435 nullNode = toAst<Exp_t>("nil"sv, x);
1436 while (values.size() < size) values.emplace_back(nullNode);
1437 }
1438 using iter = node_container::iterator;
1439 std::vector<std::pair<iter,iter>> destructPairs;
1440 str_list temp;
1441 for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) {
1442 auto expr = *i;
1443 auto value = singleValueFrom(expr);
1444 ast_node* destructNode = value->getByPath<SimpleValue_t, TableLit_t>();
1445 if (destructNode || (destructNode = value->item.as<simple_table_t>())) {
1446 destructPairs.push_back({i,j});
1447 auto& destruct = destructs.emplace_back();
1448 if (!varDefOnly) {
1449 pushScope();
1450 transformAssignItem(*j, temp);
1451 destruct.value = temp.back();
1452 temp.pop_back();
1453 popScope();
1454 }
1455 auto pairs = destructFromExp(expr);
1456 destruct.items = std::move(pairs);
1457 if (destruct.items.size() == 1 && !singleValueFrom(*j)) {
1458 destruct.value.insert(0, "("sv);
1459 destruct.value.append(")"sv);
1460 }
1461 }
1462 }
1463 for (const auto& p : destructPairs) {
1464 exprs.erase(p.first);
1465 values.erase(p.second);
1466 }
1467 ast_ptr<false, ExpListAssign_t> newAssignment;
1468 if (!destructPairs.empty() && !exprs.empty()) {
1469 auto x = assignment;
1470 auto expList = x->new_ptr<ExpList_t>();
1471 auto newAssign = x->new_ptr<ExpListAssign_t>();
1472 newAssign->expList.set(expList);
1473 for (auto expr : exprs) expList->exprs.push_back(expr);
1474 auto assign = x->new_ptr<Assign_t>();
1475 for (auto value : values) assign->values.push_back(value);
1476 newAssign->action.set(assign);
1477 newAssignment = newAssign;
1478 }
1479 return {std::move(destructs), newAssignment};
1480 }
1481
1482 void transformAssignmentCommon(ExpListAssign_t* assignment, str_list& out) {
1483 auto x = assignment;
1484 str_list temp;
1485 auto expList = assignment->expList.get();
1486 auto action = assignment->action.get();
1487 switch (action->getId()) {
1488 case id<Update_t>(): {
1489 if (expList->exprs.size() > 1) throw std::logic_error(_info.errorMessage("can not apply update to multiple values"sv, expList));
1490 auto update = static_cast<Update_t*>(action);
1491 auto leftExp = static_cast<Exp_t*>(expList->exprs.objects().front());
1492 auto leftValue = singleValueFrom(leftExp);
1493 if (!leftValue) throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, leftExp));
1494 if (auto chain = leftValue->item.as<ChainValue_t>()) {
1495 auto tmpChain = x->new_ptr<ChainValue_t>();
1496 for (auto item : chain->items.objects()) {
1497 bool itemAdded = false;
1498 BLOCK_START
1499 auto exp = ast_cast<Exp_t>(item);
1500 BREAK_IF(!exp);
1501 auto var = singleVariableFrom(exp);
1502 BREAK_IF(!var.empty());
1503 auto upVar = getUnusedName("_update_"sv);
1504 auto assignment = x->new_ptr<ExpListAssign_t>();
1505 assignment->expList.set(toAst<ExpList_t>(upVar, x));
1506 auto assign = x->new_ptr<Assign_t>();
1507 assign->values.push_back(exp);
1508 assignment->action.set(assign);
1509 transformAssignment(assignment, temp);
1510 tmpChain->items.push_back(toAst<Exp_t>(upVar, x));
1511 itemAdded = true;
1512 BLOCK_END
1513 if (!itemAdded) tmpChain->items.push_back(item);
1514 }
1515 chain->items.clear();
1516 chain->items.dup(tmpChain->items);
1517 }
1518 transformValue(leftValue, temp);
1519 auto left = std::move(temp.back());
1520 temp.pop_back();
1521 transformExp(update->value, temp, ExpUsage::Closure);
1522 auto right = std::move(temp.back());
1523 temp.pop_back();
1524 if (!singleValueFrom(update->value)) {
1525 right = s("("sv) + right + s(")"sv);
1526 }
1527 _buf << join(temp) << indent() << left << " = "sv << left <<
1528 " "sv << _parser.toString(update->op) << " "sv << right << nll(assignment);
1529 out.push_back(clearBuf());
1530 break;
1531 }
1532 case id<Assign_t>(): {
1533 bool oneLined = true;
1534 auto assign = static_cast<Assign_t*>(action);
1535 for (auto val : assign->values.objects()) {
1536 if (auto value = singleValueFrom(val)) {
1537 if (auto spValue = value->item.as<SimpleValue_t>()) {
1538 if (spValue->value.is<FunLit_t>()) {
1539 oneLined = false;
1540 break;
1541 }
1542 }
1543 }
1544 }
1545 auto defs = getAssignDefs(expList);
1546 if (oneLined && defs.size() == expList->exprs.objects().size()) {
1547 for (auto value : assign->values.objects()) {
1548 transformAssignItem(value, temp);
1549 }
1550 std::string preDefine = getPredefine(defs);
1551 for (const auto& def : defs) {
1552 addToScope(def);
1553 }
1554 if (preDefine.empty()) {
1555 transformExpList(expList, temp);
1556 std::string left = std::move(temp.back());
1557 temp.pop_back();
1558 out.push_back(indent() + left + s(" = "sv) + join(temp, ", "sv) + nll(assignment));
1559 } else {
1560 out.push_back(preDefine + s(" = "sv) + join(temp, ", "sv) + nll(assignment));
1561 }
1562 } else {
1563 std::string preDefine = getPredefine(defs);
1564 for (const auto& def : defs) {
1565 addToScope(def);
1566 }
1567 transformExpList(expList, temp);
1568 std::string left = temp.back();
1569 temp.pop_back();
1570 for (auto value : assign->values.objects()) {
1571 transformAssignItem(value, temp);
1572 }
1573 out.push_back((preDefine.empty() ? Empty : preDefine + nll(assignment)) + indent() + left + s(" = "sv) + join(temp, ", "sv) + nll(assignment));
1574 }
1575 break;
1576 }
1577 default: assert(false); break;
1578 }
1579 }
1580
1581 void transformCond(const node_container& nodes, str_list& out, ExpUsage usage, bool unless, ExpList_t* assignList) {
1582 std::vector<ast_ptr<false, ast_node>> ns(false);
1583 for (auto it = nodes.rbegin(); it != nodes.rend(); ++it) {
1584 ns.push_back(*it);
1585 if (auto cond = ast_cast<IfCond_t>(*it)) {
1586 if (*it != nodes.front() && cond->assign) {
1587 auto x = *it;
1588 auto newIf = x->new_ptr<If_t>();
1589 for (auto j = ns.rbegin(); j != ns.rend(); ++j) {
1590 newIf->nodes.push_back(*j);
1591 }
1592 ns.clear();
1593 auto simpleValue = x->new_ptr<SimpleValue_t>();
1594 simpleValue->value.set(newIf);
1595 auto value = x->new_ptr<Value_t>();
1596 value->item.set(simpleValue);
1597 auto exp = newExp(value, x);
1598 auto expList = x->new_ptr<ExpList_t>();
1599 expList->exprs.push_back(exp);
1600 auto expListAssign = x->new_ptr<ExpListAssign_t>();
1601 expListAssign->expList.set(expList);
1602 auto stmt = x->new_ptr<Statement_t>();
1603 stmt->content.set(expListAssign);
1604 ns.push_back(stmt.get());
1605 }
1606 }
1607 }
1608 if (nodes.size() != ns.size()) {
1609 auto x = ns.back();
1610 auto newIf = x->new_ptr<If_t>();
1611 for (auto j = ns.rbegin(); j != ns.rend(); ++j) {
1612 newIf->nodes.push_back(*j);
1613 }
1614 transformCond(newIf->nodes.objects(), out, usage, unless, assignList);
1615 return;
1616 }
1617 str_list temp;
1618 if (usage == ExpUsage::Closure) {
1619 temp.push_back(s("(function()"sv) + nll(nodes.front()));
1620 pushScope();
1621 _enableReturn.push(true);
1622 }
1623 std::list<std::pair<IfCond_t*, ast_node*>> ifCondPairs;
1624 ifCondPairs.emplace_back();
1625 for (auto node : nodes) {
1626 switch (node->getId()) {
1627 case id<IfCond_t>():
1628 ifCondPairs.back().first = static_cast<IfCond_t*>(node);
1629 break;
1630 case id<Block_t>():
1631 case id<Statement_t>():
1632 ifCondPairs.back().second = node;
1633 ifCondPairs.emplace_back();
1634 break;
1635 default: assert(false); break;
1636 }
1637 }
1638 auto assign = ifCondPairs.front().first->assign.get();
1639 bool storingValue = false;
1640 ast_ptr<false, ExpListAssign_t> extraAssignment;
1641 if (assign) {
1642 auto exp = ifCondPairs.front().first->condition.get();
1643 auto x = exp;
1644 bool lintGlobal = _config.lintGlobalVariable;
1645 _config.lintGlobalVariable = false;
1646 auto var = singleVariableFrom(exp);
1647 _config.lintGlobalVariable = lintGlobal;
1648 if (var.empty()) {
1649 storingValue = true;
1650 auto desVar = getUnusedName("_des_"sv);
1651 if (assign->values.objects().size() == 1) {
1652 auto var = singleVariableFrom(assign->values.objects().front());
1653 if (!var.empty()) {
1654 desVar = var;
1655 storingValue = false;
1656 }
1657 }
1658 if (storingValue) {
1659 if (usage != ExpUsage::Closure) {
1660 temp.push_back(indent() + s("do"sv) + nll(assign));
1661 pushScope();
1662 }
1663 auto expList = toAst<ExpList_t>(desVar, x);
1664 auto assignment = x->new_ptr<ExpListAssign_t>();
1665 assignment->expList.set(expList);
1666 assignment->action.set(assign);
1667 transformAssignment(assignment, temp);
1668 }
1669 {
1670 auto expList = x->new_ptr<ExpList_t>();
1671 expList->exprs.push_back(exp);
1672 auto assignOne = x->new_ptr<Assign_t>();
1673 auto valExp = toAst<Exp_t>(desVar, x);
1674 assignOne->values.push_back(valExp);
1675 auto assignment = x->new_ptr<ExpListAssign_t>();
1676 assignment->expList.set(expList);
1677 assignment->action.set(assignOne);
1678 extraAssignment.set(assignment);
1679 ifCondPairs.front().first->condition.set(valExp);
1680 }
1681 } else {
1682 if (!isDefined(var)) {
1683 storingValue = true;
1684 if (usage != ExpUsage::Closure) {
1685 temp.push_back(indent() + s("do"sv) + nll(assign));
1686 pushScope();
1687 }
1688 }
1689 auto expList = x->new_ptr<ExpList_t>();
1690 expList->exprs.push_back(exp);
1691 auto assignment = x->new_ptr<ExpListAssign_t>();
1692 assignment->expList.set(expList);
1693 assignment->action.set(assign);
1694 transformAssignment(assignment, temp);
1695 }
1696 }
1697 for (const auto& pair : ifCondPairs) {
1698 if (pair.first) {
1699 str_list tmp;
1700 auto condition = pair.first->condition.get();
1701 if (unless) {
1702 if (auto value = singleValueFrom(condition)) {
1703 transformValue(value, tmp);
1704 } else {
1705 transformExp(condition, tmp, ExpUsage::Closure);
1706 tmp.back() = s("("sv) + tmp.back() + s(")"sv);
1707 }
1708 tmp.back().insert(0, s("not "sv));
1709 unless = false;
1710 } else {
1711 transformExp(condition, tmp, ExpUsage::Closure);
1712 }
1713 _buf << indent();
1714 if (pair != ifCondPairs.front()) {
1715 _buf << "else"sv;
1716 }
1717 _buf << "if "sv << tmp.back() << " then"sv << nll(condition);
1718 temp.push_back(clearBuf());
1719 }
1720 if (pair.second) {
1721 if (!pair.first) {
1722 temp.push_back(indent() + s("else"sv) + nll(pair.second));
1723 }
1724 pushScope();
1725 if (pair == ifCondPairs.front() && extraAssignment) {
1726 transformAssignment(extraAssignment, temp);
1727 }
1728 transform_plain_body(pair.second, temp, usage, assignList);
1729 popScope();
1730 }
1731 if (!pair.first) {
1732 temp.push_back(indent() + s("end"sv) + nll(nodes.front()));
1733 break;
1734 }
1735 }
1736 if (storingValue && usage != ExpUsage::Closure) {
1737 popScope();
1738 temp.push_back(indent() + s("end"sv) + nlr(nodes.front()));
1739 }
1740 if (usage == ExpUsage::Closure) {
1741 _enableReturn.pop();
1742 popScope();
1743 temp.push_back(indent() + s("end)()"sv));
1744 }
1745 out.push_back(join(temp));
1746 }
1747
1748 void transformIf(If_t* ifNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
1749 transformCond(ifNode->nodes.objects(), out, usage, false, assignList);
1750 }
1751
1752 void transformUnless(Unless_t* unless, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
1753 transformCond(unless->nodes.objects(), out, usage, true, assignList);
1754 }
1755
1756 void transformExpList(ExpList_t* expList, str_list& out) {
1757 str_list temp;
1758 for (auto exp : expList->exprs.objects()) {
1759 transformExp(static_cast<Exp_t*>(exp), temp, ExpUsage::Closure);
1760 }
1761 out.push_back(join(temp, ", "sv));
1762 }
1763
1764 void transformExpListLow(ExpListLow_t* expListLow, str_list& out) {
1765 str_list temp;
1766 for (auto exp : expListLow->exprs.objects()) {
1767 transformExp(static_cast<Exp_t*>(exp), temp, ExpUsage::Closure);
1768 }
1769 out.push_back(join(temp, ", "sv));
1770 }
1771
1772 void transform_backcall_exp(const node_container& values, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
1773 if (values.size() == 1 && usage == ExpUsage::Closure) {
1774 transform_unary_exp(static_cast<unary_exp_t*>(values.front()), out);
1775 } else {
1776 auto x = values.front();
1777 auto arg = newExp(static_cast<unary_exp_t*>(x), x);
1778 auto begin = values.begin(); begin++;
1779 for (auto it = begin; it != values.end(); ++it) {
1780 auto unary = static_cast<unary_exp_t*>(*it);
1781 auto value = static_cast<Value_t*>(singleUnaryExpFrom(unary) ? unary->expos.back() : nullptr);
1782 if (values.back() == *it && !unary->ops.empty() && usage == ExpUsage::Common) {
1783 throw std::logic_error(_info.errorMessage("expression list is not supported here"sv, x));
1784 }
1785 if (!value) throw std::logic_error(_info.errorMessage("backcall operator must be followed by chain value"sv, *it));
1786 if (auto chainValue = value->item.as<ChainValue_t>()) {
1787 if (isChainValueCall(chainValue)) {
1788 auto last = chainValue->items.back();
1789 _ast_list* args = nullptr;
1790 if (auto invoke = ast_cast<InvokeArgs_t>(last)) {
1791 args = &invoke->args;
1792 } else {
1793 args = &(ast_to<Invoke_t>(last)->args);
1794 }
1795 bool findPlaceHolder = false;
1796 for (auto a : args->objects()) {
1797 bool lintGlobal = _config.lintGlobalVariable;
1798 _config.lintGlobalVariable = false;
1799 auto name = singleVariableFrom(a);
1800 _config.lintGlobalVariable = lintGlobal;
1801 if (name == "_"sv) {
1802 if (!findPlaceHolder) {
1803 args->swap(a, arg);
1804 findPlaceHolder = true;
1805 } else {
1806 throw std::logic_error(_info.errorMessage("backcall placeholder can be used only in one place"sv, a));
1807 }
1808 }
1809 }
1810 if (!findPlaceHolder) {
1811 args->push_front(arg);
1812 }
1813 } else {
1814 auto invoke = x->new_ptr<Invoke_t>();
1815 invoke->args.push_front(arg);
1816 chainValue->items.push_back(invoke);
1817 }
1818 arg.set(newExp(unary, x));
1819 } else {
1820 throw std::logic_error(_info.errorMessage("backcall operator must be followed by chain value"sv, value));
1821 }
1822 }
1823 switch (usage) {
1824 case ExpUsage::Assignment: {
1825 auto assignment = x->new_ptr<ExpListAssign_t>();
1826 auto assign = x->new_ptr<Assign_t>();
1827 assign->values.push_back(arg);
1828 assignment->action.set(assign);
1829 assignment->expList.set(assignList);
1830 transformAssignment(assignment, out);
1831 return;
1832 }
1833 case ExpUsage::Common: {
1834 auto value = singleValueFrom(arg);
1835 if (value && value->item.is<ChainValue_t>()) {
1836 transformChainValue(value->item.to<ChainValue_t>(), out, ExpUsage::Common);
1837 } else {
1838 transformExp(arg, out, ExpUsage::Closure);
1839 out.back().insert(0, indent());
1840 out.back().append(nlr(x));
1841 }
1842 return;
1843 }
1844 case ExpUsage::Return: {
1845 auto ret = x->new_ptr<Return_t>();
1846 auto expListLow = x->new_ptr<ExpListLow_t>();
1847 expListLow->exprs.push_back(arg);
1848 ret->valueList.set(expListLow);
1849 transformReturn(ret, out);
1850 return;
1851 }
1852 case ExpUsage::Closure: {
1853 transformExp(arg, out, ExpUsage::Closure);
1854 return;
1855 }
1856 default: assert(false); return;
1857 }
1858 }
1859 }
1860
1861 void transformExp(Exp_t* exp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
1862 if (exp->opValues.empty()) {
1863 transform_backcall_exp(exp->backcalls.objects(), out, usage, assignList);
1864 return;
1865 }
1866 assert(usage == ExpUsage::Closure);
1867 str_list temp;
1868 transform_backcall_exp(exp->backcalls.objects(), temp, ExpUsage::Closure);
1869 for (auto _opValue : exp->opValues.objects()) {
1870 auto opValue = static_cast<exp_op_value_t*>(_opValue);
1871 transformBinaryOperator(opValue->op, temp);
1872 transform_backcall_exp(opValue->backcalls.objects(), temp, ExpUsage::Closure);
1873 }
1874 out.push_back(join(temp, " "sv));
1875 }
1876
1877 void transformValue(Value_t* value, str_list& out) {
1878 auto item = value->item.get();
1879 switch (item->getId()) {
1880 case id<SimpleValue_t>(): transformSimpleValue(static_cast<SimpleValue_t*>(item), out); break;
1881 case id<simple_table_t>(): transform_simple_table(static_cast<simple_table_t*>(item), out); break;
1882 case id<ChainValue_t>(): transformChainValue(static_cast<ChainValue_t*>(item), out, ExpUsage::Closure); break;
1883 case id<String_t>(): transformString(static_cast<String_t*>(item), out); break;
1884 default: assert(false); break;
1885 }
1886 }
1887
1888 void transformCallable(Callable_t* callable, str_list& out, const ast_sel<false,Invoke_t,InvokeArgs_t>& invoke = {}) {
1889 auto item = callable->item.get();
1890 switch (item->getId()) {
1891 case id<Variable_t>(): {
1892 transformVariable(static_cast<Variable_t*>(item), out);
1893 if (_config.lintGlobalVariable && !isDefined(out.back())) {
1894 if (_globals.find(out.back()) == _globals.end()) {
1895 _globals[out.back()] = {item->m_begin.m_line, item->m_begin.m_col};
1896 }
1897 }
1898 break;
1899 }
1900 case id<SelfName_t>(): {
1901 transformSelfName(static_cast<SelfName_t*>(item), out, invoke);
1902 if (_config.lintGlobalVariable) {
1903 std::string self("self"sv);
1904 if (!isDefined(self)) {
1905 if (_globals.find(self) == _globals.end()) {
1906 _globals[self] = {item->m_begin.m_line, item->m_begin.m_col};
1907 }
1908 }
1909 }
1910 break;
1911 }
1912 case id<VarArg_t>():
1913 if (_varArgs.empty() || !_varArgs.top()) {
1914 throw std::logic_error(_info.errorMessage("cannot use '...' outside a vararg function near '...'"sv, item));
1915 }
1916 out.push_back(s("..."sv));
1917 break;
1918 case id<Parens_t>(): transformParens(static_cast<Parens_t*>(item), out); break;
1919 default: assert(false); break;
1920 }
1921 }
1922
1923 void transformParens(Parens_t* parans, str_list& out) {
1924 str_list temp;
1925 transformExp(parans->expr, temp, ExpUsage::Closure);
1926 out.push_back(s("("sv) + temp.front() + s(")"sv));
1927 }
1928
1929 void transformSimpleValue(SimpleValue_t* simpleValue, str_list& out) {
1930 auto value = simpleValue->value.get();
1931 switch (value->getId()) {
1932 case id<const_value_t>(): transform_const_value(static_cast<const_value_t*>(value), out); break;
1933 case id<If_t>(): transformIf(static_cast<If_t*>(value), out, ExpUsage::Closure); break;
1934 case id<Unless_t>(): transformUnless(static_cast<Unless_t*>(value), out, ExpUsage::Closure); break;
1935 case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Closure); break;
1936 case id<With_t>(): transformWithClosure(static_cast<With_t*>(value), out); break;
1937 case id<ClassDecl_t>(): transformClassDeclClosure(static_cast<ClassDecl_t*>(value), out); break;
1938 case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break;
1939 case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break;
1940 case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break;
1941 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break;
1942 case id<unary_value_t>(): transform_unary_value(static_cast<unary_value_t*>(value), out); break;
1943 case id<TblComprehension_t>(): transformTblComprehension(static_cast<TblComprehension_t*>(value), out, ExpUsage::Closure); break;
1944 case id<TableLit_t>(): transformTableLit(static_cast<TableLit_t*>(value), out); break;
1945 case id<Comprehension_t>(): transformComprehension(static_cast<Comprehension_t*>(value), out, ExpUsage::Closure); break;
1946 case id<FunLit_t>(): transformFunLit(static_cast<FunLit_t*>(value), out); break;
1947 case id<Num_t>(): transformNum(static_cast<Num_t*>(value), out); break;
1948 default: assert(false); break;
1949 }
1950 }
1951
1952 void transformFunLit(FunLit_t* funLit, str_list& out) {
1953 _enableReturn.push(true);
1954 _varArgs.push(false);
1955 str_list temp;
1956 bool isFatArrow = _parser.toString(funLit->arrow) == "=>"sv;
1957 pushScope();
1958 if (isFatArrow) {
1959 forceAddToScope(s("self"sv));
1960 }
1961 if (auto argsDef = funLit->argsDef.get()) {
1962 transformFnArgsDef(argsDef, temp);
1963 if (funLit->body) {
1964 transformBody(funLit->body, temp, ExpUsage::Return);
1965 } else {
1966 temp.push_back(Empty);
1967 }
1968 auto it = temp.begin();
1969 auto& args = *it;
1970 auto& initArgs = *(++it);
1971 auto& bodyCodes = *(++it);
1972 _buf << "function("sv;
1973 if (isFatArrow) {
1974 _buf << "self"sv;
1975 if (!args.empty()) _buf << ", "sv;
1976 }
1977 _buf << args << ')';
1978 if (!initArgs.empty() || !bodyCodes.empty()) {
1979 _buf << nlr(argsDef) << initArgs << bodyCodes;
1980 popScope();
1981 _buf << indent() << "end"sv;
1982 } else {
1983 popScope();
1984 _buf << " end"sv;
1985 }
1986 } else {
1987 if (funLit->body) {
1988 transformBody(funLit->body, temp, ExpUsage::Return);
1989 } else {
1990 temp.push_back(Empty);
1991 }
1992 auto& bodyCodes = temp.back();
1993 _buf << "function("sv <<
1994 (isFatArrow ? s("self"sv) : Empty) <<
1995 ')';
1996 if (!bodyCodes.empty()) {
1997 _buf << nll(funLit) << bodyCodes;
1998 popScope();
1999 _buf << indent() << "end"sv;
2000 } else {
2001 popScope();
2002 _buf << " end"sv;
2003 }
2004 }
2005 out.push_back(clearBuf());
2006 _enableReturn.pop();
2007 _varArgs.pop();
2008 }
2009
2010 void transformBody(Body_t* body, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
2011 auto x = body;
2012 if (auto stmt = body->content.as<Statement_t>()) {
2013 auto block = x->new_ptr<Block_t>();
2014 block->statements.push_back(stmt);
2015 transformBlock(block, out, usage, assignList);
2016 } else {
2017 transformBlock(body->content.to<Block_t>(), out, usage, assignList);
2018 }
2019 }
2020
2021 void transformBlock(Block_t* block, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr, bool isRoot = false) {
2022 const auto& nodes = block->statements.objects();
2023 LocalMode mode = LocalMode::None;
2024 Local_t* any = nullptr, *capital = nullptr;
2025 for (auto it = nodes.begin(); it != nodes.end(); ++it) {
2026 auto node = *it;
2027 auto stmt = static_cast<Statement_t*>(node);
2028 if (auto backcallBody = stmt->content.as<BackcallBody_t>()) {
2029 auto x = stmt;
2030 bool cond = false;
2031 BLOCK_START
2032 BREAK_IF(it == nodes.begin());
2033 auto last = it; --last;
2034 auto lst = static_cast<Statement_t*>(*last);
2035 if (lst->appendix) {
2036 throw std::logic_error(_info.errorMessage("statement decorator must be placed at the end of backcall chain"sv, lst->appendix.get()));
2037 }
2038 lst->appendix.set(stmt->appendix);
2039 stmt->appendix.set(nullptr);
2040 lst->needSep.set(stmt->needSep);
2041 stmt->needSep.set(nullptr);
2042 auto exp = lastExpFromStatement(lst);
2043 BREAK_IF(!exp);
2044 for (auto val : backcallBody->values.objects()) {
2045 exp->backcalls.push_back(val);
2046 }
2047 cond = true;
2048 BLOCK_END
2049 if (!cond) throw std::logic_error(_info.errorMessage("backcall chain must be following a value"sv, x));
2050 stmt->content.set(nullptr);
2051 auto next = it; ++next;
2052 BLOCK_START
2053 BREAK_IF(next == nodes.end());
2054 BREAK_IF(!static_cast<Statement_t*>(*next)->content.as<BackcallBody_t>());
2055 throw std::logic_error(_info.errorMessage("indent mismatch in backcall chain"sv, *next));
2056 BLOCK_END
2057 } else if (auto backcall = stmt->content.as<Backcall_t>()) {
2058 auto x = *nodes.begin();
2059 auto newBlock = x->new_ptr<Block_t>();
2060 if (it != nodes.begin()) {
2061 for (auto i = nodes.begin(); i != it; ++i) {
2062 newBlock->statements.push_back(*i);
2063 }
2064 }
2065 x = backcall;
2066 ast_ptr<false, Exp_t> arg;
2067 {
2068 auto block = x->new_ptr<Block_t>();
2069 auto next = it; ++next;
2070 if (next != nodes.end()) {
2071 for (auto i = next; i != nodes.end(); ++i) {
2072 block->statements.push_back(*i);
2073 }
2074 }
2075 auto body = x->new_ptr<Body_t>();
2076 body->content.set(block);
2077 auto funLit = x->new_ptr<FunLit_t>();
2078 funLit->argsDef.set(backcall->argsDef);
2079 auto arrow = _parser.toString(backcall->arrow);
2080 funLit->arrow.set(toAst<fn_arrow_t>(arrow == "<-"sv ? "->"sv : "=>"sv, x));
2081 funLit->body.set(body);
2082 auto simpleValue = x->new_ptr<SimpleValue_t>();
2083 simpleValue->value.set(funLit);
2084 auto value = x->new_ptr<Value_t>();
2085 value->item.set(simpleValue);
2086 arg = newExp(value, x);
2087 }
2088 if (isChainValueCall(backcall->value)) {
2089 auto last = backcall->value->items.back();
2090 _ast_list* args = nullptr;
2091 if (auto invoke = ast_cast<InvokeArgs_t>(last)) {
2092 args = &invoke->args;
2093 } else {
2094 args = &(ast_to<Invoke_t>(last)->args);
2095 }
2096 bool findPlaceHolder = false;
2097 for (auto a : args->objects()) {
2098 bool lintGlobal = _config.lintGlobalVariable;
2099 _config.lintGlobalVariable = false;
2100 auto name = singleVariableFrom(a);
2101 _config.lintGlobalVariable = lintGlobal;
2102 if (name == "_"sv) {
2103 if (!findPlaceHolder) {
2104 args->swap(a, arg);
2105 findPlaceHolder = true;
2106 } else {
2107 throw std::logic_error(_info.errorMessage("backcall placeholder can be used only in one place"sv, a));
2108 }
2109 }
2110 }
2111 if (!findPlaceHolder) {
2112 args->push_back(arg);
2113 }
2114 } else {
2115 auto invoke = x->new_ptr<Invoke_t>();
2116 invoke->args.push_back(arg);
2117 backcall->value->items.push_back(invoke);
2118 }
2119 auto newStmt = x->new_ptr<Statement_t>();
2120 {
2121 auto chainValue = backcall->value.get();
2122 auto value = x->new_ptr<Value_t>();
2123 value->item.set(chainValue);
2124 auto exp = newExp(value, x);
2125 auto expList = x->new_ptr<ExpList_t>();
2126 expList->exprs.push_back(exp);
2127 auto expListAssign = x->new_ptr<ExpListAssign_t>();
2128 expListAssign->expList.set(expList);
2129 newStmt->content.set(expListAssign);
2130 newStmt->appendix.set(stmt->appendix);
2131 newBlock->statements.push_back(newStmt);
2132 }
2133 transformBlock(newBlock, out, usage, assignList, isRoot);
2134 return;
2135 }
2136 if (auto local = stmt->content.as<Local_t>()) {
2137 if (!local->collected) {
2138 local->collected = true;
2139 switch (local->item->getId()) {
2140 case id<local_flag_t>(): {
2141 auto flag = local->item.to<local_flag_t>();
2142 LocalMode newMode = _parser.toString(flag) == "*"sv ? LocalMode::Any : LocalMode::Capital;
2143 if (int(newMode) > int(mode)) {
2144 mode = newMode;
2145 }
2146 if (mode == LocalMode::Any) {
2147 if (!any) any = local;
2148 if (!capital) capital = local;
2149 } else {
2150 if (!capital) capital = local;
2151 }
2152 break;
2153 }
2154 case id<local_values_t>(): {
2155 auto values = local->item.to<local_values_t>();
2156 for (auto name : values->nameList->names.objects()) {
2157 local->forceDecls.push_back(_parser.toString(name));
2158 }
2159 break;
2160 }
2161 }
2162 }
2163 } else if (mode != LocalMode::None) {
2164 ClassDecl_t* classDecl = nullptr;
2165 if (auto assignment = assignmentFrom(stmt)) {
2166 auto vars = getAssignVars(assignment);
2167 for (const auto& var : vars) {
2168 if (var.empty()) continue;
2169 if (std::isupper(var[0]) && capital) {
2170 capital->decls.push_back(var);
2171 } else if (any) {
2172 any->decls.push_back(var);
2173 }
2174 }
2175 auto info = extractDestructureInfo(assignment, true);
2176 if (!info.first.empty()) {
2177 for (const auto& destruct : info.first)
2178 for (const auto& item : destruct.items)
2179 if (item.isVariable) {
2180 if (std::isupper(item.name[0]) && capital) { capital->decls.push_back(item.name);
2181 } else if (any) {
2182 any->decls.push_back(item.name);
2183 }
2184 }
2185 }
2186 if (info.second) {
2187 auto defs = transformAssignDefs(info.second->expList, false);
2188 for (const auto& def : defs) {
2189 if (std::isupper(def[0]) && capital) { capital->decls.push_back(def);
2190 } else if (any) {
2191 any->decls.push_back(def);
2192 }
2193 }
2194 }
2195 BLOCK_START
2196 auto assign = assignment->action.as<Assign_t>();
2197 BREAK_IF(!assign);
2198 BREAK_IF(assign->values.objects().size() != 1);
2199 auto exp = ast_cast<Exp_t>(assign->values.objects().front());
2200 BREAK_IF(!exp);
2201 auto value = singleValueFrom(exp);
2202 classDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
2203 BLOCK_END
2204 } else if (auto expList = expListFrom(stmt)) {
2205 auto value = singleValueFrom(expList);
2206 classDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
2207 }
2208 if (classDecl) {
2209 if (auto variable = classDecl->name->item.as<Variable_t>()) {
2210 auto className = _parser.toString(variable);
2211 if (!className.empty()) {
2212 if (std::isupper(className[0]) && capital) {
2213 capital->decls.push_back(className);
2214 } else if (any) {
2215 any->decls.push_back(className);
2216 }
2217 }
2218 }
2219 }
2220 }
2221 }
2222 if (isRoot && !_info.moduleName.empty()) {
2223 block->statements.push_front(toAst<Statement_t>(_info.moduleName + s(_info.exportDefault ? "=nil"sv : "={}"sv), block));
2224 }
2225 switch (usage) {
2226 case ExpUsage::Closure:
2227 case ExpUsage::Return: {
2228 BLOCK_START
2229 BREAK_IF(isRoot && !_info.moduleName.empty());
2230 auto last = lastStatementFrom(nodes);
2231 BREAK_IF(!last);
2232 auto x = last;
2233 auto expList = expListFrom(last);
2234 BREAK_IF(!expList ||
2235 (last->appendix &&
2236 last->appendix->item.is<CompInner_t>()));
2237 auto expListLow = x->new_ptr<ExpListLow_t>();
2238 expListLow->exprs.dup(expList->exprs);
2239 auto returnNode = x->new_ptr<Return_t>();
2240 returnNode->valueList.set(expListLow);
2241 returnNode->allowBlockMacroReturn = true;
2242 last->content.set(returnNode);
2243 last->needSep.set(nullptr);
2244 auto bLast = ++nodes.rbegin();
2245 if (bLast != nodes.rend()) {
2246 bool isMacro = false;
2247 BLOCK_START
2248 BREAK_IF(expListLow->exprs.size() != 1);
2249 auto exp = static_cast<Exp_t*>(expListLow->exprs.back());
2250 BREAK_IF(!exp->opValues.empty());
2251 auto chainValue = exp->getByPath<unary_exp_t, Value_t, ChainValue_t>();
2252 BREAK_IF(!chainValue);
2253 isMacro = isMacroChain(chainValue);
2254 BLOCK_END
2255 if (!isMacro) {
2256 ast_to<Statement_t>(*bLast)->needSep.set(nullptr);
2257 }
2258 }
2259 BLOCK_END
2260 break;
2261 }
2262 case ExpUsage::Assignment: {
2263 auto last = lastStatementFrom(block);
2264 if (!last) return;
2265 bool lastAssignable = expListFrom(last) || ast_is<For_t, ForEach_t, While_t>(last->content);
2266 if (lastAssignable) {
2267 auto x = last;
2268 auto newAssignment = x->new_ptr<ExpListAssign_t>();
2269 newAssignment->expList.set(assignList);
2270 auto assign = x->new_ptr<Assign_t>();
2271 if (auto valueList = last->content.as<ExpListAssign_t>()) {
2272 assign->values.dup(valueList->expList->exprs);
2273 } else {
2274 auto simpleValue = x->new_ptr<SimpleValue_t>();
2275 simpleValue->value.set(last->content);
2276 auto value = x->new_ptr<Value_t>();
2277 value->item.set(simpleValue);
2278 auto exp = newExp(value, x);
2279 assign->values.push_back(exp);
2280 }
2281 newAssignment->action.set(assign);
2282 last->content.set(newAssignment);
2283 last->needSep.set(nullptr);
2284 auto bLast = ++nodes.rbegin();
2285 if (bLast != nodes.rend()) {
2286 static_cast<Statement_t*>(*bLast)->needSep.set(nullptr);
2287 }
2288 }
2289 break;
2290 }
2291 default: break;
2292 }
2293 if (!nodes.empty()) {
2294 str_list temp;
2295 for (auto node : nodes) {
2296 transformStatement(static_cast<Statement_t*>(node), temp);
2297 }
2298 out.push_back(join(temp));
2299 } else {
2300 out.push_back(Empty);
2301 }
2302 if (isRoot && !_info.moduleName.empty()) {
2303 out.back().append(indent() + s("return "sv) + _info.moduleName + nlr(block));
2304 }
2305 }
2306
2307#ifndef MOONP_NO_MACRO
2308 void passOptions() {
2309 if (!_config.options.empty()) {
2310 pushMoonp("options"sv); // options
2311 for (const auto& option : _config.options) {
2312 lua_pushlstring(L, option.second.c_str(), option.second.size());
2313 lua_setfield(L, -2, option.first.c_str());
2314 }
2315 lua_pop(L, 1);
2316 }
2317 }
2318
2319 void pushCurrentModule() {
2320 if (_useModule) {
2321 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE
2322 lua_rawget(L, LUA_REGISTRYINDEX); // reg[MOONP_MODULE], tb
2323 int idx = static_cast<int>(lua_objlen(L, -1)); // idx = #tb, tb
2324 lua_rawgeti(L, -1, idx); // tb[idx], tb cur
2325 lua_remove(L, -2); // cur
2326 return;
2327 }
2328 _useModule = true;
2329 if (!L) {
2330 L = luaL_newstate();
2331 if (_luaOpen) {
2332 _luaOpen(static_cast<void*>(L));
2333 }
2334 passOptions();
2335 _stateOwner = true;
2336 }
2337 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE
2338 lua_rawget(L, LUA_REGISTRYINDEX); // reg[MOONP_MODULE], tb
2339 if (lua_isnil(L, -1) != 0) { // tb == nil
2340 lua_pop(L, 1);
2341 lua_newtable(L); // tb
2342 lua_pushliteral(L, MOONP_MODULE); // tb MOONP_MODULE
2343 lua_pushvalue(L, -2); // tb MOONP_MODULE tb
2344 lua_rawset(L, LUA_REGISTRYINDEX); // reg[MOONP_MODULE] = tb, tb
2345 } // tb
2346 int idx = static_cast<int>(lua_objlen(L, -1)); // idx = #tb, tb
2347 lua_newtable(L); // tb cur
2348 lua_pushvalue(L, -1); // tb cur cur
2349 lua_rawseti(L, -3, idx + 1); // tb[idx + 1] = cur, tb cur
2350 lua_remove(L, -2); // cur
2351 }
2352
2353 void pushMoonp(std::string_view name) {
2354 lua_getglobal(L, "package"); // package
2355 lua_getfield(L, -1, "loaded"); // package loaded
2356 lua_getfield(L, -1, "moonp"); // package loaded moonp
2357 lua_pushlstring(L, &name.front(), name.size()); // package loaded moonp name
2358 lua_gettable(L, -2); // loaded[name], package loaded moonp item
2359 lua_insert(L, -4); // item package loaded moonp
2360 lua_pop(L, 3); // item
2361 }
2362
2363 bool isModuleLoaded(std::string_view name) {
2364 int top = lua_gettop(L);
2365 DEFER(lua_settop(L, top));
2366 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE
2367 lua_rawget(L, LUA_REGISTRYINDEX); // modules
2368 lua_pushlstring(L, &name.front(), name.size());
2369 lua_rawget(L, -2); // modules module
2370 if (lua_isnil(L, -1) != 0) {
2371 return false;
2372 }
2373 return true;
2374 }
2375
2376 void pushModuleTable(std::string_view name) {
2377 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE
2378 lua_rawget(L, LUA_REGISTRYINDEX); // modules
2379 lua_pushlstring(L, &name.front(), name.size());
2380 lua_rawget(L, -2); // modules module
2381 if (lua_isnil(L, -1) != 0) {
2382 lua_pop(L, 1);
2383 lua_newtable(L); // modules module
2384 lua_pushlstring(L, &name.front(), name.size());
2385 lua_pushvalue(L, -2); // modules module name module
2386 lua_rawset(L, -4); // modules[name] = module, modules module
2387 }
2388 lua_remove(L, -2); // module
2389 }
2390
2391 void pushOptions(int lineOffset) {
2392 lua_newtable(L);
2393 lua_pushliteral(L, "lint_global");
2394 lua_pushboolean(L, 0);
2395 lua_rawset(L, -3);
2396 lua_pushliteral(L, "implicit_return_root");
2397 lua_pushboolean(L, 1);
2398 lua_rawset(L, -3);
2399 lua_pushliteral(L, "reserve_line_number");
2400 lua_pushboolean(L, 1);
2401 lua_rawset(L, -3);
2402 lua_pushliteral(L, "same_module");
2403 lua_pushboolean(L, 1);
2404 lua_rawset(L, -3);
2405 lua_pushliteral(L, "line_offset");
2406 lua_pushinteger(L, lineOffset);
2407 lua_rawset(L, -3);
2408 }
2409
2410 void transformMacro(Macro_t* macro, str_list& out, bool exporting) {
2411 if (_scopes.size() > 1) {
2412 throw std::logic_error(_info.errorMessage("can not define macro outside the root block"sv, macro));
2413 }
2414 auto macroName = _parser.toString(macro->name);
2415 auto argsDef = macro->macroLit->argsDef.get();
2416 str_list newArgs;
2417 if (argsDef) {
2418 for (auto def_ : argsDef->definitions.objects()) {
2419 auto def = static_cast<FnArgDef_t*>(def_);
2420 if (def->name.is<SelfName_t>()) {
2421 throw std::logic_error(_info.errorMessage("self name is not supported for macro function argument"sv, def->name));
2422 } else {
2423 std::string defVal;
2424 if (def->defaultValue) {
2425 defVal = _parser.toString(def->defaultValue);
2426 Utils::trim(defVal);
2427 defVal.insert(0, "=[==========["sv);
2428 defVal.append("]==========]"sv);
2429 }
2430 newArgs.emplace_back(_parser.toString(def->name) + defVal);
2431 }
2432 }
2433 if (argsDef->varArg) {
2434 newArgs.emplace_back(_parser.toString(argsDef->varArg));
2435 }
2436 }
2437 _buf << "("sv << join(newArgs, ","sv) << ")->"sv;
2438 _buf << _parser.toString(macro->macroLit->body);
2439 auto macroCodes = clearBuf();
2440 _buf << "=(macro "sv << macroName << ")";
2441 auto chunkName = clearBuf();
2442 pushCurrentModule(); // cur
2443 int top = lua_gettop(L) - 1;
2444 DEFER(lua_settop(L, top));
2445 pushMoonp("loadstring"sv); // cur loadstring
2446 lua_pushlstring(L, macroCodes.c_str(), macroCodes.size()); // cur loadstring codes
2447 lua_pushlstring(L, chunkName.c_str(), chunkName.size()); // cur loadstring codes chunk
2448 pushOptions(macro->m_begin.m_line - 1); // cur loadstring codes chunk options
2449 if (lua_pcall(L, 3, 2, 0) != 0) { // loadstring(codes,chunk,options), cur f err
2450 std::string err = lua_tostring(L, -1);
2451 throw std::logic_error(_info.errorMessage(s("failed to load macro codes\n"sv) + err, macro->macroLit));
2452 } // cur f err
2453 if (lua_isnil(L, -2) != 0) { // f == nil, cur f err
2454 std::string err = lua_tostring(L, -1);
2455 throw std::logic_error(_info.errorMessage(s("failed to load macro codes, at (macro "sv) + macroName + s("): "sv) + err, macro->macroLit));
2456 }
2457 lua_pop(L, 1); // cur f
2458 pushMoonp("pcall"sv); // cur f pcall
2459 lua_insert(L, -2); // cur pcall f
2460 if (lua_pcall(L, 1, 2, 0) != 0) { // f(), cur success macro
2461 std::string err = lua_tostring(L, -1);
2462 throw std::logic_error(_info.errorMessage(s("failed to generate macro function\n"sv) + err, macro->macroLit));
2463 } // cur success res
2464 if (lua_toboolean(L, -2) == 0) {
2465 std::string err = lua_tostring(L, -1);
2466 throw std::logic_error(_info.errorMessage(s("failed to generate macro function\n"sv) + err, macro->macroLit));
2467 } // cur true macro
2468 lua_remove(L, -2); // cur macro
2469 if (exporting && !_moduleName.empty()) {
2470 pushModuleTable(_moduleName); // cur macro module
2471 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name
2472 lua_pushvalue(L, -3); // cur macro module name macro
2473 lua_rawset(L, -3); // cur macro module
2474 lua_pop(L, 1);
2475 } // cur macro
2476 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro name
2477 lua_insert(L, -2); // cur name macro
2478 lua_rawset(L, -3); // cur[name] = macro, cur
2479 out.push_back(Empty);
2480 }
2481#else
2482 void transformMacro(Macro_t* macro, str_list&, bool) {
2483 throw std::logic_error(_info.errorMessage("macro feature not supported"sv, macro));
2484 }
2485#endif // MOONP_NO_MACRO
2486
2487 void transformReturn(Return_t* returnNode, str_list& out) {
2488 if (!_enableReturn.top()) {
2489 ast_node* target = returnNode->valueList.get();
2490 if (!target) target = returnNode;
2491 throw std::logic_error(_info.errorMessage("illegal return statement here"sv, target));
2492 }
2493 if (auto valueList = returnNode->valueList.get()) {
2494 if (valueList->exprs.size() == 1) {
2495 auto exp = static_cast<Exp_t*>(valueList->exprs.back());
2496 if (isPureBackcall(exp)) {
2497 transformExp(exp, out, ExpUsage::Return);
2498 return;
2499 }
2500 }
2501 if (auto singleValue = singleValueFrom(valueList)) {
2502 if (auto simpleValue = singleValue->item.as<SimpleValue_t>()) {
2503 auto value = simpleValue->value.get();
2504 switch (value->getId()) {
2505 case id<Comprehension_t>():
2506 transformComprehension(static_cast<Comprehension_t*>(value), out, ExpUsage::Return);
2507 return;
2508 case id<TblComprehension_t>():
2509 transformTblComprehension(static_cast<TblComprehension_t*>(value), out, ExpUsage::Return);
2510 return;
2511 case id<With_t>():
2512 transformWith(static_cast<With_t*>(value), out, nullptr, true);
2513 return;
2514 case id<ClassDecl_t>():
2515 transformClassDecl(static_cast<ClassDecl_t*>(value), out, ExpUsage::Return);
2516 return;
2517 case id<Do_t>():
2518 transformDo(static_cast<Do_t*>(value), out, ExpUsage::Return);
2519 return;
2520 case id<Switch_t>():
2521 transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Return);
2522 return;
2523 case id<While_t>():
2524 transformWhileInPlace(static_cast<While_t*>(value), out);
2525 return;
2526 case id<For_t>():
2527 transformForInPlace(static_cast<For_t*>(value), out);
2528 return;
2529 case id<ForEach_t>():
2530 transformForEachInPlace(static_cast<ForEach_t*>(value), out);
2531 return;
2532 case id<If_t>():
2533 transformIf(static_cast<If_t*>(value), out, ExpUsage::Return);
2534 return;
2535 case id<Unless_t>():
2536 transformUnless(static_cast<Unless_t*>(value), out, ExpUsage::Return);
2537 return;
2538 }
2539 } else if (auto chainValue = singleValue->item.as<ChainValue_t>()) {
2540 if (specialChainValue(chainValue) != ChainType::Common) {
2541 transformChainValue(chainValue, out, ExpUsage::Return, nullptr, returnNode->allowBlockMacroReturn);
2542 return;
2543 }
2544 }
2545 transformValue(singleValue, out);
2546 out.back() = indent() + s("return "sv) + out.back() + nlr(returnNode);
2547 return;
2548 } else {
2549 str_list temp;
2550 transformExpListLow(valueList, temp);
2551 out.push_back(indent() + s("return "sv) + temp.back() + nlr(returnNode));
2552 }
2553 } else {
2554 out.push_back(indent() + s("return"sv) + nll(returnNode));
2555 }
2556 }
2557
2558 void transformFnArgsDef(FnArgsDef_t* argsDef, str_list& out) {
2559 if (!argsDef->defList) {
2560 out.push_back(Empty);
2561 out.push_back(Empty);
2562 } else {
2563 transformFnArgDefList(argsDef->defList, out);
2564 }
2565 if (argsDef->shadowOption) {
2566 transform_outer_var_shadow(argsDef->shadowOption);
2567 }
2568 }
2569
2570 void transform_outer_var_shadow(outer_var_shadow_t* shadow) {
2571 markVarShadowed();
2572 if (shadow->varList) {
2573 for (auto name : shadow->varList->names.objects()) {
2574 addToAllowList(_parser.toString(name));
2575 }
2576 }
2577 }
2578
2579 void transformFnArgDefList(FnArgDefList_t* argDefList, str_list& out) {
2580 auto x = argDefList;
2581 struct ArgItem {
2582 std::string name;
2583 std::string assignSelf;
2584 };
2585 std::list<ArgItem> argItems;
2586 str_list temp;
2587 std::string varNames;
2588 bool assignSelf = false;
2589 for (auto _def : argDefList->definitions.objects()) {
2590 auto def = static_cast<FnArgDef_t*>(_def);
2591 auto& arg = argItems.emplace_back();
2592 switch (def->name->getId()) {
2593 case id<Variable_t>(): arg.name = _parser.toString(def->name); break;
2594 case id<SelfName_t>(): {
2595 assignSelf = true;
2596 auto selfName = static_cast<SelfName_t*>(def->name.get());
2597 switch (selfName->name->getId()) {
2598 case id<self_class_name_t>(): {
2599 auto clsName = static_cast<self_class_name_t*>(selfName->name.get());
2600 arg.name = _parser.toString(clsName->name);
2601 arg.assignSelf = s("self.__class."sv) + arg.name;
2602 break;
2603 }
2604 case id<self_class_t>():
2605 arg.name = "self.__class"sv;
2606 break;
2607 case id<self_name_t>(): {
2608 auto sfName = static_cast<self_name_t*>(selfName->name.get());
2609 arg.name = _parser.toString(sfName->name);
2610 arg.assignSelf = s("self."sv) + arg.name;
2611 break;
2612 }
2613 case id<self_t>():
2614 arg.name = "self"sv;
2615 break;
2616 default: assert(false); break;
2617 }
2618 break;
2619 }
2620 default: assert(false); break;
2621 }
2622 forceAddToScope(arg.name);
2623 if (def->defaultValue) {
2624 pushScope();
2625 auto expList = toAst<ExpList_t>(arg.name, x);
2626 auto assign = x->new_ptr<Assign_t>();
2627 assign->values.push_back(def->defaultValue.get());
2628 auto assignment = x->new_ptr<ExpListAssign_t>();
2629 assignment->expList.set(expList);
2630 assignment->action.set(assign);
2631 transformAssignment(assignment, temp);
2632 popScope();
2633 _buf << indent() << "if "sv << arg.name << " == nil then"sv << nll(def);
2634 _buf << temp.back();
2635 _buf << indent() << "end"sv << nll(def);
2636 temp.back() = clearBuf();
2637 }
2638 if (varNames.empty()) varNames = arg.name;
2639 else varNames.append(s(", "sv) + arg.name);
2640 }
2641 if (argDefList->varArg) {
2642 auto& arg = argItems.emplace_back();
2643 arg.name = "..."sv;
2644 if (varNames.empty()) varNames = arg.name;
2645 else varNames.append(s(", "sv) + arg.name);
2646 _varArgs.top() = true;
2647 }
2648 std::string initCodes = join(temp);
2649 if (assignSelf) {
2650 auto sjoin = [](const decltype(argItems)& items, int index) {
2651 std::string result;
2652 for (auto it = items.begin(); it != items.end(); ++it) {
2653 if (it->assignSelf.empty()) continue;
2654 if (result.empty()) result = (&it->name)[index];
2655 else result.append(s(", "sv) + (&it->name)[index]);
2656 }
2657 return result;
2658 };
2659 std::string sleft = sjoin(argItems, 1);
2660 std::string sright = sjoin(argItems, 0);
2661 initCodes.append(indent() + sleft + s(" = "sv) + sright + nll(argDefList));
2662 }
2663 out.push_back(varNames);
2664 out.push_back(initCodes);
2665 }
2666
2667 void transformSelfName(SelfName_t* selfName, str_list& out, const ast_sel<false,Invoke_t,InvokeArgs_t>& invoke = {}) {
2668 auto x = selfName;
2669 auto name = selfName->name.get();
2670 switch (name->getId()) {
2671 case id<self_class_name_t>(): {
2672 auto clsName = static_cast<self_class_name_t*>(name);
2673 auto nameStr = _parser.toString(clsName->name);
2674 if (LuaKeywords.find(nameStr) != LuaKeywords.end()) {
2675 out.push_back(s("self.__class[\""sv) + nameStr + s("\"]"sv));
2676 if (invoke) {
2677 if (auto invokePtr = invoke.as<Invoke_t>()) {
2678 invokePtr->args.push_front(toAst<Exp_t>("self.__class"sv, x));
2679 } else {
2680 auto invokeArgsPtr = invoke.as<InvokeArgs_t>();
2681 invokeArgsPtr->args.push_front(toAst<Exp_t>("self.__class"sv, x));
2682 }
2683 }
2684 } else {
2685 out.push_back(s("self.__class"sv) + s(invoke ? ":"sv : "."sv) + nameStr);
2686 }
2687 break;
2688 }
2689 case id<self_class_t>():
2690 out.push_back(s("self.__class"sv));
2691 break;
2692 case id<self_name_t>(): {
2693 auto sfName = static_cast<self_class_name_t*>(name);
2694 auto nameStr = _parser.toString(sfName->name);
2695 if (LuaKeywords.find(nameStr) != LuaKeywords.end()) {
2696 out.push_back(s("self[\""sv) + nameStr + s("\"]"sv));
2697 if (invoke) {
2698 if (auto invokePtr = invoke.as<Invoke_t>()) {
2699 invokePtr->args.push_front(toAst<Exp_t>("self"sv, x));
2700 } else {
2701 auto invokeArgsPtr = invoke.as<InvokeArgs_t>();
2702 invokeArgsPtr->args.push_front(toAst<Exp_t>("self"sv, x));
2703 }
2704 }
2705 } else {
2706 out.push_back(s("self"sv) + s(invoke ? ":"sv : "."sv) + nameStr);
2707 }
2708 break;
2709 }
2710 case id<self_t>():
2711 out.push_back(s("self"sv));
2712 break;
2713 default: assert(false); break;
2714 }
2715 }
2716
2717 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
2718 auto x = chainList.front();
2719 if (ast_is<existential_op_t>(chainList.back())) {
2720 auto parens = x->new_ptr<Parens_t>();
2721 {
2722 auto chainValue = x->new_ptr<ChainValue_t>();
2723 for (auto item : chainList) {
2724 chainValue->items.push_back(item);
2725 }
2726 chainValue->items.pop_back();
2727 auto value = x->new_ptr<Value_t>();
2728 value->item.set(chainValue);
2729 auto exp = newExp(value, toAst<BinaryOperator_t>("!="sv, x), toAst<Value_t>("nil"sv, x), x);
2730 parens->expr.set(exp);
2731 }
2732 switch (usage) {
2733 case ExpUsage::Assignment: {
2734 auto callable = x->new_ptr<Callable_t>();
2735 callable->item.set(parens);
2736 auto chainValue = x->new_ptr<ChainValue_t>();
2737 chainValue->items.push_back(callable);
2738 auto value = x->new_ptr<Value_t>();
2739 value->item.set(chainValue);
2740 auto exp = newExp(value, x);
2741 auto assignment = x->new_ptr<ExpListAssign_t>();
2742 assignment->expList.set(assignList);
2743 auto assign = x->new_ptr<Assign_t>();
2744 assign->values.push_back(exp);
2745 assignment->action.set(assign);
2746 transformAssignment(assignment, out);
2747 break;
2748 }
2749 case ExpUsage::Return:
2750 transformParens(parens, out);
2751 out.back().insert(0, indent() + s("return "sv));
2752 out.back().append(nlr(x));
2753 break;
2754 default:
2755 transformParens(parens, out);
2756 break;
2757 }
2758 return true;
2759 }
2760 return false;
2761 }
2762
2763 bool transformChainWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
2764 auto opIt = std::find_if(chainList.begin(), chainList.end(), [](ast_node* node) { return ast_is<existential_op_t>(node); });
2765 if (opIt != chainList.end()) {
2766 auto x = chainList.front();
2767 str_list temp;
2768 if (usage == ExpUsage::Closure) {
2769 temp.push_back(s("(function()"sv) + nll(x));
2770 pushScope();
2771 _enableReturn.push(true);
2772 }
2773 auto partOne = x->new_ptr<ChainValue_t>();
2774 for (auto it = chainList.begin();it != opIt;++it) {
2775 partOne->items.push_back(*it);
2776 }
2777 BLOCK_START
2778 auto back = ast_cast<Callable_t>(partOne->items.back());
2779 BREAK_IF(!back);
2780 auto selfName = ast_cast<SelfName_t>(back->item);
2781 BREAK_IF(!selfName);
2782 if (auto sname = ast_cast<self_name_t>(selfName->name)) {
2783 auto colonItem = x->new_ptr<ColonChainItem_t>();
2784 colonItem->name.set(sname->name);
2785 partOne->items.pop_back();
2786 partOne->items.push_back(toAst<Callable_t>("@"sv, x));
2787 partOne->items.push_back(colonItem);
2788 break;
2789 }
2790 if (auto cname = ast_cast<self_class_name_t>(selfName->name)) {
2791 auto colonItem = x->new_ptr<ColonChainItem_t>();
2792 colonItem->name.set(cname->name);
2793 partOne->items.pop_back();
2794 partOne->items.push_back(toAst<Callable_t>("@@"sv, x));
2795 partOne->items.push_back(colonItem);
2796 break;
2797 }
2798 BLOCK_END
2799 auto objVar = singleVariableFrom(partOne);
2800 if (objVar.empty()) {
2801 objVar = getUnusedName("_obj_"sv);
2802 if (auto colonItem = ast_cast<ColonChainItem_t>(partOne->items.back())) {
2803 auto chainValue = x->new_ptr<ChainValue_t>();
2804 chainValue->items.dup(partOne->items);
2805 chainValue->items.pop_back();
2806 if (chainValue->items.empty()) {
2807 if (_withVars.empty()) {
2808 throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x));
2809 }
2810 chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), x));
2811 }
2812 auto newObj = singleVariableFrom(chainValue);
2813 if (!newObj.empty()) {
2814 objVar = newObj;
2815 } else {
2816 auto value = x->new_ptr<Value_t>();
2817 value->item.set(chainValue);
2818 auto exp = newExp(value, x);
2819 auto assign = x->new_ptr<Assign_t>();
2820 assign->values.push_back(exp);
2821 auto expListAssign = x->new_ptr<ExpListAssign_t>();
2822 expListAssign->expList.set(toAst<ExpList_t>(objVar, x));
2823 expListAssign->action.set(assign);
2824 transformAssignment(expListAssign, temp);
2825 }
2826 auto dotItem = x->new_ptr<DotChainItem_t>();
2827 auto name = colonItem->name.get();
2828 if (auto keyword = ast_cast<LuaKeyword_t>(name)) {
2829 name = keyword->name.get();
2830 }
2831 dotItem->name.set(name);
2832 partOne->items.clear();
2833 partOne->items.push_back(toAst<Callable_t>(objVar, x));
2834 partOne->items.push_back(dotItem);
2835 auto it = opIt; ++it;
2836 if (it != chainList.end() && ast_is<Invoke_t, InvokeArgs_t>(*it)) {
2837
2838 if (auto invoke = ast_cast<Invoke_t>(*it)) {
2839 invoke->args.push_front(toAst<Exp_t>(objVar, x));
2840 } else {
2841 auto invokeArgs = static_cast<InvokeArgs_t*>(*it);
2842 invokeArgs->args.push_front(toAst<Exp_t>(objVar, x));
2843 }
2844 }
2845 objVar = getUnusedName("_obj_"sv);
2846 }
2847 auto value = x->new_ptr<Value_t>();
2848 value->item.set(partOne);
2849 auto exp = newExp(value, x);
2850 auto assign = x->new_ptr<Assign_t>();
2851 assign->values.push_back(exp);
2852 auto expListAssign = x->new_ptr<ExpListAssign_t>();
2853 expListAssign->expList.set(toAst<ExpList_t>(objVar, x));
2854 expListAssign->action.set(assign);
2855 transformAssignment(expListAssign, temp);
2856 }
2857 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x);
2858 temp.push_back(clearBuf());
2859 pushScope();
2860 auto partTwo = x->new_ptr<ChainValue_t>();
2861 partTwo->items.push_back(toAst<Callable_t>(objVar, x));
2862 for (auto it = ++opIt;it != chainList.end();++it) {
2863 partTwo->items.push_back(*it);
2864 }
2865 switch (usage) {
2866 case ExpUsage::Common:
2867 transformChainValue(partTwo, temp, ExpUsage::Common);
2868 break;
2869 case ExpUsage::Assignment: {
2870 auto value = x->new_ptr<Value_t>();
2871 value->item.set(partTwo);
2872 auto exp = newExp(value, x);
2873 auto assign = x->new_ptr<Assign_t>();
2874 assign->values.push_back(exp);
2875 auto assignment = x->new_ptr<ExpListAssign_t>();
2876 assignment->expList.set(assignList);
2877 assignment->action.set(assign);
2878 transformAssignment(assignment, temp);
2879 break;
2880 }
2881 case ExpUsage::Return:
2882 case ExpUsage::Closure: {
2883 auto value = x->new_ptr<Value_t>();
2884 value->item.set(partTwo);
2885 auto exp = newExp(value, x);
2886 auto ret = x->new_ptr<Return_t>();
2887 auto expListLow = x->new_ptr<ExpListLow_t>();
2888 expListLow->exprs.push_back(exp);
2889 ret->valueList.set(expListLow);
2890 transformReturn(ret, temp);
2891 break;
2892 }
2893 }
2894 popScope();
2895 temp.push_back(indent() + s("end"sv) + nlr(x));
2896 switch (usage) {
2897 case ExpUsage::Return:
2898 temp.push_back(indent() + s("return nil"sv) + nlr(x));
2899 break;
2900 case ExpUsage::Closure:
2901 temp.push_back(indent() + s("return nil"sv) + nlr(x));
2902 _enableReturn.pop();
2903 popScope();
2904 temp.push_back(indent() + s("end)()"sv));
2905 break;
2906 default:
2907 break;
2908 }
2909 out.push_back(join(temp));
2910 return true;
2911 }
2912 return false;
2913 }
2914
2915 bool transformChainEndWithColonItem(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
2916 if (ast_is<ColonChainItem_t>(chainList.back())) {
2917 auto x = chainList.front();
2918 str_list temp;
2919 switch (usage) {
2920 case ExpUsage::Assignment:
2921 temp.push_back(indent() + s("do"sv) + nll(x));
2922 pushScope();
2923 break;
2924 case ExpUsage::Closure:
2925 temp.push_back(s("(function()"sv) + nll(x));
2926 pushScope();
2927 _enableReturn.push(true);
2928 break;
2929 default:
2930 break;
2931 }
2932 auto baseChain = x->new_ptr<ChainValue_t>();
2933 switch (chainList.front()->getId()) {
2934 case id<DotChainItem_t>():
2935 case id<ColonChainItem_t>():
2936 if (_withVars.empty()) {
2937 throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, chainList.front()));
2938 } else {
2939 baseChain->items.push_back(toAst<Callable_t>(_withVars.top(), x));
2940 }
2941 break;
2942 }
2943 auto end = --chainList.end();
2944 for (auto it = chainList.begin(); it != end; ++it) {
2945 baseChain->items.push_back(*it);
2946 }
2947 auto colonChainItem = static_cast<ColonChainItem_t*>(chainList.back());
2948 auto funcName = _parser.toString(colonChainItem->name);
2949 auto baseVar = getUnusedName("_base_"sv);
2950 auto fnVar = getUnusedName("_fn_"sv);
2951 {
2952 auto value = x->new_ptr<Value_t>();
2953 value->item.set(baseChain);
2954 auto exp = newExp(value, x);
2955 auto assign = x->new_ptr<Assign_t>();
2956 assign->values.push_back(exp);
2957 auto assignment = x->new_ptr<ExpListAssign_t>();
2958 assignment->expList.set(toAst<ExpList_t>(baseVar, x));
2959 assignment->action.set(assign);
2960 transformAssignment(assignment, temp);
2961 }
2962 {
2963 auto assign = x->new_ptr<Assign_t>();
2964 assign->values.push_back(toAst<Exp_t>(baseVar + "." + funcName, x));
2965 auto assignment = x->new_ptr<ExpListAssign_t>();
2966 assignment->expList.set(toAst<ExpList_t>(fnVar, x));
2967 assignment->action.set(assign);
2968 transformAssignment(assignment, temp);
2969 }
2970 auto funLit = toAst<Exp_t>(fnVar + s(" and (...)-> "sv) + fnVar + s(" "sv) + baseVar + s(", ..."sv), x);
2971 switch (usage) {
2972 case ExpUsage::Closure:
2973 case ExpUsage::Return: {
2974 auto returnNode = x->new_ptr<Return_t>();
2975 auto expListLow = x->new_ptr<ExpListLow_t>();
2976 expListLow->exprs.push_back(funLit);
2977 returnNode->valueList.set(expListLow);
2978 transformReturn(returnNode, temp);
2979 break;
2980 }
2981 case ExpUsage::Assignment: {
2982 auto assign = x->new_ptr<Assign_t>();
2983 assign->values.push_back(funLit);
2984 auto assignment = x->new_ptr<ExpListAssign_t>();
2985 assignment->expList.set(assignList);
2986 assignment->action.set(assign);
2987 transformAssignment(assignment, temp);
2988 break;
2989 }
2990 default:
2991 break;
2992 }
2993 switch (usage) {
2994 case ExpUsage::Assignment:
2995 popScope();
2996 temp.push_back(indent() + s("end"sv) + nlr(x));
2997 break;
2998 case ExpUsage::Closure:
2999 _enableReturn.pop();
3000 popScope();
3001 temp.push_back(indent() + s("end)()"sv));
3002 break;
3003 default:
3004 break;
3005 }
3006 out.push_back(join(temp));
3007 return true;
3008 }
3009 return false;
3010 }
3011
3012 void transformChainList(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
3013 auto x = chainList.front();
3014 str_list temp;
3015 switch (x->getId()) {
3016 case id<DotChainItem_t>():
3017 case id<ColonChainItem_t>():
3018 if (_withVars.empty()) {
3019 throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x));
3020 } else {
3021 temp.push_back(_withVars.top());
3022 }
3023 break;
3024 }
3025 for (auto it = chainList.begin(); it != chainList.end(); ++it) {
3026 auto item = *it;
3027 switch (item->getId()) {
3028 case id<Invoke_t>():
3029 transformInvoke(static_cast<Invoke_t*>(item), temp);
3030 break;
3031 case id<DotChainItem_t>():
3032 transformDotChainItem(static_cast<DotChainItem_t*>(item), temp);
3033 break;
3034 case id<ColonChainItem_t>(): {
3035 auto colonItem = static_cast<ColonChainItem_t*>(item);
3036 auto current = it;
3037 auto next = current; ++next;
3038 auto followItem = next != chainList.end() ? *next : nullptr;
3039 if (current != chainList.begin()) {
3040 --current;
3041 if (!ast_is<existential_op_t>(*current)) {
3042 ++current;
3043 }
3044 }
3045 if (ast_is<existential_op_t>(followItem)) {
3046 ++next;
3047 followItem = next != chainList.end() ? *next : nullptr;
3048 --next;
3049 }
3050 if (!ast_is<Invoke_t, InvokeArgs_t>(followItem)) {
3051 throw std::logic_error(_info.errorMessage("colon chain item must be followed by invoke arguments"sv, colonItem));
3052 }
3053 if (colonItem->name.is<LuaKeyword_t>()) {
3054 std::string callVar;
3055 auto block = x->new_ptr<Block_t>();
3056 {
3057 auto chainValue = x->new_ptr<ChainValue_t>();
3058 switch (chainList.front()->getId()) {
3059 case id<DotChainItem_t>():
3060 case id<ColonChainItem_t>():
3061 chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), x));
3062 break;
3063 }
3064 for (auto i = chainList.begin(); i != current; ++i) {
3065 chainValue->items.push_back(*i);
3066 }
3067 auto value = x->new_ptr<Value_t>();
3068 value->item.set(chainValue);
3069 auto exp = newExp(value, x);
3070 callVar = singleVariableFrom(exp);
3071 if (callVar.empty()) {
3072 callVar = getUnusedName(s("_call_"sv));
3073 auto assignment = x->new_ptr<ExpListAssign_t>();
3074 assignment->expList.set(toAst<ExpList_t>(callVar, x));
3075 auto assign = x->new_ptr<Assign_t>();
3076 assign->values.push_back(exp);
3077 assignment->action.set(assign);
3078 auto stmt = x->new_ptr<Statement_t>();
3079 stmt->content.set(assignment);
3080 block->statements.push_back(stmt);
3081 }
3082 }
3083 ast_ptr<false, Exp_t> nexp;
3084 {
3085 auto name = _parser.toString(colonItem->name);
3086 auto chainValue = x->new_ptr<ChainValue_t>();
3087 chainValue->items.push_back(toAst<Callable_t>(callVar, x));
3088 if (ast_is<existential_op_t>(*current)) {
3089 chainValue->items.push_back(x->new_ptr<existential_op_t>());
3090 }
3091 chainValue->items.push_back(toAst<Exp_t>(s("\""sv) + name + s("\""sv), x));
3092 if (auto invoke = ast_cast<Invoke_t>(followItem)) {
3093 invoke->args.push_front(toAst<Exp_t>(callVar, x));
3094 } else {
3095 auto invokeArgs = static_cast<InvokeArgs_t*>(followItem);
3096 invokeArgs->args.push_front(toAst<Exp_t>(callVar, x));
3097 }
3098 for (auto i = next; i != chainList.end(); ++i) {
3099 chainValue->items.push_back(*i);
3100 }
3101 auto value = x->new_ptr<Value_t>();
3102 value->item.set(chainValue);
3103 nexp = newExp(value, x);
3104 auto expList = x->new_ptr<ExpList_t>();
3105 expList->exprs.push_back(nexp);
3106 auto expListAssign = x->new_ptr<ExpListAssign_t>();
3107 expListAssign->expList.set(expList);
3108 auto stmt = x->new_ptr<Statement_t>();
3109 stmt->content.set(expListAssign);
3110 block->statements.push_back(stmt);
3111 }
3112 switch (usage) {
3113 case ExpUsage::Common:
3114 case ExpUsage::Return:
3115 transformBlock(block, out, usage);
3116 return;
3117 case ExpUsage::Assignment: {
3118 transformBlock(block, out, ExpUsage::Assignment, assignList);
3119 return;
3120 }
3121 default:
3122 break;
3123 }
3124 if (block->statements.size() == 1) {
3125 transformExp(nexp, out, usage, assignList);
3126 } else {
3127 auto body = x->new_ptr<Body_t>();
3128 body->content.set(block);
3129 auto funLit = toAst<FunLit_t>("->"sv, x);
3130 funLit->body.set(body);
3131 auto simpleValue = x->new_ptr<SimpleValue_t>();
3132 simpleValue->value.set(funLit);
3133 auto value = x->new_ptr<Value_t>();
3134 value->item.set(simpleValue);
3135 auto exp = newExp(value, x);
3136 auto paren = x->new_ptr<Parens_t>();
3137 paren->expr.set(exp);
3138 auto callable = x->new_ptr<Callable_t>();
3139 callable->item.set(paren);
3140 auto chainValue = x->new_ptr<ChainValue_t>();
3141 chainValue->items.push_back(callable);
3142 auto invoke = x->new_ptr<Invoke_t>();
3143 chainValue->items.push_back(invoke);
3144 transformChainValue(chainValue, out, ExpUsage::Closure);
3145 }
3146 return;
3147 }
3148 transformColonChainItem(colonItem, temp);
3149 break;
3150 }
3151 case id<Slice_t>():
3152 transformSlice(static_cast<Slice_t*>(item), temp);
3153 break;
3154 case id<Callable_t>(): {
3155 auto next = it; ++next;
3156 auto followItem = next != chainList.end() ? *next : nullptr;
3157 ast_sel<false, Invoke_t, InvokeArgs_t> invoke;
3158 if (ast_is<Invoke_t, InvokeArgs_t>(followItem)) {
3159 invoke.set(followItem);
3160 }
3161 transformCallable(static_cast<Callable_t*>(item), temp, invoke);
3162 break;
3163 }
3164 case id<String_t>():
3165 transformString(static_cast<String_t*>(item), temp);
3166 temp.back() = s("("sv) + temp.back() + s(")"sv);
3167 break;
3168 case id<Exp_t>():
3169 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
3170 temp.back() = s(temp.back().front() == '[' ? "[ "sv : "["sv) + temp.back() + s("]"sv);
3171 break;
3172 case id<InvokeArgs_t>(): transformInvokeArgs(static_cast<InvokeArgs_t*>(item), temp); break;
3173 default: assert(false); break;
3174 }
3175 }
3176 switch (usage) {
3177 case ExpUsage::Common:
3178 out.push_back(indent() + join(temp) + nll(chainList.front()));
3179 break;
3180 case ExpUsage::Return:
3181 out.push_back(indent() + s("return "sv) + join(temp) + nll(chainList.front()));
3182 break;
3183 case ExpUsage::Assignment: assert(false); break;
3184 default:
3185 out.push_back(join(temp));
3186 break;
3187 }
3188 }
3189
3190#ifndef MOONP_NO_MACRO
3191 std::tuple<std::string,std::string,str_list> expandMacroStr(ChainValue_t* chainValue) {
3192 const auto& chainList = chainValue->items.objects();
3193 auto x = ast_to<Callable_t>(chainList.front())->item.to<MacroName_t>();
3194 auto macroName = x->name ? _parser.toString(x->name) : Empty;
3195 if (!macroName.empty() && !_useModule) {
3196 throw std::logic_error(_info.errorMessage("can not resolve macro"sv, x));
3197 }
3198 pushCurrentModule(); // cur
3199 int top = lua_gettop(L) - 1;
3200 DEFER(lua_settop(L, top));
3201 if (macroName.empty()) {
3202 lua_pop(L, 1); // empty
3203 auto item = *(++chainList.begin());
3204 const node_container* args = nullptr;
3205 if (auto invoke = ast_cast<Invoke_t>(item)) {
3206 args = &invoke->args.objects();
3207 } else {
3208 args = &ast_to<InvokeArgs_t>(item)->args.objects();
3209 }
3210 if (args->size() != 1) {
3211 throw std::logic_error(_info.errorMessage("in-place macro must be followed by a compile time function"sv, x));
3212 }
3213 auto fcodes = _parser.toString(args->back());
3214 Utils::trim(fcodes);
3215 pushMoonp("loadstring"sv); // loadstring
3216 lua_pushlstring(L, fcodes.c_str(), fcodes.size()); // loadstring codes
3217 lua_pushliteral(L, "=(macro in-place)"); // loadstring codes chunk
3218 pushOptions(args->back()->m_begin.m_line - 1); // loadstring codes chunk options
3219 if (lua_pcall(L, 3, 2, 0) != 0) { // loadstring(codes,chunk,options), f err
3220 std::string err = lua_tostring(L, -1);
3221 throw std::logic_error(_info.errorMessage(s("failed to load macro codes\n"sv) + err, x));
3222 } // f err
3223 if (lua_isnil(L, -2) != 0) { // f == nil, f err
3224 std::string err = lua_tostring(L, -1);
3225 throw std::logic_error(_info.errorMessage(s("failed to load macro codes, at (macro in-place): "sv) + err, x));
3226 }
3227 lua_pop(L, 1); // f
3228 pushMoonp("pcall"sv); // f pcall
3229 lua_insert(L, -2); // pcall f
3230 if (lua_pcall(L, 1, 2, 0) != 0) { // f(), success macroFunc
3231 std::string err = lua_tostring(L, -1);
3232 throw std::logic_error(_info.errorMessage(s("failed to generate macro function\n"sv) + err, x));
3233 } // success res
3234 if (lua_toboolean(L, -2) == 0) {
3235 std::string err = lua_tostring(L, -1);
3236 throw std::logic_error(_info.errorMessage(s("failed to generate macro function\n"sv) + err, x));
3237 } // true macroFunc
3238 lua_remove(L, -2); // macroFunc
3239 pushMoonp("pcall"sv); // macroFunc pcall
3240 lua_insert(L, -2); // pcall macroFunc
3241 bool success = lua_pcall(L, 1, 2, 0) == 0;
3242 if (!success) { // err
3243 std::string err = lua_tostring(L, -1);
3244 throw std::logic_error(_info.errorMessage(s("failed to expand macro: "sv) + err, x));
3245 } // success err
3246 if (lua_toboolean(L, -2) == 0) {
3247 std::string err = lua_tostring(L, -1);
3248 throw std::logic_error(_info.errorMessage(s("failed to expand macro: "sv) + err, x));
3249 }
3250 return {Empty, Empty, {}};
3251 }
3252 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macroName
3253 lua_rawget(L, -2); // cur[macroName], cur macroFunc
3254 if (lua_isfunction(L, -1) == 0) {
3255 throw std::logic_error(_info.errorMessage("can not resolve macro"sv, x));
3256 } // cur macroFunc
3257 pushMoonp("pcall"sv); // cur macroFunc pcall
3258 lua_insert(L, -2); // cur pcall macroFunc
3259 auto item = *(++chainList.begin());
3260 const node_container* args = nullptr;
3261 if (auto invoke = ast_cast<Invoke_t>(item)) {
3262 args = &invoke->args.objects();
3263 } else {
3264 args = &ast_to<InvokeArgs_t>(item)->args.objects();
3265 }
3266 for (auto arg : *args) {
3267 std::string str;
3268 // check whether arg is reassembled
3269 // do some workaround for backcall expression
3270 if (ast_is<Exp_t>(arg) && arg->m_begin.m_it == arg->m_end.m_it) {
3271 auto exp = static_cast<Exp_t*>(arg);
3272 BLOCK_START
3273 BREAK_IF(!exp->opValues.empty());
3274 auto chainValue = exp->getByPath<unary_exp_t, Value_t, ChainValue_t>();
3275 BREAK_IF(!chainValue);
3276 BREAK_IF(!isMacroChain(chainValue));
3277 BREAK_IF(chainValue->items.size() != 2);
3278 str = std::get<1>(expandMacroStr(chainValue));
3279 BLOCK_END
3280 if (str.empty()) {
3281 // exp is reassembled due to backcall expressions
3282 // in transform stage, toString(exp) won't be able
3283 // to convert its whole text content
3284 str = _parser.toString(exp->backcalls.front());
3285 }
3286 } else if (auto lstr = ast_cast<LuaString_t>(arg)) {
3287 str = _parser.toString(lstr->content);
3288 } else {
3289 bool multiLineStr = false;
3290 BLOCK_START
3291 auto exp = ast_cast<Exp_t>(arg);
3292 BREAK_IF(!exp);
3293 auto value = singleValueFrom(exp);
3294 BREAK_IF(!value);
3295 auto lstr = value->getByPath<String_t, LuaString_t>();
3296 BREAK_IF(!lstr);
3297 str = _parser.toString(lstr->content);
3298 multiLineStr = true;
3299 BLOCK_END
3300 if (!multiLineStr) {
3301 str = _parser.toString(arg);
3302 }
3303 }
3304 Utils::trim(str);
3305 Utils::replace(str, "\r\n"sv, "\n"sv);
3306 lua_pushlstring(L, str.c_str(), str.size());
3307 } // cur pcall macroFunc args...
3308 bool success = lua_pcall(L, static_cast<int>(args->size()) + 1, 2, 0) == 0;
3309 if (!success) { // cur err
3310 std::string err = lua_tostring(L, -1);
3311 throw std::logic_error(_info.errorMessage(s("failed to expand macro: "sv) + err, x));
3312 } // cur success res
3313 if (lua_toboolean(L, -2) == 0) {
3314 std::string err = lua_tostring(L, -2);
3315 throw std::logic_error(_info.errorMessage(s("failed to expand macro: "sv) + err, x));
3316 }
3317 lua_remove(L, -2); // cur res
3318 if (lua_isstring(L, -1) == 0 && lua_istable(L, -1) == 0) {
3319 throw std::logic_error(_info.errorMessage(s("macro function must return string or table"sv), x));
3320 } // cur res
3321 std::string codes;
3322 std::string type;
3323 str_list localVars;
3324 if (lua_istable(L, -1) != 0) {
3325 lua_getfield(L, -1, "codes"); // cur res codes
3326 if (lua_isstring(L, -1) != 0) {
3327 codes = lua_tostring(L, -1);
3328 } else {
3329 throw std::logic_error(_info.errorMessage(s("macro table must contain field \"codes\" of string"sv), x));
3330 }
3331 lua_pop(L, 1); // cur res
3332 lua_getfield(L, -1, "type"); // cur res type
3333 if (lua_isstring(L, -1) != 0) {
3334 type = lua_tostring(L, -1);
3335 }
3336 if (type != "lua"sv && type != "text"sv) {
3337 throw std::logic_error(_info.errorMessage(s("macro table must contain field \"type\" of value \"lua\" or \"text\""sv), x));
3338 }
3339 lua_pop(L, 1); // cur res
3340 lua_getfield(L, -1, "locals"); // cur res locals
3341 if (lua_istable(L, -1) != 0) {
3342 for (int i = 0; i < static_cast<int>(lua_objlen(L, -1)); i++) {
3343 lua_rawgeti(L, -1, i + 1); // cur res locals item
3344 size_t len = 0;
3345 if (lua_isstring(L, -1) == 0) {
3346 throw std::logic_error(_info.errorMessage(s("macro table field \"locals\" must be a table of strings"sv), x));
3347 }
3348 auto name = lua_tolstring(L, -1, &len);
3349 if (_parser.match<Variable_t>({name, len})) {
3350 localVars.push_back(std::string(name, len));
3351 } else {
3352 throw std::logic_error(_info.errorMessage(s("macro table field \"locals\" must contain names for local variables, got \""sv) + std::string(name, len) + '"', x));
3353 }
3354 lua_pop(L, 1);
3355 }
3356 }
3357 lua_pop(L, 1); // cur res
3358 } else {
3359 codes = lua_tostring(L, -1);
3360 }
3361 return {type, codes, std::move(localVars)};
3362 }
3363
3364 std::tuple<ast_ptr<false,ast_node>, std::unique_ptr<input>, std::string, str_list> expandMacro(ChainValue_t* chainValue, ExpUsage usage, bool allowBlockMacroReturn) {
3365 auto x = ast_to<Callable_t>(chainValue->items.front())->item.to<MacroName_t>();
3366 const auto& chainList = chainValue->items.objects();
3367 std::string type, codes;
3368 str_list localVars;
3369 std::tie(type, codes, localVars) = expandMacroStr(chainValue);
3370 bool isBlock = (usage == ExpUsage::Common) && (chainList.size() <= 2);
3371 ParseInfo info;
3372 if (type == "lua"sv) {
3373 if (!isBlock) {
3374 throw std::logic_error(_info.errorMessage("lua macro can only be placed where block macro is allowed"sv, x));
3375 }
3376 auto macroChunk = s("=(macro "sv) + _parser.toString(x->name) + ')';
3377 int top = lua_gettop(L);
3378 DEFER(lua_settop(L, top));
3379 if (luaL_loadbuffer(L, codes.c_str(), codes.size(), macroChunk.c_str()) != 0) {
3380 std::string err = lua_tostring(L, -1);
3381 throw std::logic_error(_info.errorMessage(err, x));
3382 }
3383 return {nullptr, nullptr, std::move(codes), std::move(localVars)};
3384 } else if (type == "text"sv) {
3385 if (!isBlock) {
3386 throw std::logic_error(_info.errorMessage("text macro can only be placed where block macro is allowed"sv, x));
3387 }
3388 return {nullptr, nullptr, std::move(codes), std::move(localVars)};
3389 } else {
3390 if (!codes.empty()) {
3391 if (isBlock) {
3392 info = _parser.parse<Block_t>(codes);
3393 if (!info.node) {
3394 info.error = info.error.substr(info.error.find(':') + 2);
3395 throw std::logic_error(_info.errorMessage(s("failed to expanded macro as block: "sv) + info.error, x));
3396 }
3397 } else {
3398 info = _parser.parse<Exp_t>(codes);
3399 if (!info.node && allowBlockMacroReturn) {
3400 info = _parser.parse<Block_t>(codes);
3401 if (!info.node) {
3402 info.error = info.error.substr(info.error.find(':') + 2);
3403 throw std::logic_error(_info.errorMessage(s("failed to expanded macro as expr or block: "sv) + info.error, x));
3404 }
3405 isBlock = true;
3406 } else if (!info.node) {
3407 info.error = info.error.substr(info.error.find(':') + 2);
3408 throw std::logic_error(_info.errorMessage(s("failed to expanded macro as expr: "sv) + info.error, x));
3409 }
3410 }
3411 int line = x->m_begin.m_line;
3412 int col = x->m_begin.m_col;
3413 info.node->traverse([&](ast_node* node) {
3414 node->m_begin.m_line = line;
3415 node->m_end.m_line = line;
3416 node->m_begin.m_col = col;
3417 node->m_end.m_col = col;
3418 return traversal::Continue;
3419 });
3420 if (!isBlock) {
3421 ast_ptr<false, Exp_t> exp;
3422 exp.set(info.node);
3423 if (!exp->opValues.empty() || chainList.size() > 2) {
3424 auto paren = x->new_ptr<Parens_t>();
3425 paren->expr.set(exp);
3426 auto callable = x->new_ptr<Callable_t>();
3427 callable->item.set(paren);
3428 auto newChain = x->new_ptr<ChainValue_t>();
3429 newChain->items.push_back(callable);
3430 auto it = chainList.begin();
3431 it++; it++;
3432 for (; it != chainList.end(); ++it) {
3433 newChain->items.push_back(*it);
3434 }
3435 auto value = x->new_ptr<Value_t>();
3436 value->item.set(newChain);
3437 exp = newExp(value, x);
3438 }
3439 if (usage == ExpUsage::Common) {
3440 auto expList = x->new_ptr<ExpList_t>();
3441 expList->exprs.push_back(exp);
3442 auto exps = x->new_ptr<ExpListAssign_t>();
3443 exps->expList.set(expList);
3444 auto stmt = x->new_ptr<Statement_t>();
3445 stmt->content.set(exps);
3446 auto block = x->new_ptr<Block_t>();
3447 block->statements.push_back(stmt);
3448 info.node.set(block);
3449 } else {
3450 info.node.set(exp);
3451 }
3452 }
3453 return {info.node, std::move(info.codes), Empty, std::move(localVars)};
3454 } else {
3455 if (!isBlock) throw std::logic_error(_info.errorMessage(s("failed to expanded empty macro as expr"sv), x));
3456 return {x->new_ptr<Block_t>().get(), std::move(info.codes), Empty, std::move(localVars)};
3457 }
3458 }
3459 }
3460#endif // MOONP_NO_MACRO
3461
3462 void transformChainValue(ChainValue_t* chainValue, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr, bool allowBlockMacroReturn = false) {
3463 if (isMacroChain(chainValue)) {
3464#ifndef MOONP_NO_MACRO
3465 ast_ptr<false,ast_node> node;
3466 std::unique_ptr<input> codes;
3467 std::string luaCodes;
3468 str_list localVars;
3469 std::tie(node, codes, luaCodes, localVars) = expandMacro(chainValue, usage, allowBlockMacroReturn);
3470 Utils::replace(luaCodes, "\r\n"sv, "\n"sv);
3471 Utils::trim(luaCodes);
3472 if (!node) {
3473 if (!luaCodes.empty()) {
3474 if (_config.reserveLineNumber) {
3475 luaCodes.insert(0, nll(chainValue).substr(1));
3476 }
3477 luaCodes.append(nlr(chainValue));
3478 }
3479 out.push_back(luaCodes);
3480 if (!localVars.empty()) {
3481 for (const auto& var : localVars) {
3482 addToScope(var);
3483 }
3484 }
3485 return;
3486 }
3487 if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is<Block_t>())) {
3488 transformBlock(node.to<Block_t>(), out, usage, assignList);
3489 } else {
3490 auto x = chainValue;
3491 switch (usage) {
3492 case ExpUsage::Assignment: {
3493 auto assign = x->new_ptr<Assign_t>();
3494 assign->values.push_back(node);
3495 auto assignment = x->new_ptr<ExpListAssign_t>();
3496 assignment->expList.set(assignList);
3497 assignment->action.set(assign);
3498 transformAssignment(assignment, out);
3499 break;
3500 }
3501 case ExpUsage::Return: {
3502 auto expListLow = x->new_ptr<ExpListLow_t>();
3503 expListLow->exprs.push_back(node);
3504 auto returnNode = x->new_ptr<Return_t>();
3505 returnNode->valueList.set(expListLow);
3506 transformReturn(returnNode, out);
3507 break;
3508 }
3509 default:
3510 transformExp(node.to<Exp_t>(), out, usage);
3511 break;
3512 }
3513 }
3514 return;
3515#else
3516 (void)allowBlockMacroReturn;
3517 throw std::logic_error(_info.errorMessage("macro feature not supported"sv, chainValue));
3518#endif // MOONP_NO_MACRO
3519 }
3520 const auto& chainList = chainValue->items.objects();
3521 if (transformChainEndWithEOP(chainList, out, usage, assignList)) {
3522 return;
3523 }
3524 if (transformChainWithEOP(chainList, out, usage, assignList)) {
3525 return;
3526 }
3527 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) {
3528 return;
3529 }
3530 transformChainList(chainList, out, usage, assignList);
3531 }
3532
3533 void transformAssignableChain(AssignableChain_t* chain, str_list& out) {
3534 transformChainList(chain->items.objects(), out, ExpUsage::Closure);
3535 }
3536
3537 void transformDotChainItem(DotChainItem_t* dotChainItem, str_list& out) {
3538 auto name = _parser.toString(dotChainItem->name);
3539 if (Keywords.find(name) != Keywords.end()) {
3540 out.push_back(s("[\""sv) + name + s("\"]"sv));
3541 } else {
3542 out.push_back(s("."sv) + name);
3543 }
3544 }
3545
3546 void transformColonChainItem(ColonChainItem_t* colonChainItem, str_list& out) {
3547 auto name = _parser.toString(colonChainItem->name);
3548 out.push_back(s(colonChainItem->switchToDot ? "."sv : ":"sv) + name);
3549 }
3550
3551 void transformSlice(Slice_t* slice, str_list&) {
3552 throw std::logic_error(_info.errorMessage("slice syntax not supported here"sv, slice));
3553 }
3554
3555 void transformInvoke(Invoke_t* invoke, str_list& out) {
3556 str_list temp;
3557 for (auto arg : invoke->args.objects()) {
3558 switch (arg->getId()) {
3559 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(arg), temp, ExpUsage::Closure); break;
3560 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(arg), temp); break;
3561 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(arg), temp); break;
3562 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(arg), temp); break;
3563 case id<TableLit_t>(): transformTableLit(static_cast<TableLit_t*>(arg), temp); break;
3564 default: assert(false); break;
3565 }
3566 }
3567 out.push_back(s("("sv) + join(temp, ", "sv) + s(")"sv));
3568 }
3569
3570 void transform_unary_value(unary_value_t* unary_value, str_list& out) {
3571 str_list temp;
3572 for (auto _op : unary_value->ops.objects()) {
3573 std::string op = _parser.toString(_op);
3574 temp.push_back(op + (op == "not"sv ? s(" "sv) : Empty));
3575 }
3576 transformValue(unary_value->value, temp);
3577 out.push_back(join(temp));
3578 }
3579
3580 void transform_unary_exp(unary_exp_t* unary_exp, str_list& out) {
3581 if (unary_exp->ops.empty() && unary_exp->expos.size() == 1) {
3582 transformValue(static_cast<Value_t*>(unary_exp->expos.back()), out);
3583 return;
3584 }
3585 std::string unary_op;
3586 for (auto _op : unary_exp->ops.objects()) {
3587 std::string op = _parser.toString(_op);
3588 unary_op.append(op + (op == "not"sv ? s(" "sv) : Empty));
3589 }
3590 str_list temp;
3591 for (auto _value : unary_exp->expos.objects()) {
3592 auto value = static_cast<Value_t*>(_value);
3593 transformValue(value, temp);
3594 }
3595 out.push_back(unary_op + join(temp, " ^ "sv));
3596 }
3597
3598 void transformVariable(Variable_t* name, str_list& out) {
3599 out.push_back(_parser.toString(name));
3600 }
3601
3602 void transformNum(Num_t* num, str_list& out) {
3603 out.push_back(_parser.toString(num));
3604 }
3605
3606 void transformTableLit(TableLit_t* table, str_list& out) {
3607 transformTable(table, table->values.objects(), out);
3608 }
3609
3610 void transformCompCommon(Comprehension_t* comp, str_list& out) {
3611 str_list temp;
3612 auto x = comp;
3613 auto compInner = comp->forLoop.get();
3614 for (auto item : compInner->items.objects()) {
3615 switch (item->getId()) {
3616 case id<CompForEach_t>():
3617 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
3618 break;
3619 case id<CompFor_t>():
3620 transformCompFor(static_cast<CompFor_t*>(item), temp);
3621 break;
3622 case id<Exp_t>():
3623 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
3624 temp.back() = indent() + s("if "sv) + temp.back() + s(" then"sv) + nll(item);
3625 pushScope();
3626 break;
3627 default: assert(false); break;
3628 }
3629 }
3630 if (auto stmt = comp->value.as<Statement_t>()) {
3631 transformStatement(stmt, temp);
3632 } else if (auto exp = comp->value.as<Exp_t>()) {
3633 auto expList = x->new_ptr<ExpList_t>();
3634 expList->exprs.push_back(exp);
3635 auto expListAssign = x->new_ptr<ExpListAssign_t>();
3636 expListAssign->expList.set(expList);
3637 auto statement = x->new_ptr<Statement_t>();
3638 statement->content.set(expListAssign);
3639 transformStatement(statement, temp);
3640 }
3641 auto value = temp.back();
3642 temp.pop_back();
3643 _buf << join(temp) << value;
3644 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
3645 popScope();
3646 _buf << indent() << "end"sv << nll(comp);
3647 }
3648 out.push_back(clearBuf());
3649 }
3650
3651 void transformComprehension(Comprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
3652 auto x = comp;
3653 switch (usage) {
3654 case ExpUsage::Closure:
3655 _enableReturn.push(true);
3656 pushScope();
3657 break;
3658 case ExpUsage::Assignment:
3659 pushScope();
3660 break;
3661 default:
3662 break;
3663 }
3664 str_list temp;
3665 std::string accumVar = getUnusedName("_accum_"sv);
3666 std::string lenVar = getUnusedName("_len_"sv);
3667 addToScope(accumVar);
3668 addToScope(lenVar);
3669 auto compInner = comp->forLoop.get();
3670 for (auto item : compInner->items.objects()) {
3671 switch (item->getId()) {
3672 case id<CompForEach_t>():
3673 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
3674 break;
3675 case id<CompFor_t>():
3676 transformCompFor(static_cast<CompFor_t*>(item), temp);
3677 break;
3678 case id<Exp_t>():
3679 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
3680 temp.back() = indent() + s("if "sv) + temp.back() + s(" then"sv) + nll(item);
3681 pushScope();
3682 break;
3683 default: assert(false); break;
3684 }
3685 }
3686 {
3687 auto assignLeft = toAst<ExpList_t>(accumVar + s("["sv) + lenVar + s("]"sv), x);
3688 auto assign = x->new_ptr<Assign_t>();
3689 assign->values.push_back(comp->value);
3690 auto assignment = x->new_ptr<ExpListAssign_t>();
3691 assignment->expList.set(assignLeft);
3692 assignment->action.set(assign);
3693 transformAssignment(assignment, temp);
3694 }
3695 auto assignStr = temp.back();
3696 temp.pop_back();
3697 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
3698 popScope();
3699 }
3700 _buf << indent() << "local "sv << accumVar << " = { }"sv << nll(comp);
3701 _buf << indent() << "local "sv << lenVar << " = 1"sv << nll(comp);
3702 _buf << join(temp);
3703 _buf << assignStr;
3704 _buf << indent(int(temp.size())) << lenVar << " = "sv << lenVar << " + 1"sv << nll(comp);
3705 for (int ind = int(temp.size()) - 1; ind > -1; --ind) {
3706 _buf << indent(ind) << "end"sv << nll(comp);
3707 }
3708 switch (usage) {
3709 case ExpUsage::Common:
3710 break;
3711 case ExpUsage::Closure: {
3712 _enableReturn.pop();
3713 out.push_back(clearBuf());
3714 out.back().append(indent() + s("return "sv) + accumVar + nlr(comp));
3715 popScope();
3716 out.back().insert(0, s("(function()"sv) + nll(comp));
3717 out.back().append(indent() + s("end)()"sv));
3718 break;
3719 }
3720 case ExpUsage::Assignment: {
3721 out.push_back(clearBuf());
3722 auto assign = x->new_ptr<Assign_t>();
3723 assign->values.push_back(toAst<Exp_t>(accumVar, x));
3724 auto assignment = x->new_ptr<ExpListAssign_t>();
3725 assignment->expList.set(assignList);
3726 assignment->action.set(assign);
3727 transformAssignment(assignment, temp);
3728 popScope();
3729 out.back() = indent() + s("do"sv) + nll(comp) +
3730 out.back() + temp.back() +
3731 indent() + s("end"sv) + nlr(comp);
3732 break;
3733 }
3734 case ExpUsage::Return:
3735 out.push_back(clearBuf());
3736 out.back().append(indent() + s("return "sv) + accumVar + nlr(comp));
3737 break;
3738 default:
3739 break;
3740 }
3741 }
3742
3743 void transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out) {
3744 auto x = nameList;
3745 str_list temp;
3746 str_list vars;
3747 str_list varBefore, varAfter;
3748 std::list<std::pair<ast_node*, ast_ptr<false, ast_node>>> destructPairs;
3749 for (auto _item : nameList->items.objects()) {
3750 auto item = static_cast<NameOrDestructure_t*>(_item)->item.get();
3751 switch (item->getId()) {
3752 case id<Variable_t>():
3753 transformVariable(static_cast<Variable_t*>(item), vars);
3754 varAfter.push_back(vars.back());
3755 break;
3756 case id<TableLit_t>(): {
3757 auto desVar = getUnusedName("_des_"sv);
3758 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x));
3759 vars.push_back(desVar);
3760 varAfter.push_back(desVar);
3761 break;
3762 }
3763 default: assert(false); break;
3764 }
3765 }
3766 switch (loopTarget->getId()) {
3767 case id<star_exp_t>(): {
3768 auto star_exp = static_cast<star_exp_t*>(loopTarget);
3769 auto listVar = singleVariableFrom(star_exp->value);
3770 auto indexVar = getUnusedName("_index_"sv);
3771 varAfter.push_back(indexVar);
3772 auto value = singleValueFrom(star_exp->value);
3773 if (!value) throw std::logic_error(_info.errorMessage("invalid star syntax"sv, star_exp));
3774 bool endWithSlice = false;
3775 BLOCK_START
3776 auto chainValue = value->item.as<ChainValue_t>();
3777 BREAK_IF(!chainValue);
3778 auto chainList = chainValue->items.objects();
3779 auto slice = ast_cast<Slice_t>(chainList.back());
3780 BREAK_IF(!slice);
3781 endWithSlice = true;
3782 if (listVar.empty() && chainList.size() == 2 &&
3783 ast_is<Callable_t>(chainList.front())) {
3784 transformCallable(static_cast<Callable_t*>(chainList.front()), temp);
3785 listVar = temp.back();
3786 temp.pop_back();
3787 }
3788 chainList.pop_back();
3789 auto chain = x->new_ptr<ChainValue_t>();
3790 for (auto item : chainList) {
3791 chain->items.push_back(item);
3792 }
3793 std::string startValue("1"sv);
3794 if (auto exp = slice->startValue.as<Exp_t>()) {
3795 transformExp(exp, temp, ExpUsage::Closure);
3796 startValue = temp.back();
3797 temp.pop_back();
3798 }
3799 std::string stopValue;
3800 if (auto exp = slice->stopValue.as<Exp_t>()) {
3801 transformExp(exp, temp, ExpUsage::Closure);
3802 stopValue = temp.back();
3803 temp.pop_back();
3804 }
3805 std::string stepValue;
3806 if (auto exp = slice->stepValue.as<Exp_t>()) {
3807 transformExp(exp, temp, ExpUsage::Closure);
3808 stepValue = temp.back();
3809 temp.pop_back();
3810 }
3811 if (listVar.empty()) {
3812 listVar = getUnusedName("_list_"sv);
3813 varBefore.push_back(listVar);
3814 transformChainValue(chain, temp, ExpUsage::Closure);
3815 _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList);
3816 }
3817 std::string maxVar;
3818 if (!stopValue.empty()) {
3819 maxVar = getUnusedName("_max_"sv);
3820 varBefore.push_back(maxVar);
3821 _buf << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList);
3822 }
3823 _buf << indent() << "for "sv << indexVar << " = "sv;
3824 _buf << startValue << ", "sv;
3825 if (stopValue.empty()) {
3826 _buf << "#"sv << listVar;
3827 } else {
3828 _buf << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " or "sv << maxVar;
3829 }
3830 if (!stepValue.empty()) {
3831 _buf << ", "sv << stepValue;
3832 }
3833 _buf << " do"sv << nlr(loopTarget);
3834 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList);
3835 out.push_back(clearBuf());
3836 BLOCK_END
3837 bool newListVal = false;
3838 if (listVar.empty()) {
3839 newListVal = true;
3840 listVar = getUnusedName("_list_"sv);
3841 varBefore.push_back(listVar);
3842 }
3843 if (!endWithSlice) {
3844 transformExp(star_exp->value, temp, ExpUsage::Closure);
3845 if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList);
3846 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nlr(loopTarget);
3847 _buf << indent(1) << "local "sv << join(vars) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList);
3848 out.push_back(clearBuf());
3849 }
3850 break;
3851 }
3852 case id<Exp_t>():
3853 transformExp(static_cast<Exp_t*>(loopTarget), temp, ExpUsage::Closure);
3854 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget);
3855 out.push_back(clearBuf());
3856 break;
3857 case id<ExpList_t>():
3858 transformExpList(static_cast<ExpList_t*>(loopTarget), temp);
3859 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget);
3860 out.push_back(clearBuf());
3861 break;
3862 default: assert(false); break;
3863 }
3864 for (auto& var : varBefore) addToScope(var);
3865 pushScope();
3866 for (auto& var : varAfter) addToScope(var);
3867 if (!destructPairs.empty()) {
3868 temp.clear();
3869 for (auto& pair : destructPairs) {
3870 auto sValue = x->new_ptr<SimpleValue_t>();
3871 sValue->value.set(pair.first);
3872 auto value = x->new_ptr<Value_t>();
3873 value->item.set(sValue);
3874 auto exp = newExp(value, x);
3875 auto expList = x->new_ptr<ExpList_t>();
3876 expList->exprs.push_back(exp);
3877 auto assign = x->new_ptr<Assign_t>();
3878 assign->values.push_back(pair.second);
3879 auto assignment = x->new_ptr<ExpListAssign_t>();
3880 assignment->expList.set(expList);
3881 assignment->action.set(assign);
3882 transformAssignment(assignment, temp);
3883 }
3884 out.back().append(join(temp));
3885 }
3886 }
3887
3888 void transformCompForEach(CompForEach_t* comp, str_list& out) {
3889 transformForEachHead(comp->nameList, comp->loopValue, out);
3890 }
3891
3892 void transformInvokeArgs(InvokeArgs_t* invokeArgs, str_list& out) {
3893 if (invokeArgs->args.size() > 1) {
3894 /* merge all the key-value pairs into one table
3895 from arguments in the end */
3896 auto lastArg = invokeArgs->args.back();
3897 _ast_list* lastTable = nullptr;
3898 if (auto tableBlock = ast_cast<TableBlock_t>(lastArg)) {
3899 lastTable = &tableBlock->values;
3900 } else if (auto value = singleValueFrom(lastArg)) {
3901 if (auto simpleTable = ast_cast<simple_table_t>(value->item)) {
3902 lastTable = &simpleTable->pairs;
3903 }
3904 }
3905 if (lastTable) {
3906 ast_ptr<false, ast_node> ref(lastArg);
3907 invokeArgs->args.pop_back();
3908 while (!invokeArgs->args.empty()) {
3909 if (Value_t* value = singleValueFrom(invokeArgs->args.back())) {
3910 if (auto tb = value->item.as<simple_table_t>()) {
3911 const auto& ps = tb->pairs.objects();
3912 for (auto it = ps.rbegin(); it != ps.rend(); ++it) {
3913 lastTable->push_front(*it);
3914 }
3915 invokeArgs->args.pop_back();
3916 continue;
3917 }
3918 }
3919 break;
3920 }
3921 invokeArgs->args.push_back(lastArg);
3922 }
3923 }
3924 str_list temp;
3925 for (auto arg : invokeArgs->args.objects()) {
3926 switch (arg->getId()) {
3927 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(arg), temp, ExpUsage::Closure); break;
3928 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(arg), temp); break;
3929 default: assert(false); break;
3930 }
3931 }
3932 out.push_back(s("("sv) + join(temp, ", "sv) + s(")"sv));
3933 }
3934
3935 void transformForHead(For_t* forNode, str_list& out) {
3936 str_list temp;
3937 std::string varName = _parser.toString(forNode->varName);
3938 transformExp(forNode->startValue, temp, ExpUsage::Closure);
3939 transformExp(forNode->stopValue, temp, ExpUsage::Closure);
3940 if (forNode->stepValue) {
3941 transformExp(forNode->stepValue->value, temp, ExpUsage::Closure);
3942 } else {
3943 temp.emplace_back();
3944 }
3945 auto it = temp.begin();
3946 const auto& start = *it;
3947 const auto& stop = *(++it);
3948 const auto& step = *(++it);
3949 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : s(", "sv) + step) << " do"sv << nll(forNode);
3950 pushScope();
3951 addToScope(varName);
3952 out.push_back(clearBuf());
3953 }
3954
3955 void transform_plain_body(ast_node* body, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
3956 switch (body->getId()) {
3957 case id<Block_t>():
3958 transformBlock(static_cast<Block_t*>(body), out, usage, assignList);
3959 break;
3960 case id<Statement_t>(): {
3961 auto newBlock = body->new_ptr<Block_t>();
3962 newBlock->statements.push_back(body);
3963 transformBlock(newBlock, out, usage, assignList);
3964 break;
3965 }
3966 default: assert(false); break;
3967 }
3968 }
3969
3970 void transformLoopBody(ast_node* body, str_list& out, const std::string& appendContent, ExpUsage usage, ExpList_t* assignList = nullptr) {
3971 str_list temp;
3972 bool withContinue = traversal::Stop == body->traverse([&](ast_node* node) {
3973 if (auto stmt = ast_cast<Statement_t>(node)) {
3974 if (stmt->content.is<BreakLoop_t>()) {
3975 return _parser.toString(stmt->content) == "continue"sv ?
3976 traversal::Stop : traversal::Return;
3977 } else if (expListFrom(stmt)) {
3978 return traversal::Continue;
3979 }
3980 return traversal::Return;
3981 }
3982 return traversal::Continue;
3983 });
3984 if (withContinue) {
3985 auto continueVar = getUnusedName("_continue_"sv);
3986 addToScope(continueVar);
3987 _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body);
3988 _buf << indent() << "repeat"sv << nll(body);
3989 temp.push_back(clearBuf());
3990 _continueVars.push(continueVar);
3991 pushScope();
3992 }
3993 transform_plain_body(body, temp, usage, assignList);
3994 if (withContinue) {
3995 if (!appendContent.empty()) {
3996 _buf << indent() << appendContent;
3997 }
3998 _buf << indent() << _continueVars.top() << " = true"sv << nll(body);
3999 popScope();
4000 _buf << indent() << "until true"sv << nlr(body);
4001 _buf << indent() << "if not "sv << _continueVars.top() << " then"sv << nlr(body);
4002 _buf << indent(1) << "break"sv << nlr(body);
4003 _buf << indent() << "end"sv << nlr(body);
4004 temp.push_back(clearBuf());
4005 _continueVars.pop();
4006 } else if (!appendContent.empty()) {
4007 temp.back().append(indent() + appendContent);
4008 }
4009 out.push_back(join(temp));
4010 }
4011
4012 void transformFor(For_t* forNode, str_list& out) {
4013 str_list temp;
4014 transformForHead(forNode, temp);
4015 transformLoopBody(forNode->body, temp, Empty, ExpUsage::Common);
4016 popScope();
4017 out.push_back(join(temp) + indent() + s("end"sv) + nlr(forNode));
4018 }
4019
4020 std::string transformForInner(For_t* forNode, str_list& out) {
4021 auto x = forNode;
4022 std::string accum = getUnusedName("_accum_"sv);
4023 addToScope(accum);
4024 std::string len = getUnusedName("_len_"sv);
4025 addToScope(len);
4026 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forNode);
4027 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode);
4028 out.push_back(clearBuf());
4029 transformForHead(forNode, out);
4030 auto expList = toAst<ExpList_t>(accum + s("["sv) + len + s("]"sv), x);
4031 auto lenLine = len + s(" = "sv) + len + s(" + 1"sv) + nlr(forNode->body);
4032 transformLoopBody(forNode->body, out, lenLine, ExpUsage::Assignment, expList);
4033 popScope();
4034 out.push_back(indent() + s("end"sv) + nlr(forNode));
4035 return accum;
4036 }
4037
4038 void transformForClosure(For_t* forNode, str_list& out) {
4039 str_list temp;
4040 _buf << "(function()"sv << nll(forNode);
4041 pushScope();
4042 _enableReturn.push(true);
4043 auto accum = transformForInner(forNode, temp);
4044 temp.push_back(indent() + s("return "sv) + accum + nlr(forNode));
4045 _enableReturn.pop();
4046 popScope();
4047 temp.push_back(indent() + s("end)()"sv));
4048 out.push_back(join(temp));
4049 }
4050
4051 void transformForInPlace(For_t* forNode, str_list& out, ExpList_t* assignExpList = nullptr) {
4052 auto x = forNode;
4053 str_list temp;
4054 if (assignExpList) {
4055 _buf << indent() << "do"sv << nll(forNode);
4056 pushScope();
4057 auto accum = transformForInner(forNode, temp);
4058 auto assign = x->new_ptr<Assign_t>();
4059 assign->values.push_back(toAst<Exp_t>(accum, x));
4060 auto assignment = x->new_ptr<ExpListAssign_t>();
4061 assignment->expList.set(assignExpList);
4062 assignment->action.set(assign);
4063 transformAssignment(assignment, temp);
4064 popScope();
4065 temp.push_back(indent() + s("end"sv) + nlr(forNode));
4066 } else {
4067 auto accum = transformForInner(forNode, temp);
4068 auto returnNode = x->new_ptr<Return_t>();
4069 auto expListLow = toAst<ExpListLow_t>(accum, x);
4070 returnNode->valueList.set(expListLow);
4071 transformReturn(returnNode, temp);
4072 }
4073 out.push_back(join(temp));
4074 }
4075
4076 void transformBinaryOperator(BinaryOperator_t* node, str_list& out) {
4077 auto op = _parser.toString(node);
4078 out.push_back(op == "!="sv ? s("~="sv) : op);
4079 }
4080
4081 void transformForEach(ForEach_t* forEach, str_list& out) {
4082 str_list temp;
4083 transformForEachHead(forEach->nameList, forEach->loopValue, temp);
4084 transformLoopBody(forEach->body, temp, Empty, ExpUsage::Common);
4085 popScope();
4086 out.push_back(temp.front() + temp.back() + indent() + s("end"sv) + nlr(forEach));
4087 }
4088
4089 std::string transformForEachInner(ForEach_t* forEach, str_list& out) {
4090 auto x = forEach;
4091 std::string accum = getUnusedName("_accum_"sv);
4092 addToScope(accum);
4093 std::string len = getUnusedName("_len_"sv);
4094 addToScope(len);
4095 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forEach);
4096 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach);
4097 out.push_back(clearBuf());
4098 transformForEachHead(forEach->nameList, forEach->loopValue, out);
4099 auto expList = toAst<ExpList_t>(accum + s("["sv) + len + s("]"sv), x);
4100 auto lenLine = len + s(" = "sv) + len + s(" + 1"sv) + nlr(forEach->body);
4101 transformLoopBody(forEach->body, out, lenLine, ExpUsage::Assignment, expList);
4102 popScope();
4103 out.push_back(indent() + s("end"sv) + nlr(forEach));
4104 return accum;
4105 }
4106
4107 void transformForEachClosure(ForEach_t* forEach, str_list& out) {
4108 str_list temp;
4109 _buf << "(function()"sv << nll(forEach);
4110 pushScope();
4111 _enableReturn.push(true);
4112 auto accum = transformForEachInner(forEach, temp);
4113 temp.push_back(indent() + s("return "sv) + accum + nlr(forEach));
4114 _enableReturn.pop();
4115 popScope();
4116 temp.push_back(indent() + s("end)()"sv));
4117 out.push_back(join(temp));
4118 }
4119
4120 void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList = nullptr) {
4121 auto x = forEach;
4122 str_list temp;
4123 if (assignExpList) {
4124 _buf << indent() << "do"sv << nll(forEach);
4125 pushScope();
4126 auto accum = transformForEachInner(forEach, temp);
4127 auto assign = x->new_ptr<Assign_t>();
4128 assign->values.push_back(toAst<Exp_t>(accum, x));
4129 auto assignment = x->new_ptr<ExpListAssign_t>();
4130 assignment->expList.set(assignExpList);
4131 assignment->action.set(assign);
4132 transformAssignment(assignment, temp);
4133 popScope();
4134 temp.push_back(indent() + s("end"sv) + nlr(forEach));
4135 } else {
4136 auto accum = transformForEachInner(forEach, temp);
4137 auto returnNode = x->new_ptr<Return_t>();
4138 auto expListLow = toAst<ExpListLow_t>(accum, x);
4139 returnNode->valueList.set(expListLow);
4140 transformReturn(returnNode, temp);
4141 }
4142 out.push_back(join(temp));
4143 }
4144
4145 void transform_variable_pair(variable_pair_t* pair, str_list& out) {
4146 auto name = _parser.toString(pair->name);
4147 out.push_back(name + s(" = "sv) + name);
4148 }
4149
4150 void transform_normal_pair(normal_pair_t* pair, str_list& out) {
4151 auto key = pair->key.get();
4152 str_list temp;
4153 switch (key->getId()) {
4154 case id<KeyName_t>(): {
4155 transformKeyName(static_cast<KeyName_t*>(key), temp);
4156 if (LuaKeywords.find(temp.back()) != LuaKeywords.end()) {
4157 temp.back() = s("[\""sv) + temp.back() + s("\"]");
4158 }
4159 break;
4160 }
4161 case id<Exp_t>():
4162 transformExp(static_cast<Exp_t*>(key), temp, ExpUsage::Closure);
4163 temp.back() = s(temp.back().front() == '[' ? "[ "sv : "["sv) + temp.back() + s("]"sv);
4164 break;
4165 case id<DoubleString_t>():
4166 transformDoubleString(static_cast<DoubleString_t*>(key), temp);
4167 temp.back() = s("["sv) + temp.back() + s("]"sv);
4168 break;
4169 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(key), temp);
4170 temp.back() = s("["sv) + temp.back() + s("]"sv);
4171 break;
4172 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(key), temp);
4173 temp.back() = s("[ "sv) + temp.back() + s("]"sv);
4174 break;
4175 default: assert(false); break;
4176 }
4177 auto value = pair->value.get();
4178 switch (value->getId()) {
4179 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(value), temp, ExpUsage::Closure); break;
4180 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(value), temp); break;
4181 default: assert(false); break;
4182 }
4183 out.push_back(temp.front() + s(" = "sv) + temp.back());
4184 }
4185
4186 void transformKeyName(KeyName_t* keyName, str_list& out) {
4187 auto name = keyName->name.get();
4188 switch (name->getId()) {
4189 case id<SelfName_t>(): transformSelfName(static_cast<SelfName_t*>(name), out); break;
4190 case id<Name_t>(): out.push_back(_parser.toString(name)); break;
4191 default: assert(false); break;
4192 }
4193 }
4194
4195 void transformLuaString(LuaString_t* luaString, str_list& out) {
4196 auto content = _parser.toString(luaString->content);
4197 Utils::replace(content, "\r\n"sv, "\n");
4198 if (content[0] == '\n') content.erase(content.begin());
4199 out.push_back(_parser.toString(luaString->open) + content + _parser.toString(luaString->close));
4200 }
4201
4202 void transformSingleString(SingleString_t* singleString, str_list& out) {
4203 auto str = _parser.toString(singleString);
4204 Utils::replace(str, "\r\n"sv, "\n");
4205 Utils::replace(str, "\n"sv, "\\n"sv);
4206 out.push_back(str);
4207 }
4208
4209 void transformDoubleString(DoubleString_t* doubleString, str_list& out) {
4210 str_list temp;
4211 for (auto _seg : doubleString->segments.objects()) {
4212 auto seg = static_cast<double_string_content_t*>(_seg);
4213 auto content = seg->content.get();
4214 switch (content->getId()) {
4215 case id<double_string_inner_t>(): {
4216 auto str = _parser.toString(content);
4217 Utils::replace(str, "\r\n"sv, "\n");
4218 Utils::replace(str, "\n"sv, "\\n"sv);
4219 temp.push_back(s("\""sv) + str + s("\""sv));
4220 break;
4221 }
4222 case id<Exp_t>(): {
4223 transformExp(static_cast<Exp_t*>(content), temp, ExpUsage::Closure);
4224 std::string tostr("tostring"sv);
4225 temp.back() = tostr + '(' + temp.back() + s(")"sv);
4226 if (_config.lintGlobalVariable) {
4227 if (!isDefined(tostr)) {
4228 if (_globals.find(tostr) == _globals.end()) {
4229 _globals[tostr] = {content->m_begin.m_line, content->m_begin.m_col};
4230 }
4231 }
4232 }
4233 break;
4234 }
4235 default: assert(false); break;
4236 }
4237 }
4238 out.push_back(temp.empty() ? s("\"\""sv) : join(temp, " .. "sv));
4239 }
4240
4241 void transformString(String_t* string, str_list& out) {
4242 auto str = string->str.get();
4243 switch (str->getId()) {
4244 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break;
4245 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break;
4246 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break;
4247 default: assert(false); break;
4248 }
4249 }
4250
4251 std::pair<std::string,bool> defineClassVariable(Assignable_t* assignable) {
4252 if (auto variable = assignable->item.as<Variable_t>()) {
4253 auto name = _parser.toString(variable);
4254 if (addToScope(name)) {
4255 return {name, true};
4256 } else {
4257 return {name, false};
4258 }
4259 }
4260 return {Empty, false};
4261 }
4262
4263 void transformClassDeclClosure(ClassDecl_t* classDecl, str_list& out) {
4264 str_list temp;
4265 temp.push_back(s("(function()"sv) + nll(classDecl));
4266 pushScope();
4267 _enableReturn.push(true);
4268 transformClassDecl(classDecl, temp, ExpUsage::Return);
4269 _enableReturn.pop();
4270 popScope();
4271 temp.push_back(s("end)()"sv));
4272 out.push_back(join(temp));
4273 }
4274
4275 void transformClassDecl(ClassDecl_t* classDecl, str_list& out, ExpUsage usage, ExpList_t* expList = nullptr) {
4276 str_list temp;
4277 auto x = classDecl;
4278 auto body = classDecl->body.get();
4279 auto assignable = classDecl->name.get();
4280 auto extend = classDecl->extend.get();
4281 std::string className;
4282 std::string assignItem;
4283 if (assignable) {
4284 if (!isAssignable(assignable)) {
4285 throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, assignable));
4286 }
4287 bool newDefined = false;
4288 std::tie(className, newDefined) = defineClassVariable(assignable);
4289 if (newDefined) {
4290 temp.push_back(indent() + s("local "sv) + className + nll(classDecl));
4291 }
4292 if (className.empty()) {
4293 if (auto chain = ast_cast<AssignableChain_t>(assignable->item)) {
4294 if (auto dotChain = ast_cast<DotChainItem_t>(chain->items.back())) {
4295 className = s("\""sv) + _parser.toString(dotChain->name) + s("\""sv);
4296 } else if (auto index = ast_cast<Exp_t>(chain->items.back())) {
4297 if (auto name = index->getByPath<unary_exp_t, Value_t, String_t>()) {
4298 transformString(name, temp);
4299 className = temp.back();
4300 temp.pop_back();
4301 }
4302 }
4303 }
4304 } else {
4305 className = s("\""sv) + className + s("\""sv);
4306 }
4307 pushScope();
4308 transformAssignable(assignable, temp);
4309 popScope();
4310 assignItem = temp.back();
4311 temp.pop_back();
4312 } else if (expList) {
4313 auto name = singleVariableFrom(expList);
4314 if (!name.empty()) {
4315 className = s("\""sv) + name + s("\""sv);
4316 }
4317 }
4318 temp.push_back(indent() + s("do"sv) + nll(classDecl));
4319 pushScope();
4320 auto classVar = getUnusedName("_class_"sv);
4321 addToScope(classVar);
4322 temp.push_back(indent() + s("local "sv) + classVar + nll(classDecl));
4323 if (body) {
4324 str_list varDefs;
4325 for (auto item : body->contents.objects()) {
4326 if (auto statement = ast_cast<Statement_t>(item)) {
4327 ClassDecl_t* clsDecl = nullptr;
4328 if (auto assignment = assignmentFrom(statement)) {
4329 auto names = transformAssignDefs(assignment->expList.get());
4330 varDefs.insert(varDefs.end(), names.begin(), names.end());
4331 auto info = extractDestructureInfo(assignment, true);
4332 if (!info.first.empty()) {
4333 for (const auto& destruct : info.first)
4334 for (const auto& item : destruct.items)
4335 if (item.isVariable && addToScope(item.name))
4336 varDefs.push_back(item.name);
4337 }
4338 BLOCK_START
4339 auto assign = assignment->action.as<Assign_t>();
4340 BREAK_IF(!assign);
4341 BREAK_IF(assign->values.objects().size() != 1);
4342 auto exp = ast_cast<Exp_t>(assign->values.objects().front());
4343 BREAK_IF(!exp);
4344 auto value = singleValueFrom(exp);
4345 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
4346 BLOCK_END
4347 } else if (auto expList = expListFrom(statement)) {
4348 auto value = singleValueFrom(expList);
4349 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
4350 }
4351 if (clsDecl) {
4352 std::string clsName;
4353 bool newDefined = false;
4354 std::tie(clsName,newDefined) = defineClassVariable(clsDecl->name);
4355 if (newDefined) varDefs.push_back(clsName);
4356 }
4357 }
4358 }
4359 if (!varDefs.empty()) {
4360 temp.push_back(indent() + s("local "sv) + join(varDefs, ", "sv) + nll(body));
4361 }
4362 }
4363 std::string parent, parentVar;
4364 if (extend) {
4365 parentVar = getUnusedName("_parent_"sv);
4366 addToScope(parentVar);
4367 transformExp(extend, temp, ExpUsage::Closure);
4368 parent = temp.back();
4369 temp.pop_back();
4370 temp.push_back(indent() + s("local "sv) + parentVar + s(" = "sv) + parent + nll(classDecl));
4371 }
4372 auto baseVar = getUnusedName("_base_"sv);
4373 addToScope(baseVar);
4374 temp.push_back(indent() + s("local "sv) + baseVar + s(" = "sv));
4375 str_list builtins;
4376 str_list commons;
4377 str_list statements;
4378 if (body) {
4379 std::list<ClassMember> members;
4380 for (auto content : classDecl->body->contents.objects()) {
4381 switch (content->getId()) {
4382 case id<class_member_list_t>(): {
4383 size_t inc = transform_class_member_list(static_cast<class_member_list_t*>(content), members, classVar);
4384 auto it = members.end();
4385 for (size_t i = 0; i < inc; ++i, --it);
4386 for (; it != members.end(); ++it) {
4387 auto& member = *it;
4388 if (member.type == MemType::Property) {
4389 statements.push_back(indent() + member.item + nll(content));
4390 } else {
4391 member.item = indent(1) + member.item;
4392 }
4393 }
4394 break;
4395 }
4396 case id<Statement_t>():
4397 transformStatement(static_cast<Statement_t*>(content), statements);
4398 break;
4399 default: assert(false); break;
4400 }
4401 }
4402 for (auto& member : members) {
4403 switch (member.type) {
4404 case MemType::Common:
4405 commons.push_back((commons.empty() ? Empty : s(","sv) + nll(member.node)) + member.item);
4406 break;
4407 case MemType::Builtin:
4408 builtins.push_back((builtins.empty() ? Empty : s(","sv) + nll(member.node)) + member.item);
4409 break;
4410 default: break;
4411 }
4412 }
4413 if (!commons.empty()) {
4414 temp.back() += s("{"sv) + nll(body);
4415 temp.push_back(join(commons) + nll(body));
4416 temp.push_back(indent() + s("}"sv) + nll(body));
4417 } else {
4418 temp.back() += s("{ }"sv) + nll(body);
4419 }
4420 } else {
4421 temp.back() += s("{ }"sv) + nll(classDecl);
4422 }
4423 temp.push_back(indent() + baseVar + s(".__index = "sv) + baseVar + nll(classDecl));
4424 str_list tmp;
4425 if (usage == ExpUsage::Assignment) {
4426 auto assign = x->new_ptr<Assign_t>();
4427 assign->values.push_back(toAst<Exp_t>(classVar, x));
4428 auto assignment = x->new_ptr<ExpListAssign_t>();
4429 assignment->expList.set(expList);
4430 assignment->action.set(assign);
4431 transformAssignment(assignment, tmp);
4432 }
4433 if (extend) {
4434 _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nll(classDecl);
4435 }
4436 _buf << indent() << classVar << " = setmetatable({"sv << nll(classDecl);
4437 if (!builtins.empty()) {
4438 _buf << join(builtins) << ","sv << nll(classDecl);
4439 } else {
4440 if (extend) {
4441 _buf << indent(1) << "__init = function(self, ...)"sv << nll(classDecl);
4442 _buf << indent(2) << "return _class_0.__parent.__init(self, ...)"sv << nll(classDecl);
4443 _buf << indent(1) << "end,"sv << nll(classDecl);
4444 } else {
4445 _buf << indent(1) << "__init = function() end,"sv << nll(classDecl);
4446 }
4447 }
4448 _buf << indent(1) << "__base = "sv << baseVar;
4449 if (!className.empty()) {
4450 _buf << ","sv << nll(classDecl);
4451 _buf << indent(1) << "__name = "sv << className;
4452 }
4453 if (extend) {
4454 _buf << ","sv << nll(classDecl);
4455 _buf << indent(1) << "__parent = "sv << parentVar;
4456 }
4457 _buf << nll(classDecl);
4458 _buf << indent() << "}, {"sv << nll(classDecl);
4459 if (extend) {
4460 _buf << indent(1) << "__index = function(cls, name)"sv << nll(classDecl);
4461 _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nll(classDecl);
4462 _buf << indent(2) << "if val == nil then"sv << nll(classDecl);
4463 _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nll(classDecl);
4464 _buf << indent(3) << "if parent then"sv << nll(classDecl);
4465 _buf << indent(4) << "return parent[name]"sv << nll(classDecl);
4466 _buf << indent(3) << "end"sv << nll(classDecl);
4467 _buf << indent(2) << "else"sv << nll(classDecl);
4468 _buf << indent(3) << "return val"sv << nll(classDecl);
4469 _buf << indent(2) << "end"sv << nll(classDecl);
4470 _buf << indent(1) << "end,"sv << nll(classDecl);
4471 } else {
4472 _buf << indent(1) << "__index = "sv << baseVar << ","sv << nll(classDecl);
4473 }
4474 _buf << indent(1) << "__call = function(cls, ...)"sv << nll(classDecl);
4475 pushScope();
4476 auto selfVar = getUnusedName("_self_"sv);
4477 addToScope(selfVar);
4478 _buf << indent(1) << "local "sv << selfVar << " = setmetatable({}, "sv << baseVar << ")"sv << nll(classDecl);
4479 _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nll(classDecl);
4480 _buf << indent(1) << "return "sv << selfVar << nll(classDecl);
4481 popScope();
4482 _buf << indent(1) << "end"sv << nll(classDecl);
4483 _buf << indent() << "})"sv << nll(classDecl);
4484 _buf << indent() << baseVar << ".__class = "sv << classVar << nll(classDecl);
4485 if (!statements.empty()) {
4486 _buf << indent() << "local self = "sv << classVar << ';' << nll(classDecl);
4487 }
4488 _buf << join(statements);
4489 if (extend) {
4490 _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nll(classDecl);
4491 _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nll(classDecl);
4492 _buf << indent() << "end"sv << nll(classDecl);
4493 }
4494 if (!assignItem.empty()) {
4495 _buf << indent() << assignItem << " = "sv << classVar << nll(classDecl);
4496 }
4497 switch (usage) {
4498 case ExpUsage::Return: {
4499 _buf << indent() << "return "sv << classVar << nlr(classDecl);
4500 break;
4501 }
4502 case ExpUsage::Assignment: {
4503 _buf << tmp.back();
4504 break;
4505 }
4506 default: break;
4507 }
4508 temp.push_back(clearBuf());
4509 popScope();
4510 temp.push_back(indent() + s("end"sv) + nlr(classDecl));
4511 out.push_back(join(temp));
4512 }
4513
4514 size_t transform_class_member_list(class_member_list_t* class_member_list, std::list<ClassMember>& out, const std::string& classVar) {
4515 str_list temp;
4516 size_t count = 0;
4517 for (auto keyValue : class_member_list->values.objects()) {
4518 MemType type = MemType::Common;
4519 BLOCK_START
4520 auto normal_pair = ast_cast<normal_pair_t>(keyValue);
4521 BREAK_IF(!normal_pair);
4522 auto keyName = normal_pair->key.as<KeyName_t>();
4523 BREAK_IF(!keyName);
4524 std::string newSuperCall;
4525 auto selfName = keyName->name.as<SelfName_t>();
4526 if (selfName) {
4527 type = MemType::Property;
4528 auto name = ast_cast<self_name_t>(selfName->name);
4529 if (!name) throw std::logic_error(_info.errorMessage("invalid class poperty name"sv, selfName->name));
4530 newSuperCall = classVar + s(".__parent."sv) + _parser.toString(name->name);
4531 } else {
4532 auto x = keyName;
4533 auto nameNode = keyName->name.as<Name_t>();
4534 if (!nameNode) break;
4535 auto name = _parser.toString(nameNode);
4536 if (name == "new"sv) {
4537 type = MemType::Builtin;
4538 keyName->name.set(toAst<Name_t>("__init"sv, x));
4539 newSuperCall = classVar + s(".__parent.__init"sv);
4540 } else {
4541 newSuperCall = classVar + s(".__parent.__base."sv) + name;
4542 }
4543 }
4544 normal_pair->value->traverse([&](ast_node* node) {
4545 if (node->getId() == id<ClassDecl_t>()) return traversal::Return;
4546 if (auto chainValue = ast_cast<ChainValue_t>(node)) {
4547 if (auto callable = ast_cast<Callable_t>(chainValue->items.front())) {
4548 auto var = callable->item.get();
4549 if (_parser.toString(var) == "super"sv) {
4550 auto insertSelfToArguments = [&](ast_node* item) {
4551 auto x = item;
4552 switch (item->getId()) {
4553 case id<InvokeArgs_t>(): {
4554 auto invoke = static_cast<InvokeArgs_t*>(item);
4555 invoke->args.push_front(toAst<Exp_t>("self"sv, x));
4556 return true;
4557 }
4558 case id<Invoke_t>(): {
4559 auto invoke = static_cast<Invoke_t*>(item);
4560 invoke->args.push_front(toAst<Exp_t>("self"sv, x));
4561 return true;
4562 }
4563 default:
4564 return false;
4565 }
4566 };
4567 const auto& chainList = chainValue->items.objects();
4568 if (chainList.size() >= 2) {
4569 auto it = chainList.begin();
4570 auto secondItem = *(++it);
4571 if (!insertSelfToArguments(secondItem)) {
4572 if (auto colonChainItem = ast_cast<ColonChainItem_t>(secondItem)) {
4573 if (chainList.size() > 2 && insertSelfToArguments(*(++it))) {
4574 colonChainItem->switchToDot = true;
4575 }
4576 }
4577 newSuperCall = classVar + s(".__parent"sv);
4578 }
4579 } else {
4580 newSuperCall = classVar + s(".__parent"sv);
4581 }
4582 auto newChain = toAst<ChainValue_t>(newSuperCall, chainValue);
4583 chainValue->items.pop_front();
4584 const auto& items = newChain->items.objects();
4585 for (auto it = items.rbegin(); it != items.rend(); ++it) {
4586 chainValue->items.push_front(*it);
4587 }
4588 }
4589 }
4590 }
4591 return traversal::Continue;
4592 });
4593 BLOCK_END
4594 pushScope();
4595 if (type == MemType::Property) {
4596 decIndentOffset();
4597 }
4598 switch (keyValue->getId()) {
4599 case id<variable_pair_t>():
4600 transform_variable_pair(static_cast<variable_pair_t*>(keyValue), temp);
4601 break;
4602 case id<normal_pair_t>():
4603 transform_normal_pair(static_cast<normal_pair_t*>(keyValue), temp);
4604 break;
4605 default: assert(false); break;
4606 }
4607 if (type == MemType::Property) {
4608 incIndentOffset();
4609 }
4610 popScope();
4611 out.push_back({temp.back(), type, keyValue});
4612 temp.clear();
4613 ++count;
4614 }
4615 return count;
4616 }
4617
4618 void transformAssignable(Assignable_t* assignable, str_list& out) {
4619 auto item = assignable->item.get();
4620 switch (item->getId()) {
4621 case id<AssignableChain_t>(): transformAssignableChain(static_cast<AssignableChain_t*>(item), out); break;
4622 case id<Variable_t>(): transformVariable(static_cast<Variable_t*>(item), out); break;
4623 case id<SelfName_t>(): transformSelfName(static_cast<SelfName_t*>(item), out); break;
4624 default: assert(false); break;
4625 }
4626 }
4627
4628 void transformWithClosure(With_t* with, str_list& out) {
4629 str_list temp;
4630 temp.push_back(s("(function()"sv) + nll(with));
4631 pushScope();
4632 _enableReturn.push(true);
4633 transformWith(with, temp, nullptr, true);
4634 _enableReturn.pop();
4635 popScope();
4636 temp.push_back(indent() + s("end)()"sv));
4637 out.push_back(join(temp));
4638 }
4639
4640 void transformWith(With_t* with, str_list& out, ExpList_t* assignList = nullptr, bool returnValue = false) {
4641 auto x = with;
4642 str_list temp;
4643 std::string withVar;
4644 bool scoped = false;
4645 if (with->assigns) {
4646 checkAssignable(with->valueList);
4647 auto vars = getAssignVars(with);
4648 if (vars.front().empty()) {
4649 if (with->assigns->values.objects().size() == 1) {
4650 auto var = singleVariableFrom(with->assigns->values.objects().front());
4651 if (!var.empty()) {
4652 withVar = var;
4653 }
4654 }
4655 if (withVar.empty()) {
4656 withVar = getUnusedName("_with_"sv);
4657 auto assignment = x->new_ptr<ExpListAssign_t>();
4658 assignment->expList.set(toAst<ExpList_t>(withVar, x));
4659 auto assign = x->new_ptr<Assign_t>();
4660 assign->values.push_back(with->assigns->values.objects().front());
4661 assignment->action.set(assign);
4662 if (!returnValue) {
4663 scoped = true;
4664 temp.push_back(indent() + s("do"sv) + nll(with));
4665 pushScope();
4666 }
4667 transformAssignment(assignment, temp);
4668 }
4669 auto assignment = x->new_ptr<ExpListAssign_t>();
4670 assignment->expList.set(with->valueList);
4671 auto assign = x->new_ptr<Assign_t>();
4672 assign->values.push_back(toAst<Exp_t>(withVar, x));
4673 bool skipFirst = true;
4674 for (auto value : with->assigns->values.objects()) {
4675 if (skipFirst) {
4676 skipFirst = false;
4677 continue;
4678 }
4679 assign->values.push_back(value);
4680 }
4681 assignment->action.set(assign);
4682 transformAssignment(assignment, temp);
4683 } else {
4684 withVar = vars.front();
4685 auto assignment = x->new_ptr<ExpListAssign_t>();
4686 assignment->expList.set(with->valueList);
4687 assignment->action.set(with->assigns);
4688 if (!returnValue) {
4689 scoped = true;
4690 temp.push_back(indent() + s("do"sv) + nll(with));
4691 pushScope();
4692 }
4693 transformAssignment(assignment, temp);
4694 }
4695 } else {
4696 withVar = singleVariableFrom(with->valueList);
4697 if (withVar.empty()) {
4698 withVar = getUnusedName("_with_"sv);
4699 auto assignment = x->new_ptr<ExpListAssign_t>();
4700 assignment->expList.set(toAst<ExpList_t>(withVar, x));
4701 auto assign = x->new_ptr<Assign_t>();
4702 assign->values.dup(with->valueList->exprs);
4703 assignment->action.set(assign);
4704 if (!returnValue) {
4705 scoped = true;
4706 temp.push_back(indent() + s("do"sv) + nll(with));
4707 pushScope();
4708 }
4709 transformAssignment(assignment, temp);
4710 }
4711 }
4712 if (!with->eop && !scoped && !returnValue) {
4713 pushScope();
4714 scoped = traversal::Stop == with->body->traverse([&](ast_node* node) {
4715 if (auto statement = ast_cast<Statement_t>(node)) {
4716 ClassDecl_t* clsDecl = nullptr;
4717 if (auto assignment = assignmentFrom(statement)) {
4718 auto names = getAssignDefs(assignment->expList.get());
4719 if (!names.empty()) {
4720 return traversal::Stop;
4721 }
4722 auto info = extractDestructureInfo(assignment, true);
4723 if (!info.first.empty()) {
4724 for (const auto& destruct : info.first)
4725 for (const auto& item : destruct.items)
4726 if (item.isVariable && !isDefined(item.name))
4727 return traversal::Stop;
4728 }
4729 BLOCK_START
4730 auto assign = assignment->action.as<Assign_t>();
4731 BREAK_IF(!assign);
4732 BREAK_IF(assign->values.objects().size() != 1);
4733 auto exp = ast_cast<Exp_t>(assign->values.objects().front());
4734 BREAK_IF(!exp);
4735 if (auto value = singleValueFrom(exp)) {
4736 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
4737 }
4738 BLOCK_END
4739 } else if (auto expList = expListFrom(statement)) {
4740 auto value = singleValueFrom(expList);
4741 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
4742 }
4743 if (clsDecl) {
4744 auto variable = clsDecl->name.as<Variable_t>();
4745 if (!isDefined(_parser.toString(variable))) return traversal::Stop;
4746 }
4747 return traversal::Return;
4748 }
4749 return traversal::Continue;
4750 });
4751 popScope();
4752 if (scoped) {
4753 temp.push_back(indent() + s("do"sv) + nll(with));
4754 pushScope();
4755 }
4756 }
4757 _withVars.push(withVar);
4758 if (with->eop) {
4759 auto ifNode = x->new_ptr<If_t>();
4760 ifNode->nodes.push_back(toAst<IfCond_t>(withVar + s("~=nil"sv), x));
4761 ifNode->nodes.push_back(with->body);
4762 transformIf(ifNode, temp, ExpUsage::Common);
4763 } else {
4764 transform_plain_body(with->body, temp, ExpUsage::Common);
4765 }
4766 _withVars.pop();
4767 if (assignList) {
4768 auto assignment = x->new_ptr<ExpListAssign_t>();
4769 assignment->expList.set(assignList);
4770 auto assign = x->new_ptr<Assign_t>();
4771 assign->values.push_back(toAst<Exp_t>(withVar, x));
4772 assignment->action.set(assign);
4773 transformAssignment(assignment, temp);
4774 }
4775 if (returnValue) {
4776 auto last = lastStatementFrom(with->body);
4777 if (last && !last->content.is<Return_t>()) {
4778 temp.push_back(indent() + s("return "sv) + withVar + nll(with));
4779 }
4780 }
4781 if (scoped) {
4782 popScope();
4783 temp.push_back(indent() + s("end"sv) + nll(with));
4784 }
4785 out.push_back(join(temp));
4786 }
4787
4788 void transform_const_value(const_value_t* const_value, str_list& out) {
4789 out.push_back(_parser.toString(const_value));
4790 }
4791
4792 void transformGlobal(Global_t* global, str_list& out) {
4793 auto x = global;
4794 auto item = global->item.get();
4795 switch (item->getId()) {
4796 case id<ClassDecl_t>(): {
4797 auto classDecl = static_cast<ClassDecl_t*>(item);
4798 if (classDecl->name && classDecl->name->item->getId() == id<Variable_t>()) {
4799 markVarGlobal(GlobalMode::Any, true);
4800 addGlobalVar(_parser.toString(classDecl->name->item));
4801 }
4802 transformClassDecl(classDecl, out, ExpUsage::Common);
4803 break;
4804 }
4805 case id<global_op_t>():
4806 if (_parser.toString(item) == "*"sv) {
4807 markVarGlobal(GlobalMode::Any, false);
4808 } else {
4809 markVarGlobal(GlobalMode::Capital, false);
4810 }
4811 break;
4812 case id<global_values_t>(): {
4813 markVarGlobal(GlobalMode::Any, true);
4814 auto values = global->item.to<global_values_t>();
4815 if (values->valueList) {
4816 auto expList = x->new_ptr<ExpList_t>();
4817 for (auto name : values->nameList->names.objects()) {
4818 addGlobalVar(_parser.toString(name));
4819 auto callable = x->new_ptr<Callable_t>();
4820 callable->item.set(name);
4821 auto chainValue = x->new_ptr<ChainValue_t>();
4822 chainValue->items.push_back(callable);
4823 auto value = x->new_ptr<Value_t>();
4824 value->item.set(chainValue);
4825 auto exp = newExp(value, x);
4826 expList->exprs.push_back(exp);
4827 }
4828 auto assignment = x->new_ptr<ExpListAssign_t>();
4829 assignment->expList.set(expList);
4830 auto assign = x->new_ptr<Assign_t>();
4831 if (auto expListLow = values->valueList.as<ExpListLow_t>()) {
4832 assign->values.dup(expListLow->exprs);
4833 } else {
4834 auto tableBlock = values->valueList.to<TableBlock_t>();
4835 assign->values.push_back(tableBlock);
4836 }
4837 assignment->action.set(assign);
4838 transformAssignment(assignment, out);
4839 } else {
4840 for (auto name : values->nameList->names.objects()) {
4841 addGlobalVar(_parser.toString(name));
4842 }
4843 }
4844 break;
4845 }
4846 default: assert(false); break;
4847 }
4848 }
4849
4850 void transformExport(Export_t* exportNode, str_list& out) {
4851 auto x = exportNode;
4852 if (_scopes.size() > 1) {
4853 throw std::logic_error(_info.errorMessage("can not do module export outside the root block"sv, exportNode));
4854 }
4855 if (exportNode->assign) {
4856 auto expList = exportNode->target.to<ExpList_t>();
4857 if (expList->exprs.size() != exportNode->assign->values.size()) {
4858 throw std::logic_error(_info.errorMessage("left and right expressions must be matched in export statement"sv, x));
4859 }
4860 for (auto _exp : expList->exprs.objects()) {
4861 auto exp = static_cast<Exp_t*>(_exp);
4862 if (!variableFrom(exp) &&
4863 !exp->getByPath<unary_exp_t, Value_t, SimpleValue_t, TableLit_t>() &&
4864 !exp->getByPath<unary_exp_t, Value_t, simple_table_t>()) {
4865 throw std::logic_error(_info.errorMessage("left hand expressions must be variables in export statement"sv, x));
4866 }
4867 }
4868 auto assignment = x->new_ptr<ExpListAssign_t>();
4869 assignment->expList.set(expList);
4870 assignment->action.set(exportNode->assign);
4871 transformAssignment(assignment, out);
4872 str_list names = transformAssignDefs(expList, false);
4873 auto info = extractDestructureInfo(assignment, true);
4874 if (!info.first.empty()) {
4875 for (const auto& destruct : info.first)
4876 for (const auto& item : destruct.items)
4877 if (item.isVariable)
4878 names.push_back(item.name);
4879 }
4880 if (_info.exportDefault) {
4881 out.back().append(indent() + _info.moduleName + s(" = "sv) + names.back() + nlr(exportNode));
4882 } else {
4883 str_list lefts, rights;
4884 for (const auto& name : names) {
4885 lefts.push_back(_info.moduleName + s("[\""sv) + name + s("\"]"sv));
4886 rights.push_back(name);
4887 }
4888 out.back().append(indent() + join(lefts,", "sv) + s(" = "sv) + join(rights, ", "sv) + nlr(exportNode));
4889 }
4890 } else {
4891 if (auto macro = exportNode->target.as<Macro_t>()) {
4892 transformMacro(macro, out, true);
4893 } else if (_info.exportDefault) {
4894 auto exp = exportNode->target.to<Exp_t>();
4895 auto assignment = x->new_ptr<ExpListAssign_t>();
4896 assignment->expList.set(toAst<ExpList_t>(_info.moduleName, x));
4897 auto assign = x->new_ptr<Assign_t>();
4898 assign->values.push_back(exp);
4899 assignment->action.set(assign);
4900 transformAssignment(assignment, out);
4901 } else {
4902 str_list temp;
4903 auto expList = exportNode->target.to<ExpList_t>();
4904 auto assignment = x->new_ptr<ExpListAssign_t>();
4905 auto assignList = toAst<ExpList_t>(_info.moduleName + s("[#"sv) + _info.moduleName + s("+1]"sv), x);
4906 assignment->expList.set(assignList);
4907 for (auto exp : expList->exprs.objects()) {
4908 if (auto classDecl = exp->getByPath<unary_exp_t, Value_t, SimpleValue_t, ClassDecl_t>()) {
4909 if (classDecl->name && classDecl->name->item->getId() == id<Variable_t>()) {
4910 transformClassDecl(classDecl, temp, ExpUsage::Common);
4911 auto name = _parser.toString(classDecl->name->item);
4912 assignment->expList.set(toAst<ExpList_t>(_info.moduleName + s("[\""sv) + name + s("\"]"sv), x));
4913 auto assign = x->new_ptr<Assign_t>();
4914 assign->values.push_back(toAst<Exp_t>(name, x));
4915 assignment->action.set(assign);
4916 transformAssignment(assignment, temp);
4917 assignment->expList.set(assignList);
4918 continue;
4919 }
4920 }
4921 auto assign = x->new_ptr<Assign_t>();
4922 assign->values.push_back(exp);
4923 assignment->action.set(assign);
4924 transformAssignment(assignment, temp);
4925 }
4926 out.push_back(join(temp));
4927 }
4928 }
4929 }
4930
4931 void transformTable(ast_node* table, const node_container& pairs, str_list& out) {
4932 if (pairs.empty()) {
4933 out.push_back(s("{ }"sv));
4934 return;
4935 }
4936 str_list temp;
4937 incIndentOffset();
4938 for (auto pair : pairs) {
4939 switch (pair->getId()) {
4940 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(pair), temp, ExpUsage::Closure); break;
4941 case id<variable_pair_t>(): transform_variable_pair(static_cast<variable_pair_t*>(pair), temp); break;
4942 case id<normal_pair_t>(): transform_normal_pair(static_cast<normal_pair_t*>(pair), temp); break;
4943 case id<TableBlockIndent_t>(): transformTableBlockIndent(static_cast<TableBlockIndent_t*>(pair), temp); break;
4944 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(pair), temp); break;
4945 default: assert(false); break;
4946 }
4947 temp.back() = indent() + temp.back() + (pair == pairs.back() ? Empty : s(","sv)) + nll(pair);
4948 }
4949 out.push_back(s("{"sv) + nll(table) + join(temp));
4950 decIndentOffset();
4951 out.back() += (indent() + s("}"sv));
4952 }
4953
4954 void transform_simple_table(simple_table_t* table, str_list& out) {
4955 transformTable(table, table->pairs.objects(), out);
4956 }
4957
4958 void transformTblComprehension(TblComprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
4959 switch (usage) {
4960 case ExpUsage::Closure:
4961 pushScope();
4962 _enableReturn.push(true);
4963 break;
4964 case ExpUsage::Assignment:
4965 pushScope();
4966 break;
4967 default:
4968 break;
4969 }
4970 auto x = comp;
4971 str_list kv;
4972 std::string tbl = getUnusedName("_tbl_"sv);
4973 addToScope(tbl);
4974 str_list temp;
4975 auto compInner = comp->forLoop.get();
4976 for (auto item : compInner->items.objects()) {
4977 switch (item->getId()) {
4978 case id<CompForEach_t>():
4979 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
4980 break;
4981 case id<CompFor_t>():
4982 transformCompFor(static_cast<CompFor_t*>(item), temp);
4983 break;
4984 case id<Exp_t>():
4985 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
4986 temp.back() = indent() + s("if "sv) + temp.back() + s(" then"sv) + nll(item);
4987 pushScope();
4988 break;
4989 default: assert(false); break;
4990 }
4991 }
4992 transformExp(comp->key, kv, ExpUsage::Closure);
4993 if (comp->value) {
4994 transformExp(comp->value->value, kv, ExpUsage::Closure);
4995 }
4996 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
4997 popScope();
4998 }
4999 _buf << indent() << "local "sv << tbl << " = { }"sv << nll(comp);
5000 _buf << join(temp);
5001 pushScope();
5002 if (!comp->value) {
5003 auto keyVar = getUnusedName("_key_"sv);
5004 auto valVar = getUnusedName("_val_"sv);
5005 _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nll(comp);
5006 kv.front() = keyVar;
5007 kv.push_back(valVar);
5008 }
5009 _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nll(comp);
5010 for (int ind = int(temp.size()) - 2; ind > -1 ; --ind) {
5011 _buf << indent(ind) << "end"sv << nll(comp);
5012 }
5013 popScope();
5014 _buf << indent() << "end"sv << nll(comp);
5015 switch (usage) {
5016 case ExpUsage::Closure:
5017 out.push_back(clearBuf() + indent() + s("return "sv) + tbl + nlr(comp));
5018 popScope();
5019 _enableReturn.pop();
5020 out.back().insert(0, s("(function()"sv) + nll(comp));
5021 out.back().append(indent() + s("end)()"sv));
5022 break;
5023 case ExpUsage::Assignment: {
5024 out.push_back(clearBuf());
5025 auto assign = x->new_ptr<Assign_t>();
5026 assign->values.push_back(toAst<Exp_t>(tbl, x));
5027 auto assignment = x->new_ptr<ExpListAssign_t>();
5028 assignment->expList.set(assignList);
5029 assignment->action.set(assign);
5030 transformAssignment(assignment, temp);
5031 out.back().append(temp.back());
5032 popScope();
5033 out.back().insert(0, indent() + s("do"sv) + nll(comp));
5034 out.back().append(indent() + s("end"sv) + nlr(comp));
5035 break;
5036 }
5037 case ExpUsage::Return:
5038 out.push_back(clearBuf() + indent() + s("return "sv) + tbl + nlr(comp));
5039 break;
5040 default:
5041 break;
5042 }
5043 }
5044
5045 void transformCompFor(CompFor_t* comp, str_list& out) {
5046 str_list temp;
5047 std::string varName = _parser.toString(comp->varName);
5048 transformExp(comp->startValue, temp, ExpUsage::Closure);
5049 transformExp(comp->stopValue, temp, ExpUsage::Closure);
5050 if (comp->stepValue) {
5051 transformExp(comp->stepValue->value, temp, ExpUsage::Closure);
5052 } else {
5053 temp.emplace_back();
5054 }
5055 auto it = temp.begin();
5056 const auto& start = *it;
5057 const auto& stop = *(++it);
5058 const auto& step = *(++it);
5059 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : s(", "sv) + step) << " do"sv << nll(comp);
5060 out.push_back(clearBuf());
5061 pushScope();
5062 addToScope(varName);
5063 }
5064
5065 void transformTableBlockIndent(TableBlockIndent_t* table, str_list& out) {
5066 transformTable(table, table->values.objects(), out);
5067 }
5068
5069 void transformTableBlock(TableBlock_t* table, str_list& out) {
5070 transformTable(table, table->values.objects(), out);
5071 }
5072
5073 void transformDo(Do_t* doNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
5074 str_list temp;
5075 if (usage == ExpUsage::Closure) {
5076 temp.push_back(s("(function()"sv) + nll(doNode));
5077 _enableReturn.push(true);
5078 } else {
5079 temp.push_back(indent() + s("do"sv) + nll(doNode));
5080 }
5081 pushScope();
5082 transformBody(doNode->body, temp, usage, assignList);
5083 popScope();
5084 if (usage == ExpUsage::Closure) {
5085 _enableReturn.pop();
5086 temp.push_back(indent() + s("end)()"sv));
5087 } else {
5088 temp.push_back(indent() + s("end"sv) + nlr(doNode));
5089 }
5090 out.push_back(join(temp));
5091 }
5092
5093 void transformImportFrom(ImportFrom_t* import, str_list& out) {
5094 str_list temp;
5095 auto x = import;
5096 auto objVar = singleVariableFrom(import->exp);
5097 ast_ptr<false, ExpListAssign_t> objAssign;
5098 if (objVar.empty()) {
5099 objVar = getUnusedName("_obj_"sv);
5100 auto expList = toAst<ExpList_t>(objVar, x);
5101 auto assign = x->new_ptr<Assign_t>();
5102 assign->values.push_back(import->exp);
5103 auto assignment = x->new_ptr<ExpListAssign_t>();
5104 assignment->expList.set(expList);
5105 assignment->action.set(assign);
5106 objAssign.set(assignment);
5107 }
5108 auto expList = x->new_ptr<ExpList_t>();
5109 auto assign = x->new_ptr<Assign_t>();
5110 for (auto name : import->names.objects()) {
5111 switch (name->getId()) {
5112 case id<Variable_t>(): {
5113 auto var = ast_to<Variable_t>(name);
5114 {
5115 auto callable = toAst<Callable_t>(objVar, x);
5116 auto dotChainItem = x->new_ptr<DotChainItem_t>();
5117 dotChainItem->name.set(var->name);
5118 auto chainValue = x->new_ptr<ChainValue_t>();
5119 chainValue->items.push_back(callable);
5120 chainValue->items.push_back(dotChainItem);
5121 auto value = x->new_ptr<Value_t>();
5122 value->item.set(chainValue);
5123 auto exp = newExp(value, x);
5124 assign->values.push_back(exp);
5125 }
5126 auto callable = x->new_ptr<Callable_t>();
5127 callable->item.set(var);
5128 auto chainValue = x->new_ptr<ChainValue_t>();
5129 chainValue->items.push_back(callable);
5130 auto value = x->new_ptr<Value_t>();
5131 value->item.set(chainValue);
5132 auto exp = newExp(value, x);
5133 expList->exprs.push_back(exp);
5134 break;
5135 }
5136 case id<colon_import_name_t>(): {
5137 auto var = static_cast<colon_import_name_t*>(name)->name.get();
5138 {
5139 auto nameNode = var->name.get();
5140 auto callable = toAst<Callable_t>(objVar, x);
5141 auto colonChain = x->new_ptr<ColonChainItem_t>();
5142 colonChain->name.set(nameNode);
5143 auto chainValue = x->new_ptr<ChainValue_t>();
5144 chainValue->items.push_back(callable);
5145 chainValue->items.push_back(colonChain);
5146 auto value = x->new_ptr<Value_t>();
5147 value->item.set(chainValue);
5148 auto exp = newExp(value, x);
5149 assign->values.push_back(exp);
5150 }
5151 auto callable = x->new_ptr<Callable_t>();
5152 callable->item.set(var);
5153 auto chainValue = x->new_ptr<ChainValue_t>();
5154 chainValue->items.push_back(callable);
5155 auto value = x->new_ptr<Value_t>();
5156 value->item.set(chainValue);
5157 auto exp = newExp(value, x);
5158 expList->exprs.push_back(exp);
5159 break;
5160 }
5161 default: assert(false); break;
5162 }
5163 }
5164 if (objAssign) {
5165 auto preDef = getPredefine(transformAssignDefs(expList));
5166 if (!preDef.empty()) {
5167 temp.push_back(preDef + nll(import));
5168 }
5169 temp.push_back(indent() + s("do"sv) + nll(import));
5170 pushScope();
5171 transformAssignment(objAssign, temp);
5172 }
5173 auto assignment = x->new_ptr<ExpListAssign_t>();
5174 assignment->expList.set(expList);
5175 assignment->action.set(assign);
5176 transformAssignment(assignment, temp);
5177 if (objAssign) {
5178 popScope();
5179 temp.push_back(indent() + s("end"sv) + nlr(import));
5180 }
5181 out.push_back(join(temp));
5182 }
5183
5184 std::string moduleNameFrom(ImportLiteral_t* literal) {
5185 auto name = _parser.toString(literal->inners.back());
5186 Utils::replace(name, "-"sv, "_"sv);
5187 Utils::replace(name, " "sv, "_"sv);
5188 return name;
5189 }
5190
5191 void transformImportAs(ImportAs_t* import, str_list& out) {
5192 auto x = import;
5193 if (!import->target) {
5194 auto name = moduleNameFrom(import->literal);
5195 import->target.set(toAst<Variable_t>(name, x));
5196 }
5197 if (auto tabLit = import->target.as<ImportTabLit_t>()) {
5198 auto newTab = x->new_ptr<ImportTabLit_t>();
5199#ifndef MOONP_NO_MACRO
5200 bool importAllMacro = false;
5201 std::list<std::pair<std::string,std::string>> macroPairs;
5202 for (auto item : tabLit->items.objects()) {
5203 switch (item->getId()) {
5204 case id<MacroName_t>(): {
5205 auto macroName = static_cast<MacroName_t*>(item);
5206 auto name = _parser.toString(macroName->name);
5207 macroPairs.emplace_back(name, name);
5208 break;
5209 }
5210 case id<macro_name_pair_t>(): {
5211 auto pair = static_cast<macro_name_pair_t*>(item);
5212 macroPairs.emplace_back(_parser.toString(pair->key->name), _parser.toString(pair->value->name));
5213 break;
5214 }
5215 case id<import_all_macro_t>():
5216 if (importAllMacro) throw std::logic_error(_info.errorMessage(s("import all macro symbol duplicated"sv), item));
5217 importAllMacro = true;
5218 break;
5219 case id<variable_pair_t>():
5220 case id<normal_pair_t>():
5221 newTab->items.push_back(item);
5222 break;
5223 default: assert(false); break;
5224 }
5225 }
5226 if (importAllMacro || !macroPairs.empty()) {
5227 auto moduleName = _parser.toString(import->literal);
5228 Utils::replace(moduleName, "'"sv, ""sv);
5229 Utils::replace(moduleName, "\""sv, ""sv);
5230 Utils::trim(moduleName);
5231 pushCurrentModule(); // cur
5232 int top = lua_gettop(L) - 1; // Lua state may be setup by pushCurrentModule()
5233 DEFER(lua_settop(L, top));
5234 pushMoonp("find_modulepath"sv); // cur find_modulepath
5235 lua_pushlstring(L, moduleName.c_str(), moduleName.size()); // cur find_modulepath moduleName
5236 if (lua_pcall(L, 1, 1, 0) != 0) {
5237 std::string err = lua_tostring(L, -1);
5238 throw std::logic_error(_info.errorMessage(s("failed to resolve module path\n"sv) + err, x));
5239 }
5240 if (lua_isnil(L, -1) != 0) {
5241 throw std::logic_error(_info.errorMessage(s("failed to find module '"sv) + moduleName + '\'', x));
5242 }
5243 std::string moduleFullName = lua_tostring(L, -1);
5244 lua_pop(L, 1); // cur
5245 if (!isModuleLoaded(moduleFullName)) {
5246 pushMoonp("read_file"sv); // cur read_file
5247 lua_pushlstring(L, moduleFullName.c_str(), moduleFullName.size()); // cur load_text moduleFullName
5248 if (lua_pcall(L, 1, 1, 0) != 0) {
5249 std::string err = lua_tostring(L, -1);
5250 throw std::logic_error(_info.errorMessage(s("failed to read module file\n"sv) + err, x));
5251 } // cur text
5252 if (lua_isnil(L, -1) != 0) {
5253 throw std::logic_error(_info.errorMessage("failed to get module text"sv, x));
5254 } // cur text
5255 std::string text = lua_tostring(L, -1);
5256 auto compiler = MoonCompilerImpl(L, _luaOpen, false, moduleFullName);
5257 MoonConfig config;
5258 config.lineOffset = 0;
5259 config.lintGlobalVariable = false;
5260 config.reserveLineNumber = false;
5261 config.implicitReturnRoot = _config.implicitReturnRoot;
5262 auto result = compiler.compile(text, config);
5263 if (result.codes.empty() && !result.error.empty()) {
5264 throw std::logic_error(_info.errorMessage(s("failed to compile module '"sv) + moduleName + s("\': "sv) + result.error, x));
5265 }
5266 lua_pop(L, 1); // cur
5267 }
5268 pushModuleTable(moduleFullName); // cur mod
5269 if (importAllMacro) {
5270 lua_pushnil(L); // cur mod startKey
5271 while (lua_next(L, -2) != 0) { // cur mod key value
5272 lua_pushvalue(L, -2); // cur mod key value key
5273 lua_insert(L, -2); // cur mod key key value
5274 lua_rawset(L, -5); // cur[key] = value, cur mod key
5275 }
5276 }
5277 for (const auto& pair : macroPairs) {
5278 lua_getfield(L, -1, pair.first.c_str()); // mod[first], cur mod val
5279 lua_setfield(L, -3, pair.second.c_str()); // cur[second] = val, cur mod
5280 }
5281 }
5282#else // MOONP_NO_MACRO
5283 for (auto item : tabLit->items.objects()) {
5284 switch (item->getId()) {
5285 case id<MacroName_t>():
5286 case id<macro_name_pair_t>():
5287 case id<import_all_macro_t>(): {
5288 throw std::logic_error(_info.errorMessage("macro feature not supported"sv, item));
5289 break;
5290 }
5291 case id<variable_pair_t>():
5292 case id<normal_pair_t>():
5293 newTab->items.push_back(item);
5294 break;
5295 default: assert(false); break;
5296 }
5297 }
5298#endif // MOONP_NO_MACRO
5299 if (newTab->items.empty()) {
5300 out.push_back(Empty);
5301 return;
5302 } else {
5303 import->target.set(newTab);
5304 }
5305 }
5306 auto target = import->target.get();
5307 auto value = x->new_ptr<Value_t>();
5308 if (auto var = ast_cast<Variable_t>(target)) {
5309 auto callable = x->new_ptr<Callable_t>();
5310 callable->item.set(var);
5311 auto chainValue = x->new_ptr<ChainValue_t>();
5312 chainValue->items.push_back(callable);
5313 value->item.set(chainValue);
5314 } else {
5315 auto tabLit = ast_to<ImportTabLit_t>(target);
5316 auto simpleValue = x->new_ptr<SimpleValue_t>();
5317 auto tableLit = x->new_ptr<TableLit_t>();
5318 tableLit->values.dup(tabLit->items);
5319 simpleValue->value.set(tableLit);
5320 value->item.set(simpleValue);
5321 }
5322 auto exp = newExp(value, x);
5323 auto assignList = x->new_ptr<ExpList_t>();
5324 assignList->exprs.push_back(exp);
5325 auto assign = x->new_ptr<Assign_t>();
5326 assign->values.push_back(toAst<Exp_t>(s("require "sv) + _parser.toString(import->literal), x));
5327 auto assignment = x->new_ptr<ExpListAssign_t>();
5328 assignment->expList.set(assignList);
5329 assignment->action.set(assign);
5330 transformAssignment(assignment, out);
5331 }
5332
5333 void transformImport(Import_t* import, str_list& out) {
5334 auto content = import->content.get();
5335 switch (content->getId()) {
5336 case id<ImportAs_t>():
5337 transformImportAs(static_cast<ImportAs_t*>(content), out);
5338 break;
5339 case id<ImportFrom_t>():
5340 transformImportFrom(static_cast<ImportFrom_t*>(content), out);
5341 break;
5342 default: assert(false); break;
5343 }
5344 }
5345
5346 void transformWhileInPlace(While_t* whileNode, str_list& out, ExpList_t* expList = nullptr) {
5347 auto x = whileNode;
5348 str_list temp;
5349 if (expList) {
5350 temp.push_back(indent() + s("do"sv) + nll(whileNode));
5351 }
5352 pushScope();
5353 auto accumVar = getUnusedName("_accum_"sv);
5354 addToScope(accumVar);
5355 auto lenVar = getUnusedName("_len_"sv);
5356 addToScope(lenVar);
5357 temp.push_back(indent() + s("local "sv) + accumVar + s(" = { }"sv) + nll(whileNode));
5358 temp.push_back(indent() + s("local "sv) + lenVar + s(" = 1"sv) + nll(whileNode));
5359 transformExp(whileNode->condition, temp, ExpUsage::Closure);
5360 temp.back() = indent() + s("while "sv) + temp.back() + s(" do"sv) + nll(whileNode);
5361 pushScope();
5362 auto assignLeft = toAst<ExpList_t>(accumVar + s("["sv) + lenVar + s("]"sv), x);
5363 auto lenLine = lenVar + s(" = "sv) + lenVar + s(" + 1"sv) + nlr(whileNode);
5364 transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft);
5365 popScope();
5366 temp.push_back(indent() + s("end"sv) + nlr(whileNode));
5367 if (expList) {
5368 auto assign = x->new_ptr<Assign_t>();
5369 assign->values.push_back(toAst<Exp_t>(accumVar, x));
5370 auto assignment = x->new_ptr<ExpListAssign_t>();
5371 assignment->expList.set(expList);
5372 assignment->action.set(assign);
5373 transformAssignment(assignment, temp);
5374 } else {
5375 temp.push_back(indent() + s("return "sv) + accumVar + nlr(whileNode));
5376 }
5377 popScope();
5378 if (expList) {
5379 temp.push_back(indent() + s("end"sv) + nlr(whileNode));
5380 }
5381 out.push_back(join(temp));
5382 }
5383
5384 void transformWhileClosure(While_t* whileNode, str_list& out) {
5385 auto x = whileNode;
5386 str_list temp;
5387 temp.push_back(s("(function() "sv) + nll(whileNode));
5388 pushScope();
5389 _enableReturn.push(true);
5390 auto accumVar = getUnusedName("_accum_"sv);
5391 addToScope(accumVar);
5392 auto lenVar = getUnusedName("_len_"sv);
5393 addToScope(lenVar);
5394 temp.push_back(indent() + s("local "sv) + accumVar + s(" = { }"sv) + nll(whileNode));
5395 temp.push_back(indent() + s("local "sv) + lenVar + s(" = 1"sv) + nll(whileNode));
5396 transformExp(whileNode->condition, temp, ExpUsage::Closure);
5397 temp.back() = indent() + s("while "sv) + temp.back() + s(" do"sv) + nll(whileNode);
5398 pushScope();
5399 auto assignLeft = toAst<ExpList_t>(accumVar + s("["sv) + lenVar + s("]"sv), x);
5400 auto lenLine = lenVar + s(" = "sv) + lenVar + s(" + 1"sv) + nlr(whileNode);
5401 transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft);
5402 popScope();
5403 temp.push_back(indent() + s("end"sv) + nlr(whileNode));
5404 temp.push_back(indent() + s("return "sv) + accumVar + nlr(whileNode));
5405 _enableReturn.pop();
5406 popScope();
5407 temp.push_back(indent() + s("end)()"sv));
5408 out.push_back(join(temp));
5409 }
5410
5411 void transformWhile(While_t* whileNode, str_list& out) {
5412 str_list temp;
5413 pushScope();
5414 transformExp(whileNode->condition, temp, ExpUsage::Closure);
5415 transformLoopBody(whileNode->body, temp, Empty, ExpUsage::Common);
5416 popScope();
5417 _buf << indent() << "while "sv << temp.front() << " do"sv << nll(whileNode);
5418 _buf << temp.back();
5419 _buf << indent() << "end"sv << nlr(whileNode);
5420 out.push_back(clearBuf());
5421 }
5422
5423 void transformRepeat(Repeat_t* repeat, str_list& out) {
5424 str_list temp;
5425 pushScope();
5426 transformLoopBody(repeat->body->content, temp, Empty, ExpUsage::Common);
5427 transformExp(repeat->condition, temp, ExpUsage::Closure);
5428 popScope();
5429 _buf << indent() << "repeat"sv << nll(repeat);
5430 _buf << temp.front();
5431 _buf << indent() << "until "sv << temp.back() << nlr(repeat);
5432 out.push_back(clearBuf());
5433 }
5434
5435 void transformSwitch(Switch_t* switchNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
5436 str_list temp;
5437 if (usage == ExpUsage::Closure) {
5438 temp.push_back(s("(function()"sv) + nll(switchNode));
5439 pushScope();
5440 _enableReturn.push(true);
5441 }
5442 auto objVar = singleVariableFrom(switchNode->target);
5443 if (objVar.empty()) {
5444 objVar = getUnusedName("_exp_"sv);
5445 addToScope(objVar);
5446 transformExp(switchNode->target, temp, ExpUsage::Closure);
5447 _buf << indent() << "local "sv << objVar << " = "sv << temp.back() << nll(switchNode);
5448 temp.back() = clearBuf();
5449 }
5450 const auto& branches = switchNode->branches.objects();
5451 for (auto branch_ : branches) {
5452 auto branch = static_cast<SwitchCase_t*>(branch_);
5453 temp.push_back(indent() + s(branches.front() == branch ? "if"sv : "elseif"sv));
5454 str_list tmp;
5455 const auto& exprs = branch->valueList->exprs.objects();
5456 for (auto exp_ : exprs) {
5457 auto exp = static_cast<Exp_t*>(exp_);
5458 transformExp(exp, tmp, ExpUsage::Closure);
5459 if (!singleValueFrom(exp)) {
5460 tmp.back() = s("("sv) + tmp.back() + s(")"sv);
5461 }
5462 temp.back().append(s(" "sv) + tmp.back() + s(" == "sv) + objVar +
5463 s(exp == exprs.back() ? ""sv : " or"sv));
5464 }
5465 temp.back().append(s(" then"sv) + nll(branch));
5466 pushScope();
5467 transform_plain_body(branch->body, temp, usage, assignList);
5468 popScope();
5469 }
5470 if (switchNode->lastBranch) {
5471 temp.push_back(indent() + s("else"sv) + nll(switchNode->lastBranch));
5472 pushScope();
5473 transform_plain_body(switchNode->lastBranch, temp, usage, assignList);
5474 popScope();
5475 }
5476 temp.push_back(indent() + s("end"sv) + nlr(switchNode));
5477 if (usage == ExpUsage::Closure) {
5478 _enableReturn.pop();
5479 popScope();
5480 temp.push_back(indent() + s("end)()"sv));
5481 }
5482 out.push_back(join(temp));
5483 }
5484
5485 void transformLocalDef(Local_t* local, str_list& out) {
5486 if (!local->forceDecls.empty() || !local->decls.empty()) {
5487 str_list defs;
5488 for (const auto& decl : local->forceDecls) {
5489 forceAddToScope(decl);
5490 defs.push_back(decl);
5491 }
5492 for (const auto& decl : local->decls) {
5493 if (addToScope(decl)) {
5494 defs.push_back(decl);
5495 }
5496 }
5497 auto preDefine = getPredefine(defs);
5498 if (!preDefine.empty()) {
5499 out.push_back(preDefine + nll(local));
5500 }
5501 }
5502 }
5503
5504 void transformLocal(Local_t* local, str_list& out) {
5505 str_list temp;
5506 if (!local->defined) {
5507 local->defined = true;
5508 transformLocalDef(local, temp);
5509 }
5510 if (auto values = local->item.as<local_values_t>()) {
5511 if (values->valueList) {
5512 auto x = local;
5513 auto expList = x->new_ptr<ExpList_t>();
5514 for (auto name : values->nameList->names.objects()) {
5515 auto callable = x->new_ptr<Callable_t>();
5516 callable->item.set(name);
5517 auto chainValue = x->new_ptr<ChainValue_t>();
5518 chainValue->items.push_back(callable);
5519 auto value = x->new_ptr<Value_t>();
5520 value->item.set(chainValue);
5521 auto exp = newExp(value, x);
5522 expList->exprs.push_back(exp);
5523 }
5524 auto assignment = x->new_ptr<ExpListAssign_t>();
5525 assignment->expList.set(expList);
5526 auto assign = x->new_ptr<Assign_t>();
5527 if (auto expListLow = values->valueList.as<ExpListLow_t>()) {
5528 assign->values.dup(expListLow->exprs);
5529 } else {
5530 auto tableBlock = values->valueList.to<TableBlock_t>();
5531 assign->values.push_back(tableBlock);
5532 }
5533 assignment->action.set(assign);
5534 transformAssignment(assignment, temp);
5535 }
5536 }
5537 out.push_back(join(temp));
5538 }
5539
5540 void transformLocalAttrib(LocalAttrib_t* localAttrib, str_list& out) {
5541 auto x = localAttrib;
5542 auto attrib = _parser.toString(localAttrib->attrib);
5543 if (attrib != "close"sv && attrib != "const"sv) {
5544 throw std::logic_error(_info.errorMessage(s("unknown attribute '"sv) + attrib + '\'', localAttrib->attrib));
5545 }
5546 auto expList = x->new_ptr<ExpList_t>();
5547 str_list tmpVars;
5548 str_list vars;
5549 pushScope();
5550 for (auto name : localAttrib->nameList->names.objects()) {
5551 auto callable = x->new_ptr<Callable_t>();
5552 callable->item.set(name);
5553 auto chainValue = x->new_ptr<ChainValue_t>();
5554 chainValue->items.push_back(callable);
5555 auto value = x->new_ptr<Value_t>();
5556 value->item.set(chainValue);
5557 auto exp = newExp(value, x);
5558 expList->exprs.push_back(exp);
5559 tmpVars.push_back(getUnusedName("_var_"sv));
5560 addToScope(tmpVars.back());
5561 vars.push_back(_parser.toString(name));
5562 }
5563 popScope();
5564 auto tmpVarStr = join(tmpVars, ", "sv);
5565 auto tmpVarList = toAst<ExpList_t>(tmpVarStr, x);
5566 auto assignment = x->new_ptr<ExpListAssign_t>();
5567 assignment->expList.set(tmpVarList);
5568 assignment->action.set(localAttrib->assign);
5569 str_list temp;
5570 transformAssignment(assignment, temp);
5571 attrib = s(" <"sv) + attrib + '>';
5572 for (auto& var : vars) {
5573 forceAddToScope(var);
5574 var.append(attrib);
5575 }
5576 temp.push_back(indent() + s("local "sv) + join(vars, ", "sv) + s(" = "sv) + tmpVarStr + nll(x));
5577 out.push_back(join(temp));
5578 }
5579
5580 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) {
5581 auto keyword = _parser.toString(breakLoop);
5582 if (keyword == "break"sv) {
5583 out.push_back(indent() + keyword + nll(breakLoop));
5584 return;
5585 }
5586 if (_continueVars.empty()) throw std::logic_error(_info.errorMessage("continue is not inside a loop"sv, breakLoop));
5587 _buf << indent() << _continueVars.top() << " = true"sv << nll(breakLoop);
5588 _buf << indent() << "break"sv << nll(breakLoop);
5589 out.push_back(clearBuf());
5590 }
5591
5592 void transformLabel(Label_t* label, str_list& out) {
5593 out.push_back(indent() + s("::"sv) + _parser.toString(label->label) + s("::"sv) + nll(label));
5594 }
5595
5596 void transformGoto(Goto_t* gotoNode, str_list& out) {
5597 out.push_back(indent() + s("goto "sv) + _parser.toString(gotoNode->label) + nll(gotoNode));
5598 }
5599};
5600
5601const std::string MoonCompilerImpl::Empty;
5602
5603MoonCompiler::MoonCompiler(void* sharedState,
5604 const std::function<void(void*)>& luaOpen,
5605 bool sameModule):
5606#ifndef MOONP_NO_MACRO
5607_compiler(std::make_unique<MoonCompilerImpl>(static_cast<lua_State*>(sharedState), luaOpen, sameModule)) {}
5608#else
5609_compiler(std::make_unique<MoonCompilerImpl>()) {
5610 (void)sharedState;
5611 (void)luaOpen;
5612 (void)sameModule;
5613}
5614#endif // MOONP_NO_MACRO
5615
5616MoonCompiler::~MoonCompiler() {}
5617
5618CompileInfo MoonCompiler::compile(std::string_view codes, const MoonConfig& config) {
5619 return _compiler->compile(codes, config);
5620}
5621
5622} // namespace MoonP
diff --git a/src/MoonP/moon_compiler.h b/src/MoonP/moon_compiler.h
deleted file mode 100644
index 5855b2d..0000000
--- a/src/MoonP/moon_compiler.h
+++ /dev/null
@@ -1,63 +0,0 @@
1/* Copyright (c) 2021 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 <string_view>
13#include <tuple>
14#include <list>
15#include <memory>
16#include <unordered_map>
17#include <functional>
18
19namespace MoonP {
20
21extern const std::string_view version;
22extern const std::string_view extension;
23
24using Options = std::unordered_map<std::string,std::string>;
25
26struct MoonConfig {
27 bool lintGlobalVariable = false;
28 bool implicitReturnRoot = true;
29 bool reserveLineNumber = true;
30 bool useSpaceOverTab = false;
31 int lineOffset = 0;
32 Options options;
33};
34
35struct GlobalVar {
36 std::string name;
37 int line;
38 int col;
39};
40
41using GlobalVars = std::list<GlobalVar>;
42
43struct CompileInfo {
44 std::string codes;
45 std::string error;
46 std::unique_ptr<GlobalVars> globals;
47 std::unique_ptr<Options> options;
48};
49
50class MoonCompilerImpl;
51
52class MoonCompiler {
53public:
54 MoonCompiler(void* luaState = nullptr,
55 const std::function<void(void*)>& luaOpen = nullptr,
56 bool sameModule = false);
57 virtual ~MoonCompiler();
58 CompileInfo compile(std::string_view codes, const MoonConfig& config = {});
59private:
60 std::unique_ptr<MoonCompilerImpl> _compiler;
61};
62
63} // namespace MoonP
diff --git a/src/MoonP/moon_parser.cpp b/src/MoonP/moon_parser.cpp
deleted file mode 100644
index a581e15..0000000
--- a/src/MoonP/moon_parser.cpp
+++ /dev/null
@@ -1,719 +0,0 @@
1/* Copyright (c) 2021 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 {
14using namespace std::string_view_literals;
15
16std::unordered_set<std::string> LuaKeywords = {
17 "and", "break", "do", "else", "elseif",
18 "end", "false", "for", "function", "goto",
19 "if", "in", "local", "nil", "not",
20 "or", "repeat", "return", "then", "true",
21 "until", "while"
22};
23
24std::unordered_set<std::string> Keywords = {
25 "and", "break", "do", "else", "elseif",
26 "end", "false", "for", "function", "goto",
27 "if", "in", "local", "nil", "not",
28 "or", "repeat", "return", "then", "true",
29 "until", "while", // Lua keywords
30 "as", "class", "continue", "export", "extends",
31 "from", "global", "import", "macro", "switch",
32 "unless", "using", "when", "with" // Moon keywords
33};
34
35MoonParser::MoonParser() {
36 plain_space = *set(" \t");
37 Break = nl(-expr('\r') >> '\n');
38 Any = Break | any();
39 Stop = Break | eof();
40 Indent = plain_space;
41 Comment = "--" >> *(not_(set("\r\n")) >> Any) >> and_(Stop);
42 multi_line_open = expr("--[[");
43 multi_line_close = expr("]]");
44 multi_line_content = *(not_(multi_line_close) >> Any);
45 MultiLineComment = multi_line_open >> multi_line_content >> multi_line_close;
46 EscapeNewLine = expr('\\') >> *(set(" \t") | MultiLineComment) >> -Comment >> Break;
47 space_one = set(" \t") | and_(set("-\\")) >> (MultiLineComment | EscapeNewLine);
48 Space = *space_one >> -Comment;
49 SpaceBreak = Space >> Break;
50 White = Space >> *(Break >> Space);
51 EmptyLine = SpaceBreak;
52 AlphaNum = range('a', 'z') | range('A', 'Z') | range('0', '9') | '_';
53 Name = (range('a', 'z') | range('A', 'Z') | '_') >> *AlphaNum;
54 Num = (
55 "0x" >>
56 +(range('0', '9') | range('a', 'f') | range('A', 'F')) >>
57 -(-set("uU") >> set("lL") >> set("lL"))
58 ) | (
59 +range('0', '9') >> -set("uU") >> set("lL") >> set("lL")
60 ) | (
61 (
62 +range('0', '9') >> -('.' >> +range('0', '9'))
63 ) | (
64 '.' >> +range('0', '9')
65 )
66 ) >> -(set("eE") >> -expr('-') >> +range('0', '9'));
67
68 Cut = false_();
69 Seperator = true_();
70
71 #define sym(str) (Space >> str)
72 #define symx(str) expr(str)
73 #define ensure(patt, finally) ((patt) >> (finally) | (finally) >> Cut)
74 #define key(str) (Space >> str >> not_(AlphaNum))
75 #define disable_do(patt) (DisableDo >> ((patt) >> EnableDo | EnableDo >> Cut))
76 #define disable_chain(patt) (DisableChain >> ((patt) >> EnableChain | EnableChain >> Cut))
77 #define disable_do_chain(patt) (DisableDoChain >> ((patt) >> EnableDoChain | EnableDoChain >> Cut))
78 #define plain_body_with(str) (-key(str) >> InBlock | key(str) >> Statement)
79 #define plain_body (InBlock | Statement)
80
81 Variable = pl::user(Name, [](const item_t& item) {
82 State* st = reinterpret_cast<State*>(item.user_data);
83 for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it);
84 auto isValid = Keywords.find(st->buffer) == Keywords.end();
85 if (isValid) {
86 if (st->buffer == st->moduleName) {
87 st->moduleFix++;
88 st->moduleName = std::string("_module_"sv) + std::to_string(st->moduleFix);
89 }
90 }
91 st->buffer.clear();
92 return isValid;
93 });
94
95 LabelName = pl::user(Name, [](const item_t& item) {
96 State* st = reinterpret_cast<State*>(item.user_data);
97 for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it);
98 auto isValid = LuaKeywords.find(st->buffer) == LuaKeywords.end();
99 st->buffer.clear();
100 return isValid;
101 });
102
103 LuaKeyword = pl::user(Name, [](const item_t& item) {
104 State* st = reinterpret_cast<State*>(item.user_data);
105 for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it);
106 auto it = LuaKeywords.find(st->buffer);
107 st->buffer.clear();
108 return it != LuaKeywords.end();
109 });
110
111 self = expr('@');
112 self_name = '@' >> Name;
113 self_class = expr("@@");
114 self_class_name = "@@" >> Name;
115
116 SelfName = self_class_name | self_class | self_name | self;
117 KeyName = Space >> (SelfName | Name);
118 VarArg = expr("...");
119
120 check_indent = pl::user(Indent, [](const item_t& item) {
121 int indent = 0;
122 for (input_it i = item.begin; i != item.end; ++i) {
123 switch (*i) {
124 case ' ': indent++; break;
125 case '\t': indent += 4; break;
126 }
127 }
128 State* st = reinterpret_cast<State*>(item.user_data);
129 return st->indents.top() == indent;
130 });
131 CheckIndent = and_(check_indent);
132
133 advance = pl::user(Indent, [](const item_t& item) {
134 int indent = 0;
135 for (input_it i = item.begin; i != item.end; ++i) {
136 switch (*i) {
137 case ' ': indent++; break;
138 case '\t': indent += 4; break;
139 }
140 }
141 State* st = reinterpret_cast<State*>(item.user_data);
142 int top = st->indents.top();
143 if (top != -1 && indent > top) {
144 st->indents.push(indent);
145 return true;
146 }
147 return false;
148 });
149 Advance = and_(advance);
150
151 push_indent = pl::user(Indent, [](const item_t& item) {
152 int indent = 0;
153 for (input_it i = item.begin; i != item.end; ++i) {
154 switch (*i) {
155 case ' ': indent++; break;
156 case '\t': indent += 4; break;
157 }
158 }
159 State* st = reinterpret_cast<State*>(item.user_data);
160 st->indents.push(indent);
161 return true;
162 });
163 PushIndent = and_(push_indent);
164
165 PreventIndent = pl::user(true_(), [](const item_t& item) {
166 State* st = reinterpret_cast<State*>(item.user_data);
167 st->indents.push(-1);
168 return true;
169 });
170
171 PopIndent = pl::user(true_(), [](const item_t& item) {
172 State* st = reinterpret_cast<State*>(item.user_data);
173 st->indents.pop();
174 return true;
175 });
176
177 InBlock = +SpaceBreak >> Advance >> ensure(Block, PopIndent);
178
179 local_flag = expr('*') | expr('^');
180 local_values = NameList >> -(sym('=') >> (TableBlock | ExpListLow));
181 Local = key("local") >> (Space >> local_flag | local_values);
182
183 LocalAttrib = and_(key(pl::user(Name, [](const item_t& item) {
184 State* st = reinterpret_cast<State*>(item.user_data);
185 for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it);
186 auto it = Keywords.find(st->buffer);
187 st->buffer.clear();
188 return it == Keywords.end();
189 })) >> NameList >> sym('=') >> not_('=')) >> Space >> Name >> NameList >> Assign;
190
191 colon_import_name = sym('\\') >> Space >> Variable;
192 ImportName = colon_import_name | Space >> Variable;
193 ImportNameList = Seperator >> *SpaceBreak >> ImportName >> *((+SpaceBreak | sym(',') >> *SpaceBreak) >> ImportName);
194 ImportFrom = ImportNameList >> *SpaceBreak >> key("from") >> Exp;
195
196 import_literal_inner = (range('a', 'z') | range('A', 'Z') | set("_-")) >> *(AlphaNum | '-');
197 import_literal_chain = Seperator >> import_literal_inner >> *(expr('.') >> import_literal_inner);
198 ImportLiteral = sym('\'') >> import_literal_chain >> symx('\'') | sym('"') >> import_literal_chain >> symx('"');
199
200 macro_name_pair = Space >> MacroName >> Space >> symx(':') >> Space >> MacroName;
201 import_all_macro = expr('$');
202 ImportTabItem = variable_pair | normal_pair | sym(':') >> MacroName | macro_name_pair | Space >> import_all_macro;
203 ImportTabList = ImportTabItem >> *(sym(',') >> ImportTabItem);
204 ImportTabLine = (
205 PushIndent >> (ImportTabList >> PopIndent | PopIndent)
206 ) | Space;
207 import_tab_lines = SpaceBreak >> ImportTabLine >> *(-sym(',') >> SpaceBreak >> ImportTabLine) >> -sym(',');
208 ImportTabLit =
209 sym('{') >> Seperator >>
210 -ImportTabList >>
211 -sym(',') >>
212 -import_tab_lines >>
213 White >> sym('}');
214
215 ImportAs = ImportLiteral >> -(key("as") >> (Space >> Variable | ImportTabLit));
216
217 Import = key("import") >> (ImportAs | ImportFrom);
218
219 Label = Space >> expr("::") >> LabelName >> expr("::");
220
221 Goto = key("goto") >> Space >> LabelName;
222
223 BreakLoop = (expr("break") | expr("continue")) >> not_(AlphaNum);
224
225 Return = key("return") >> -ExpListLow;
226
227 WithExp = ExpList >> -Assign;
228
229 With = key("with") >> -existential_op >> disable_do_chain(WithExp) >> plain_body_with("do");
230 SwitchCase = key("when") >> disable_chain(ExpList) >> plain_body_with("then");
231 SwitchElse = key("else") >> plain_body;
232
233 SwitchBlock = *EmptyLine >>
234 Advance >> Seperator >>
235 SwitchCase >>
236 *(+SpaceBreak >> SwitchCase) >>
237 -(+SpaceBreak >> SwitchElse) >>
238 PopIndent;
239
240 Switch = key("switch") >> disable_do(Exp) >> -key("do")
241 >> -Space >> Break >> SwitchBlock;
242
243 IfCond = disable_chain(Exp >> -Assign);
244 IfElseIf = -(Break >> *EmptyLine >> CheckIndent) >> key("elseif") >> IfCond >> plain_body_with("then");
245 IfElse = -(Break >> *EmptyLine >> CheckIndent) >> key("else") >> plain_body;
246 If = key("if") >> Seperator >> IfCond >> plain_body_with("then") >> *IfElseIf >> -IfElse;
247 Unless = key("unless") >> Seperator >> IfCond >> plain_body_with("then") >> *IfElseIf >> -IfElse;
248
249 While = key("while") >> disable_do_chain(Exp) >> plain_body_with("do");
250 Repeat = key("repeat") >> Body >> Break >> *EmptyLine >> CheckIndent >> key("until") >> Exp;
251
252 for_step_value = sym(',') >> Exp;
253 for_args = Space >> Variable >> sym('=') >> Exp >> sym(',') >> Exp >> -for_step_value;
254
255 For = key("for") >> disable_do_chain(for_args) >> plain_body_with("do");
256
257 for_in = star_exp | ExpList;
258
259 ForEach = key("for") >> AssignableNameList >> key("in") >>
260 disable_do_chain(for_in) >> plain_body_with("do");
261
262 Do = pl::user(key("do"), [](const item_t& item) {
263 State* st = reinterpret_cast<State*>(item.user_data);
264 return st->doStack.empty() || st->doStack.top();
265 }) >> Body;
266
267 DisableDo = pl::user(true_(), [](const item_t& item) {
268 State* st = reinterpret_cast<State*>(item.user_data);
269 st->doStack.push(false);
270 return true;
271 });
272
273 EnableDo = pl::user(true_(), [](const item_t& item) {
274 State* st = reinterpret_cast<State*>(item.user_data);
275 st->doStack.pop();
276 return true;
277 });
278
279 DisableDoChain = pl::user(true_(), [](const item_t& item) {
280 State* st = reinterpret_cast<State*>(item.user_data);
281 st->doStack.push(false);
282 st->chainBlockStack.push(false);
283 return true;
284 });
285
286 EnableDoChain = pl::user(true_(), [](const item_t& item) {
287 State* st = reinterpret_cast<State*>(item.user_data);
288 st->doStack.pop();
289 st->chainBlockStack.pop();
290 return true;
291 });
292
293 Comprehension = sym('[') >> Exp >> CompInner >> sym(']');
294 comp_value = sym(',') >> Exp;
295 TblComprehension = sym('{') >> Exp >> -comp_value >> CompInner >> sym('}');
296
297 CompInner = Seperator >> (CompForEach | CompFor) >> *CompClause;
298 star_exp = sym('*') >> Exp;
299 CompForEach = key("for") >> AssignableNameList >> key("in") >> (star_exp | Exp);
300 CompFor = key("for") >> Space >> Variable >> sym('=') >> Exp >> sym(',') >> Exp >> -for_step_value;
301 CompClause = CompFor | CompForEach | key("when") >> Exp;
302
303 Assign = sym('=') >> Seperator >> (With | If | Switch | TableBlock | Exp >> *(Space >> set(",;") >> Exp));
304
305 update_op =
306 expr("..") |
307 expr("+") |
308 expr("-") |
309 expr("*") |
310 expr("/") |
311 expr("%") |
312 expr("or") |
313 expr("and") |
314 expr("&") |
315 expr("|") |
316 expr(">>") |
317 expr("<<");
318
319 Update = Space >> update_op >> expr("=") >> Exp;
320
321 Assignable = AssignableChain | Space >> Variable | Space >> SelfName;
322
323 unary_value = unary_operator >> *(Space >> unary_operator) >> Value;
324
325 ExponentialOperator = expr('^');
326 expo_value = Space >> ExponentialOperator >> *SpaceBreak >> Value;
327 expo_exp = Value >> *expo_value;
328
329 unary_operator =
330 expr('-') >> not_(set(">=") | space_one) |
331 expr('#') |
332 expr('~') >> not_(expr('=') | space_one) |
333 expr("not") >> not_(AlphaNum);
334 unary_exp = *(Space >> unary_operator) >> expo_exp;
335
336 BackcallOperator = expr("|>");
337 backcall_value = Space >> BackcallOperator >> *SpaceBreak >> unary_exp;
338 backcall_exp = unary_exp >> *backcall_value;
339
340 BinaryOperator =
341 (expr("or") >> not_(AlphaNum)) |
342 (expr("and") >> not_(AlphaNum)) |
343 expr("<=") |
344 expr(">=") |
345 expr("~=") |
346 expr("!=") |
347 expr("==") |
348 expr("..") |
349 expr("<<") |
350 expr(">>") |
351 expr("//") |
352 set("+-*/%><|&~");
353 exp_op_value = Space >> BinaryOperator >> *SpaceBreak >> backcall_exp;
354 Exp = Seperator >> backcall_exp >> *exp_op_value;
355
356 DisableChain = pl::user(true_(), [](const item_t& item) {
357 State* st = reinterpret_cast<State*>(item.user_data);
358 st->chainBlockStack.push(false);
359 return true;
360 });
361
362 EnableChain = pl::user(true_(), [](const item_t& item) {
363 State* st = reinterpret_cast<State*>(item.user_data);
364 st->chainBlockStack.pop();
365 return true;
366 });
367
368 chain_line = CheckIndent >> (chain_item | Space >> (chain_dot_chain | ColonChain)) >> -InvokeArgs;
369 chain_block = pl::user(true_(), [](const item_t& item) {
370 State* st = reinterpret_cast<State*>(item.user_data);
371 return st->chainBlockStack.empty() || st->chainBlockStack.top();
372 }) >> +SpaceBreak >> Advance >> ensure(
373 chain_line >> *(+SpaceBreak >> chain_line), PopIndent);
374 ChainValue = Seperator >> (Chain | Callable) >> -existential_op >> -(InvokeArgs | chain_block);
375
376 simple_table = Seperator >> KeyValue >> *(sym(',') >> KeyValue);
377 Value = SimpleValue | simple_table | ChainValue | String;
378
379 single_string_inner = expr("\\'") | "\\\\" | not_(expr('\'')) >> Any;
380 SingleString = symx('\'') >> *single_string_inner >> symx('\'');
381 interp = symx("#{") >> Exp >> sym('}');
382 double_string_plain = expr("\\\"") | "\\\\" | not_(expr('"')) >> Any;
383 double_string_inner = +(not_(interp) >> double_string_plain);
384 double_string_content = double_string_inner | interp;
385 DoubleString = symx('"') >> Seperator >> *double_string_content >> symx('"');
386 String = Space >> (DoubleString | SingleString | LuaString);
387
388 lua_string_open = '[' >> *expr('=') >> '[';
389 lua_string_close = ']' >> *expr('=') >> ']';
390
391 LuaStringOpen = pl::user(lua_string_open, [](const item_t& item) {
392 size_t count = std::distance(item.begin, item.end);
393 State* st = reinterpret_cast<State*>(item.user_data);
394 st->stringOpen = count;
395 return true;
396 });
397
398 LuaStringClose = pl::user(lua_string_close, [](const item_t& item) {
399 size_t count = std::distance(item.begin, item.end);
400 State* st = reinterpret_cast<State*>(item.user_data);
401 return st->stringOpen == count;
402 });
403
404 LuaStringContent = *(not_(LuaStringClose) >> Any);
405
406 LuaString = LuaStringOpen >> -Break >> LuaStringContent >> LuaStringClose;
407
408 Parens = symx('(') >> *SpaceBreak >> Exp >> *SpaceBreak >> sym(')');
409 Callable = Space >> (Variable | SelfName | MacroName | VarArg | Parens);
410 FnArgsExpList = Exp >> *((Break | sym(',')) >> White >> Exp);
411
412 FnArgs = (symx('(') >> *SpaceBreak >> -FnArgsExpList >> *SpaceBreak >> sym(')')) |
413 (sym('!') >> not_(expr('=')));
414
415 existential_op = expr('?');
416 chain_call = (Callable | String) >> -existential_op >> ChainItems;
417 chain_item = and_(set(".\\")) >> ChainItems;
418 chain_dot_chain = DotChainItem >> -existential_op >> -ChainItems;
419
420 Chain = chain_call | chain_item |
421 Space >> (chain_dot_chain | ColonChain);
422
423 AssignableChain = Seperator >> Chain;
424
425 chain_with_colon = +ChainItem >> -ColonChain;
426 ChainItems = chain_with_colon | ColonChain;
427
428 Index = symx('[') >> Exp >> sym(']');
429 ChainItem = Invoke >> -existential_op | DotChainItem >> -existential_op | Slice | Index >> -existential_op;
430 DotChainItem = symx('.') >> Name;
431 ColonChainItem = symx('\\') >> (LuaKeyword | Name);
432 invoke_chain = Invoke >> -existential_op >> -ChainItems;
433 ColonChain = ColonChainItem >> -existential_op >> -invoke_chain;
434
435 default_value = true_();
436 Slice =
437 symx('[') >>
438 (Exp | default_value) >>
439 sym(',') >>
440 (Exp | default_value) >>
441 (sym(',') >> Exp | default_value) >>
442 sym(']');
443
444 Invoke = Seperator >> (
445 FnArgs |
446 SingleString |
447 DoubleString |
448 and_(expr('[')) >> LuaString |
449 and_(expr('{')) >> TableLit);
450
451 TableValue = KeyValue | Exp;
452
453 table_lit_lines = SpaceBreak >> TableLitLine >> *(-sym(',') >> SpaceBreak >> TableLitLine) >> -sym(',');
454
455 TableLit =
456 sym('{') >> Seperator >>
457 -TableValueList >>
458 -sym(',') >>
459 -table_lit_lines >>
460 White >> sym('}');
461
462 TableValueList = TableValue >> *(sym(',') >> TableValue);
463
464 TableLitLine = (
465 PushIndent >> (TableValueList >> PopIndent | PopIndent)
466 ) | (
467 Space
468 );
469
470 TableBlockInner = Seperator >> KeyValueLine >> *(+SpaceBreak >> KeyValueLine);
471 TableBlock = +SpaceBreak >> Advance >> ensure(TableBlockInner, PopIndent);
472 TableBlockIndent = sym('*') >> Seperator >> KeyValueList >> -sym(',') >>
473 -(+SpaceBreak >> Advance >> ensure(KeyValueList >> -sym(',') >> *(+SpaceBreak >> KeyValueLine), PopIndent));
474
475 class_member_list = Seperator >> KeyValue >> *(sym(',') >> KeyValue);
476 ClassLine = CheckIndent >> (class_member_list | Statement) >> -sym(',');
477 ClassBlock = +SpaceBreak >> Advance >> Seperator >> ClassLine >> *(+SpaceBreak >> ClassLine) >> PopIndent;
478
479 ClassDecl =
480 key("class") >> not_(expr(':')) >>
481 -Assignable >>
482 -(key("extends") >> PreventIndent >> ensure(Exp, PopIndent)) >>
483 -ClassBlock;
484
485 global_values = NameList >> -(sym('=') >> (TableBlock | ExpListLow));
486 global_op = expr('*') | expr('^');
487 Global = key("global") >> (ClassDecl | (Space >> global_op) | global_values);
488
489 export_default = key("default");
490
491 Export = pl::user(key("export"), [](const item_t& item) {
492 State* st = reinterpret_cast<State*>(item.user_data);
493 st->exportCount++;
494 return true;
495 }) >> ((pl::user(export_default, [](const item_t& item) {
496 State* st = reinterpret_cast<State*>(item.user_data);
497 bool isValid = !st->exportDefault && st->exportCount == 1;
498 st->exportDefault = true;
499 return isValid;
500 }) >> Exp)
501 | (pl::user(true_(), [](const item_t& item) {
502 State* st = reinterpret_cast<State*>(item.user_data);
503 if (st->exportDefault && st->exportCount > 1) {
504 return false;
505 } else {
506 return true;
507 }
508 }) >> ExpList >> -Assign)
509 | Macro) >> not_(Space >> statement_appendix);
510
511 variable_pair = sym(':') >> Variable;
512
513 normal_pair = (
514 KeyName |
515 sym('[') >> Exp >> sym(']') |
516 Space >> DoubleString |
517 Space >> SingleString |
518 Space >> LuaString
519 ) >>
520 symx(':') >>
521 (Exp | TableBlock | +(SpaceBreak) >> Exp);
522
523 KeyValue = variable_pair | normal_pair;
524
525 KeyValueList = KeyValue >> *(sym(',') >> KeyValue);
526 KeyValueLine = CheckIndent >> (KeyValueList >> -sym(',') | TableBlockIndent | Space >> expr('*') >> (Exp | TableBlock));
527
528 FnArgDef = (Variable | SelfName) >> -(sym('=') >> Space >> Exp);
529
530 FnArgDefList = Space >> Seperator >> (
531 (
532 FnArgDef >>
533 *((sym(',') | Break) >> White >> FnArgDef) >>
534 -((sym(',') | Break) >> White >> VarArg)
535 ) | (
536 VarArg
537 )
538 );
539
540 outer_var_shadow = key("using") >> (NameList | Space >> expr("nil"));
541
542 FnArgsDef = sym('(') >> White >> -FnArgDefList >> -outer_var_shadow >> White >> sym(')');
543 fn_arrow = expr("->") | expr("=>");
544 FunLit = -FnArgsDef >> Space >> fn_arrow >> -Body;
545
546 MacroName = expr('$') >> -Name;
547 macro_args_def = sym('(') >> White >> -FnArgDefList >> White >> sym(')');
548 MacroLit = -macro_args_def >> Space >> expr("->") >> Body;
549 Macro = key("macro") >> Space >> Name >> sym('=') >> MacroLit;
550
551 NameList = Seperator >> Space >> Variable >> *(sym(',') >> Space >> Variable);
552 NameOrDestructure = Space >> Variable | TableLit;
553 AssignableNameList = Seperator >> NameOrDestructure >> *(sym(',') >> NameOrDestructure);
554
555 fn_arrow_back = expr('<') >> set("-=");
556 Backcall = -FnArgsDef >> Space >> fn_arrow_back >> Space >> ChainValue;
557
558 BackcallBody = Seperator >> Space >> BackcallOperator >> unary_exp >> *(+SpaceBreak >> CheckIndent >> Space >> BackcallOperator >> unary_exp);
559
560 ExpList = Seperator >> Exp >> *(sym(',') >> Exp);
561 ExpListLow = Seperator >> Exp >> *(Space >> set(",;") >> Exp);
562
563 ArgLine = CheckIndent >> Exp >> *(sym(',') >> Exp);
564 ArgBlock = ArgLine >> *(sym(',') >> SpaceBreak >> ArgLine) >> PopIndent;
565
566 invoke_args_with_table =
567 sym(',') >>
568 (
569 TableBlock |
570 SpaceBreak >> Advance >> ArgBlock >> -TableBlock
571 );
572
573 InvokeArgs =
574 not_(set("-~")) >> Seperator >>
575 (
576 Exp >> *(sym(',') >> Exp) >> -(invoke_args_with_table | TableBlock) |
577 TableBlock
578 );
579
580 const_value = (expr("nil") | expr("true") | expr("false")) >> not_(AlphaNum);
581
582 SimpleValue =
583 (Space >> const_value) |
584 If | Unless | Switch | With | ClassDecl | ForEach | For | While | Do |
585 (Space >> unary_value) |
586 TblComprehension | TableLit | Comprehension | FunLit |
587 (Space >> Num);
588
589 ExpListAssign = ExpList >> -(Update | Assign);
590
591 if_line = key("if") >> Exp >> -Assign;
592 unless_line = key("unless") >> Exp;
593
594 statement_appendix = (if_line | unless_line | CompInner) >> Space;
595 statement_sep = and_(*SpaceBreak >> CheckIndent >> Space >> (set("($'\"") | expr("[[") | expr("[=")));
596 Statement = (
597 Import | While | Repeat | For | ForEach |
598 Return | Local | Global | Export | Macro |
599 Space >> BreakLoop | Label | Goto | Backcall |
600 LocalAttrib | BackcallBody | ExpListAssign
601 ) >> Space >>
602 -statement_appendix >> -statement_sep;
603
604 Body = InBlock | Statement;
605
606 empty_line_stop = Space >> and_(Stop);
607 Line = and_(check_indent >> Space >> not_(BackcallOperator)) >> Statement | Advance >> ensure(and_(Space >> BackcallOperator) >> Statement, PopIndent) | empty_line_stop;
608 Block = Seperator >> Line >> *(+Break >> Line);
609
610 Shebang = expr("#!") >> *(not_(Stop) >> Any);
611 File = White >> -Shebang >> Block >> eof();
612}
613
614ParseInfo MoonParser::parse(std::string_view codes, rule& r) {
615 ParseInfo res;
616 try {
617 res.codes = std::make_unique<input>();
618 *(res.codes) = _converter.from_bytes(&codes.front(), &codes.back() + 1);
619 } catch (const std::range_error&) {
620 res.error = "Invalid text encoding."sv;
621 return res;
622 }
623 error_list errors;
624 try {
625 State state;
626 res.node.set(pl::parse(*(res.codes), r, errors, &state));
627 if (state.exportCount > 0) {
628 res.moduleName = std::move(state.moduleName);
629 res.exportDefault = state.exportDefault;
630 }
631 } catch (const std::logic_error& err) {
632 res.error = err.what();
633 return res;
634 }
635 if (!errors.empty()) {
636 std::ostringstream buf;
637 for (error_list::iterator it = errors.begin(); it != errors.end(); ++it) {
638 const error& err = *it;
639 switch (err.m_type) {
640 case ERROR_TYPE::ERROR_SYNTAX_ERROR:
641 buf << res.errorMessage("syntax error"sv, &err);
642 break;
643 case ERROR_TYPE::ERROR_INVALID_EOF:
644 buf << res.errorMessage("invalid EOF"sv, &err);
645 break;
646 }
647 }
648 res.error = buf.str();
649 }
650 return res;
651}
652
653std::string MoonParser::toString(ast_node* node) {
654 return _converter.to_bytes(std::wstring(node->m_begin.m_it, node->m_end.m_it));
655}
656
657std::string MoonParser::toString(input::iterator begin, input::iterator end) {
658 return _converter.to_bytes(std::wstring(begin, end));
659}
660
661input MoonParser::encode(std::string_view codes) {
662 return _converter.from_bytes(&codes.front(), &codes.back() + 1);
663}
664
665std::string MoonParser::decode(const input& codes) {
666 return _converter.to_bytes(codes);
667}
668
669namespace Utils {
670 void replace(std::string& str, std::string_view from, std::string_view to) {
671 size_t start_pos = 0;
672 while((start_pos = str.find(from, start_pos)) != std::string::npos) {
673 str.replace(start_pos, from.size(), to);
674 start_pos += to.size();
675 }
676 }
677
678 void trim(std::string& str) {
679 if (str.empty()) return;
680 str.erase(0, str.find_first_not_of(" \t\n"));
681 str.erase(str.find_last_not_of(" \t\n") + 1);
682 }
683}
684
685std::string ParseInfo::errorMessage(std::string_view msg, const input_range* loc) const {
686 const int ASCII = 255;
687 int length = loc->m_begin.m_line;
688 auto begin = codes->begin();
689 auto end = codes->end();
690 int count = 0;
691 for (auto it = codes->begin(); it != codes->end(); ++it) {
692 if (*it == '\n') {
693 if (count + 1 == length) {
694 end = it;
695 break;
696 } else {
697 begin = it + 1;
698 }
699 count++;
700 }
701 }
702 int oldCol = loc->m_begin.m_col;
703 int col = std::max(0, oldCol - 1);
704 auto it = begin;
705 for (int i = 0; i < oldCol && it != end; ++i) {
706 if (*it > ASCII) {
707 ++col;
708 }
709 ++it;
710 }
711 auto line = Converter{}.to_bytes(std::wstring(begin, end));
712 Utils::replace(line, "\t"sv, " "sv);
713 std::ostringstream buf;
714 buf << loc->m_begin.m_line << ": "sv << msg <<
715 '\n' << line << '\n' << std::string(col, ' ') << "^"sv;
716 return buf.str();
717}
718
719} // namespace MoonP
diff --git a/src/MoonP/moon_parser.h b/src/MoonP/moon_parser.h
deleted file mode 100644
index b165070..0000000
--- a/src/MoonP/moon_parser.h
+++ /dev/null
@@ -1,317 +0,0 @@
1/* Copyright (c) 2021 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 <unordered_set>
13#include <stack>
14#include <algorithm>
15#include <list>
16#include <sstream>
17#include <string_view>
18
19#include "MoonP/ast.hpp"
20#include "MoonP/moon_ast.h"
21
22namespace MoonP {
23using namespace parserlib;
24
25struct ParseInfo {
26 ast_ptr<false, ast_node> node;
27 std::string error;
28 std::unique_ptr<input> codes;
29 bool exportDefault = false;
30 std::string moduleName;
31 std::string errorMessage(std::string_view msg, const input_range* loc) const;
32};
33
34template<typename T>
35struct identity { typedef T type; };
36
37#define AST_RULE(type) \
38 rule type; \
39 ast<type##_t> type##_impl = type; \
40 inline rule& getRule(identity<type##_t>) { return type; }
41
42extern std::unordered_set<std::string> LuaKeywords;
43extern std::unordered_set<std::string> Keywords;
44
45class MoonParser {
46public:
47 MoonParser();
48
49 template<class AST>
50 ParseInfo parse(std::string_view codes) {
51 return parse(codes, getRule<AST>());
52 }
53
54 template <class AST>
55 bool match(std::string_view codes) {
56 auto rEnd = rule(getRule<AST>() >> eof());
57 return parse(codes, rEnd).node;
58 }
59
60 std::string toString(ast_node* node);
61 std::string toString(input::iterator begin, input::iterator end);
62
63 input encode(std::string_view input);
64 std::string decode(const input& input);
65
66protected:
67 ParseInfo parse(std::string_view codes, rule& r);
68
69 struct State {
70 State() {
71 indents.push(0);
72 }
73 bool exportDefault = false;
74 int exportCount = 0;
75 int moduleFix = 0;
76 size_t stringOpen = 0;
77 std::string moduleName = "_module_0";
78 std::string buffer;
79 std::stack<int> indents;
80 std::stack<bool> doStack;
81 std::stack<bool> chainBlockStack;
82 };
83
84 template <class T>
85 inline rule& getRule() {
86 return getRule(identity<T>());
87 }
88
89private:
90 Converter _converter;
91
92 template <class T>
93 inline rule& getRule(identity<T>) {
94 assert(false);
95 return Cut;
96 }
97
98 rule plain_space;
99 rule Break;
100 rule Any;
101 rule White;
102 rule Stop;
103 rule Comment;
104 rule multi_line_open;
105 rule multi_line_close;
106 rule multi_line_content;
107 rule MultiLineComment;
108 rule Indent;
109 rule EscapeNewLine;
110 rule space_one;
111 rule Space;
112 rule SpaceBreak;
113 rule EmptyLine;
114 rule AlphaNum;
115 rule Cut;
116 rule check_indent;
117 rule CheckIndent;
118 rule advance;
119 rule Advance;
120 rule push_indent;
121 rule PushIndent;
122 rule PreventIndent;
123 rule PopIndent;
124 rule InBlock;
125 rule ImportName;
126 rule ImportNameList;
127 rule import_literal_chain;
128 rule ImportTabItem;
129 rule ImportTabList;
130 rule ImportTabLine;
131 rule import_tab_lines;
132 rule WithExp;
133 rule DisableDo;
134 rule EnableDo;
135 rule DisableChain;
136 rule EnableChain;
137 rule DisableDoChain;
138 rule EnableDoChain;
139 rule SwitchElse;
140 rule SwitchBlock;
141 rule IfElseIf;
142 rule IfElse;
143 rule for_args;
144 rule for_in;
145 rule CompClause;
146 rule Chain;
147 rule KeyValue;
148 rule single_string_inner;
149 rule interp;
150 rule double_string_plain;
151 rule lua_string_open;
152 rule lua_string_close;
153 rule FnArgsExpList;
154 rule FnArgs;
155 rule macro_args_def;
156 rule chain_call;
157 rule chain_item;
158 rule ChainItems;
159 rule chain_dot_chain;
160 rule ColonChain;
161 rule chain_with_colon;
162 rule ChainItem;
163 rule chain_line;
164 rule chain_block;
165 rule Index;
166 rule invoke_chain;
167 rule TableValue;
168 rule table_lit_lines;
169 rule TableLitLine;
170 rule TableValueList;
171 rule TableBlockInner;
172 rule ClassLine;
173 rule KeyValueLine;
174 rule KeyValueList;
175 rule ArgLine;
176 rule ArgBlock;
177 rule invoke_args_with_table;
178 rule BackcallOperator;
179 rule ExponentialOperator;
180 rule backcall_value;
181 rule backcall_exp;
182 rule expo_value;
183 rule expo_exp;
184 rule empty_line_stop;
185 rule Line;
186 rule Shebang;
187
188 AST_RULE(Num)
189 AST_RULE(Name)
190 AST_RULE(Variable)
191 AST_RULE(LabelName)
192 AST_RULE(LuaKeyword)
193 AST_RULE(self)
194 AST_RULE(self_name)
195 AST_RULE(self_class)
196 AST_RULE(self_class_name)
197 AST_RULE(SelfName)
198 AST_RULE(KeyName)
199 AST_RULE(VarArg)
200 AST_RULE(Seperator)
201 AST_RULE(NameList)
202 AST_RULE(local_flag)
203 AST_RULE(local_values)
204 AST_RULE(Local)
205 AST_RULE(LocalAttrib);
206 AST_RULE(colon_import_name)
207 AST_RULE(import_literal_inner)
208 AST_RULE(ImportLiteral)
209 AST_RULE(ImportFrom)
210 AST_RULE(macro_name_pair)
211 AST_RULE(import_all_macro)
212 AST_RULE(ImportTabLit)
213 AST_RULE(ImportAs)
214 AST_RULE(Import)
215 AST_RULE(Label)
216 AST_RULE(Goto)
217 AST_RULE(fn_arrow_back)
218 AST_RULE(Backcall)
219 AST_RULE(BackcallBody)
220 AST_RULE(ExpListLow)
221 AST_RULE(ExpList)
222 AST_RULE(Return)
223 AST_RULE(With)
224 AST_RULE(SwitchCase)
225 AST_RULE(Switch)
226 AST_RULE(IfCond)
227 AST_RULE(If)
228 AST_RULE(Unless)
229 AST_RULE(While)
230 AST_RULE(Repeat)
231 AST_RULE(for_step_value)
232 AST_RULE(For)
233 AST_RULE(ForEach)
234 AST_RULE(Do)
235 AST_RULE(Comprehension)
236 AST_RULE(comp_value)
237 AST_RULE(TblComprehension)
238 AST_RULE(star_exp)
239 AST_RULE(CompForEach)
240 AST_RULE(CompFor)
241 AST_RULE(CompInner)
242 AST_RULE(Assign)
243 AST_RULE(update_op)
244 AST_RULE(Update)
245 AST_RULE(BinaryOperator)
246 AST_RULE(unary_operator)
247 AST_RULE(Assignable)
248 AST_RULE(AssignableChain)
249 AST_RULE(exp_op_value)
250 AST_RULE(Exp)
251 AST_RULE(Callable)
252 AST_RULE(ChainValue)
253 AST_RULE(simple_table)
254 AST_RULE(SimpleValue)
255 AST_RULE(Value)
256 AST_RULE(LuaStringOpen);
257 AST_RULE(LuaStringContent);
258 AST_RULE(LuaStringClose);
259 AST_RULE(LuaString)
260 AST_RULE(SingleString)
261 AST_RULE(double_string_inner)
262 AST_RULE(double_string_content)
263 AST_RULE(DoubleString)
264 AST_RULE(String)
265 AST_RULE(Parens)
266 AST_RULE(DotChainItem)
267 AST_RULE(ColonChainItem)
268 AST_RULE(default_value)
269 AST_RULE(Slice)
270 AST_RULE(Invoke)
271 AST_RULE(existential_op)
272 AST_RULE(TableLit)
273 AST_RULE(TableBlock)
274 AST_RULE(TableBlockIndent)
275 AST_RULE(class_member_list)
276 AST_RULE(ClassBlock)
277 AST_RULE(ClassDecl)
278 AST_RULE(global_values)
279 AST_RULE(global_op)
280 AST_RULE(Global)
281 AST_RULE(export_default)
282 AST_RULE(Export)
283 AST_RULE(variable_pair)
284 AST_RULE(normal_pair)
285 AST_RULE(FnArgDef)
286 AST_RULE(FnArgDefList)
287 AST_RULE(outer_var_shadow)
288 AST_RULE(FnArgsDef)
289 AST_RULE(fn_arrow)
290 AST_RULE(FunLit)
291 AST_RULE(MacroName)
292 AST_RULE(MacroLit)
293 AST_RULE(Macro)
294 AST_RULE(NameOrDestructure)
295 AST_RULE(AssignableNameList)
296 AST_RULE(InvokeArgs)
297 AST_RULE(const_value)
298 AST_RULE(unary_value)
299 AST_RULE(unary_exp)
300 AST_RULE(ExpListAssign)
301 AST_RULE(if_line)
302 AST_RULE(unless_line)
303 AST_RULE(BreakLoop)
304 AST_RULE(statement_appendix)
305 AST_RULE(statement_sep)
306 AST_RULE(Statement)
307 AST_RULE(Body)
308 AST_RULE(Block)
309 AST_RULE(File)
310};
311
312namespace Utils {
313 void replace(std::string& str, std::string_view from, std::string_view to);
314 void trim(std::string& str);
315};
316
317} // namespace MoonP
diff --git a/src/MoonP/moonplus.cpp b/src/MoonP/moonplus.cpp
deleted file mode 100644
index 9b9689c..0000000
--- a/src/MoonP/moonplus.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
1/* Copyright (c) 2021 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 "MoonP/moon_compiler.h"
9
10extern "C" {
11
12#include "lua.h"
13#include "lauxlib.h"
14
15static const char moonplusCodes[] =
16#include "MoonP/moonplus.h"
17
18static void init_moonplus(lua_State* L) {
19 if (luaL_loadbuffer(L, moonplusCodes, sizeof(moonplusCodes) / sizeof(moonplusCodes[0]) - 1, "=(moonplus)") != 0) {
20 std::string err = std::string("failed to load moonplus module.\n") + lua_tostring(L, -1);
21 luaL_error(L, err.c_str());
22 } else if (lua_pcall(L, 0, 0, 0) != 0) {
23 std::string err = std::string("failed to init moonplus module.\n") + lua_tostring(L, -1);
24 luaL_error(L, err.c_str());
25 }
26}
27
28static const char stpCodes[] =
29#include "MoonP/stacktraceplus.h"
30
31static int init_stacktraceplus(lua_State* L) {
32 if (luaL_loadbuffer(L, stpCodes, sizeof(stpCodes) / sizeof(stpCodes[0]) - 1, "=(stacktraceplus)") != 0) {
33 std::string err = std::string("failed to load stacktraceplus module.\n") + lua_tostring(L, -1);
34 luaL_error(L, err.c_str());
35 } else if (lua_pcall(L, 0, 1, 0) != 0) {
36 std::string err = std::string("failed to init stacktraceplus module.\n") + lua_tostring(L, -1);
37 luaL_error(L, err.c_str());
38 }
39 return 1;
40}
41
42static int moontolua(lua_State* L) {
43 size_t size = 0;
44 const char* input = luaL_checklstring(L, 1, &size);
45 MoonP::MoonConfig config;
46 bool sameModule = false;
47 if (lua_gettop(L) == 2) {
48 luaL_checktype(L, 2, LUA_TTABLE);
49 lua_pushliteral(L, "lint_global");
50 lua_gettable(L, -2);
51 if (lua_isboolean(L, -1) != 0) {
52 config.lintGlobalVariable = lua_toboolean(L, -1) != 0;
53 }
54 lua_pop(L, 1);
55 lua_pushliteral(L, "implicit_return_root");
56 lua_gettable(L, -2);
57 if (lua_isboolean(L, -1) != 0) {
58 config.implicitReturnRoot = lua_toboolean(L, -1) != 0;
59 }
60 lua_pop(L, 1);
61 lua_pushliteral(L, "reserve_line_number");
62 lua_gettable(L, -2);
63 if (lua_isboolean(L, -1) != 0) {
64 config.reserveLineNumber = lua_toboolean(L, -1) != 0;
65 }
66 lua_pop(L, 1);
67 lua_pushliteral(L, "space_over_tab");
68 lua_gettable(L, -2);
69 if (lua_isboolean(L, -1) != 0) {
70 config.useSpaceOverTab = lua_toboolean(L, -1) != 0;
71 }
72 lua_pop(L, 1);
73 lua_pushliteral(L, "same_module");
74 lua_gettable(L, -2);
75 if (lua_isboolean(L, -1) != 0) {
76 sameModule = lua_toboolean(L, -1) != 0;
77 }
78 lua_pop(L, 1);
79 lua_pushliteral(L, "line_offset");
80 lua_gettable(L, -2);
81 if (lua_isnumber(L, -1) != 0) {
82 config.lineOffset = static_cast<int>(lua_tonumber(L, -1));
83 }
84 lua_pop(L, 1);
85 }
86 std::string s(input, size);
87 auto result = MoonP::MoonCompiler(L, nullptr, sameModule).compile(s, config);
88 if (result.codes.empty() && !result.error.empty()) {
89 lua_pushnil(L);
90 } else {
91 lua_pushlstring(L, result.codes.c_str(), result.codes.size());
92 }
93 if (result.error.empty()) {
94 lua_pushnil(L);
95 } else {
96 lua_pushlstring(L, result.error.c_str(), result.error.size());
97 }
98 if (result.globals) {
99 lua_createtable(L, static_cast<int>(result.globals->size()), 0);
100 int i = 1;
101 for (const auto& var : *result.globals) {
102 lua_createtable(L, 3, 0);
103 lua_pushlstring(L, var.name.c_str(), var.name.size());
104 lua_rawseti(L, -2, 1);
105 lua_pushinteger(L, var.line);
106 lua_rawseti(L, -2, 2);
107 lua_pushinteger(L, var.col);
108 lua_rawseti(L, -2, 3);
109 lua_rawseti(L, -2, i);
110 i++;
111 }
112 } else {
113 lua_pushnil(L);
114 }
115 return 3;
116}
117
118int luaopen_moonp(lua_State* L) {
119 lua_getglobal(L, "package"); // package
120 lua_getfield(L, -1, "loaded"); // package loaded
121 lua_createtable(L, 0, 0); // package loaded moonp
122 lua_pushcfunction(L, moontolua); // package loaded moonp func
123 lua_setfield(L, -2, "to_lua"); // moonp["to_lua"] = func, package loaded moonp
124 lua_pushlstring(L, &MoonP::version.front(), MoonP::version.size()); // package loaded moonp version
125 lua_setfield(L, -2, "version"); // moonp["version"] = version, package loaded moonp
126 lua_createtable(L, 0, 0); // package loaded moonp options
127 lua_pushlstring(L, &MoonP::extension.front(), MoonP::extension.size()); // package loaded moonp options ext
128 lua_setfield(L, -2, "extension"); // options["extension"] = ext, package loaded moonp options
129 lua_setfield(L, -2, "options"); // moonp["options"] = options, package loaded moonp
130 lua_pushcfunction(L, init_stacktraceplus); // package loaded moonp func1
131 lua_setfield(L, -2, "load_stacktraceplus"); // moonp["load_stacktraceplus"] = func1, package loaded moonp
132 lua_setfield(L, -2, "moonp"); // loaded["moonp"] = moonp, package loaded
133 lua_pop(L, 2); // empty
134 init_moonplus(L);
135 return 0;
136}
137
138} // extern "C"
139
diff --git a/src/MoonP/moonplus.h b/src/MoonP/moonplus.h
deleted file mode 100644
index ff82e9f..0000000
--- a/src/MoonP/moonplus.h
+++ /dev/null
@@ -1,251 +0,0 @@
1R"moonplus_codes(
2--[[
3Copyright (C) 2020 by Leaf Corcoran, modified by Li Jin
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.]]
22
23local moonp = require("moonp")
24local concat, insert, remove = table.concat, table.insert, table.remove
25local unpack = unpack or table.unpack
26local lua = {
27 loadstring = loadstring,
28 load = load
29}
30local split, get_options, create_moonpath, moon_loader, load_text, moon_call, loadstring, loadfile, dofile, insert_loader, remove_loader, moon_require, find_modulepath
31moonp.dirsep = "/"
32moonp.moon_compiled = { }
33moonp.file_exist = function(fname)
34 local file = io.open(fname)
35 if file then
36 file:close()
37 return true
38 else
39 return false
40 end
41end
42moonp.read_file = function(fname)
43 local file, err = io.open(fname)
44 if not file then
45 return nil, err
46 end
47 local text = assert(file:read("*a"))
48 file:close()
49 return text
50end
51split = function(str, delim)
52 if str == "" then
53 return { }
54 end
55 str = str .. delim
56 local _accum_0 = { }
57 local _len_0 = 1
58 for m in str:gmatch("(.-)" .. delim) do
59 _accum_0[_len_0] = m
60 _len_0 = _len_0 + 1
61 end
62 return _accum_0
63end
64get_options = function(...)
65 local count = select("#", ...)
66 local opts = select(count, ...)
67 if type(opts) == "table" then
68 return opts, unpack({
69 ...
70 }, nil, count - 1)
71 else
72 return { }, ...
73 end
74end
75create_moonpath = function(package_path)
76 local extension = moonp.options.extension
77 local moonpaths
78 do
79 local _accum_0 = { }
80 local _len_0 = 1
81 local _list_0 = split(package_path, ";")
82 for _index_0 = 1, #_list_0 do
83 local path = _list_0[_index_0]
84 local _continue_0 = false
85 repeat
86 local prefix = path:match("^(.-)%.lua$")
87 if not prefix then
88 _continue_0 = true
89 break
90 end
91 _accum_0[_len_0] = prefix .. "." .. extension
92 _len_0 = _len_0 + 1
93 _continue_0 = true
94 until true
95 if not _continue_0 then
96 break
97 end
98 end
99 moonpaths = _accum_0
100 end
101 return concat(moonpaths, ";")
102end
103find_modulepath = function(name)
104 if not package.moonpath then
105 package.moonpath = create_moonpath(package.path)
106 end
107 local name_path = name:gsub("%.", moonp.dirsep)
108 local file_exist, file_path
109 for path in package.moonpath:gmatch("[^;]+") do
110 file_path = path:gsub("?", name_path)
111 file_exist = moonp.file_exist(file_path)
112 if file_exist then
113 break
114 end
115 end
116 if file_exist then
117 return file_path
118 else
119 return nil
120 end
121end
122load_text = function(name)
123 local file_path = find_modulepath(name)
124 if file_path then
125 return moonp.read_file(file_path), file_path
126 end
127 return nil, nil
128end
129moon_loader = function(name)
130 local text, file_path = load_text(name)
131 if text then
132 local res, err = loadstring(text, file_path)
133 if not res then
134 error(file_path .. ": " .. err)
135 end
136 return res
137 end
138 return nil, "Could not find moonp file"
139end
140moon_call = function(f, ...)
141 local args = {
142 ...
143 }
144 return xpcall((function()
145 return f(unpack(args))
146 end), function(err)
147 return moonp.stp.stacktrace(err, 1)
148 end)
149end
150loadstring = function(...)
151 local options, str, chunk_name, mode, env = get_options(...)
152 chunk_name = chunk_name or "=(moonplus.loadstring)"
153 local code, err = moonp.to_lua(str, options)
154 if not code then
155 return nil, err
156 end
157 if chunk_name then
158 moonp.moon_compiled["@" .. chunk_name] = code
159 end
160 return (lua.loadstring or lua.load)(code, chunk_name, unpack({
161 mode,
162 env
163 }))
164end
165loadfile = function(fname, ...)
166 local text = moonp.read_file(fname)
167 return loadstring(text, tostring(fname), ...)
168end
169dofile = function(...)
170 local f = assert(loadfile(...))
171 return f()
172end
173insert_loader = function(pos)
174 if pos == nil then
175 pos = 2
176 end
177 if not package.moonpath then
178 package.moonpath = create_moonpath(package.path)
179 end
180 local loaders = package.loaders or package.searchers
181 for _index_0 = 1, #loaders do
182 local loader = loaders[_index_0]
183 if loader == moon_loader then
184 return false
185 end
186 end
187 insert(loaders, pos, moon_loader)
188 return true
189end
190remove_loader = function()
191 local loaders = package.loaders or package.searchers
192 for i, loader in ipairs(loaders) do
193 if loader == moon_loader then
194 remove(loaders, i)
195 return true
196 end
197 end
198 return false
199end
200moon_require = function(name)
201 insert_loader()
202 local success, res = xpcall((function()
203 return require(name)
204 end), function(err)
205 local msg = moonp.stp.stacktrace(err, 1)
206 print(msg)
207 return msg
208 end)
209 if success then
210 return res
211 else
212 return nil
213 end
214end
215setmetatable(moonp, {
216 __index = function(self, key)
217 if not (key == "stp") then
218 return nil
219 end
220 local stp = rawget(moonp, "stp")
221 if not stp then
222 do
223 local _with_0 = moonp.load_stacktraceplus()
224 _with_0.dump_locals = false
225 _with_0.simplified = true
226 stp = _with_0
227 end
228 rawset(moonp, "stp", stp)
229 rawset(moonp, "load_stacktraceplus", nil)
230 end
231 return stp
232 end,
233 __call = function(self, name)
234 return self.require(name)
235 end
236})
237for k, v in pairs({
238 insert_loader = insert_loader,
239 remove_loader = remove_loader,
240 loader = moon_loader,
241 dofile = dofile,
242 loadfile = loadfile,
243 loadstring = loadstring,
244 create_moonpath = create_moonpath,
245 find_modulepath = find_modulepath,
246 pcall = moon_call,
247 require = moon_require
248}) do
249 moonp[k] = v
250end
251)moonplus_codes";
diff --git a/src/MoonP/parser.cpp b/src/MoonP/parser.cpp
deleted file mode 100644
index 8dc2ff9..0000000
--- a/src/MoonP/parser.cpp
+++ /dev/null
@@ -1,1412 +0,0 @@
1/* Copyright (c) 2012, Achilleas Margaritis, modified by Jin Li
2All rights reserved.
3
4Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
6Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
8Redistributions 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.
9
10THIS 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.*/
11
12#include <cstdlib>
13#include <cstring>
14#include <cassert>
15#include <stdexcept>
16#include <unordered_map>
17#include <unordered_set>
18
19#include "MoonP/parser.hpp"
20
21
22namespace parserlib {
23
24
25//internal private class that manages access to the public classes' internals.
26class _private {
27public:
28 //get the internal expression object from the expression.
29 static _expr* get_expr(const expr& e) {
30 return e.m_expr;
31 }
32
33 //create new expression from given expression
34 static expr construct_expr(_expr* e) {
35 return e;
36 }
37
38 //get the internal expression object from the rule.
39 static _expr* get_expr(rule& r) {
40 return r.m_expr;
41 }
42
43 //get the internal parse proc from the rule.
44 static parse_proc get_parse_proc(rule& r) {
45 return r.m_parse_proc;
46 }
47};
48
49
50class _context;
51
52
53//parser state
54class _state {
55public:
56 //position
57 pos m_pos;
58
59 //size of match vector
60 size_t m_matches;
61
62 //constructor
63 _state(_context& con);
64};
65
66
67//match
68class _match {
69public:
70 //rule matched
71 rule* m_rule;
72
73 //begin position
74 pos m_begin;
75
76 //end position
77 pos m_end;
78
79 //null constructor
80 _match() {}
81
82 //constructor from parameters
83 _match(rule* r, const pos& b, const pos& e) :
84 m_rule(r),
85 m_begin(b),
86 m_end(e)
87 {
88 }
89};
90
91
92//match vector
93typedef std::vector<_match> _match_vector;
94
95
96//parsing context
97class _context {
98public:
99 //user data
100 void* m_user_data;
101
102 //current position
103 pos m_pos;
104
105 //error position
106 pos m_error_pos;
107
108 //input begin
109 input::iterator m_begin;
110
111 //input end
112 input::iterator m_end;
113
114 //matches
115 _match_vector m_matches;
116
117 //constructor
118 _context(input& i, void* ud) :
119 m_user_data(ud),
120 m_pos(i),
121 m_error_pos(i),
122 m_begin(i.begin()),
123 m_end(i.end())
124 {
125 }
126
127 //check if the end is reached
128 bool end() const {
129 return m_pos.m_it == m_end;
130 }
131
132 //get the current symbol
133 input::value_type symbol() const {
134 assert(!end());
135 return *m_pos.m_it;
136 }
137
138 //set the longest possible error
139 void set_error_pos() {
140 if (m_pos.m_it > m_error_pos.m_it) {
141 m_error_pos = m_pos;
142 }
143 }
144
145 //next column
146 void next_col() {
147 ++m_pos.m_it;
148 ++m_pos.m_col;
149 }
150
151 //next line
152 void next_line() {
153 ++m_pos.m_line;
154 m_pos.m_col = 1;
155 }
156
157 //restore the state
158 void restore(const _state& st) {
159 m_pos = st.m_pos;
160 m_matches.resize(st.m_matches);
161 }
162
163 //parse non-term rule.
164 bool parse_non_term(rule& r);
165
166 //parse term rule.
167 bool parse_term(rule& r);
168
169 //execute all the parse procs
170 void do_parse_procs(void* d) const {
171 for(_match_vector::const_iterator it = m_matches.begin();
172 it != m_matches.end();
173 ++it) {
174 const _match &m = *it;
175 parse_proc p = _private::get_parse_proc(*m.m_rule);
176 p(m.m_begin, m.m_end, d);
177 }
178 }
179
180private:
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
188
189//base class for expressions
190class _expr {
191public:
192 //destructor.
193 virtual ~_expr() {
194 }
195
196 //parse with whitespace
197 virtual bool parse_non_term(_context& con) const = 0;
198
199 //parse terminal
200 virtual bool parse_term(_context& con) const = 0;
201};
202
203
204//single character expression.
205class _char : public _expr {
206public:
207 //constructor.
208 _char(char c) :
209 m_char(c)
210 {
211 }
212
213 //parse with whitespace
214 virtual bool parse_non_term(_context& con) const {
215 return _parse(con);
216 }
217
218 //parse terminal
219 virtual bool parse_term(_context& con) const {
220 return _parse(con);
221 }
222
223private:
224 //character
225 input::value_type m_char;
226
227 //internal parse
228 bool _parse(_context& con) const {
229 if (!con.end()) {
230 input::value_type ch = con.symbol();
231 if (ch == m_char) {
232 con.next_col();
233 return true;
234 }
235 }
236 con.set_error_pos();
237 return false;
238 }
239};
240
241
242//string expression.
243class _string : public _expr {
244public:
245 //constructor from ansi string.
246 _string(const char* s) :
247 m_string(Converter{}.from_bytes(s))
248 {
249 }
250
251 //parse with whitespace
252 virtual bool parse_non_term(_context& con) const {
253 return _parse(con);
254 }
255
256 //parse terminal
257 virtual bool parse_term(_context& con) const {
258 return _parse(con);
259 }
260
261private:
262 //string
263 input m_string;
264
265 //parse the string
266 bool _parse(_context& con) const {
267 for(input::const_iterator it = m_string.begin(),
268 end = m_string.end();;) {
269 if (it == end) return true;
270 if (con.end()) break;
271 if (con.symbol() != *it) break;
272 ++it;
273 con.next_col();
274 }
275 con.set_error_pos();
276 return false;
277 }
278};
279
280
281//set expression.
282class _set : public _expr {
283public:
284 //constructor from ansi string.
285 _set(const char* s) {
286 auto str = Converter{}.from_bytes(s);
287 for (auto ch : str) {
288 _add(ch);
289 }
290 }
291
292 //constructor from range.
293 _set(int min, int max) {
294 assert(min >= 0);
295 assert(min <= max);
296 m_quick_set.resize((size_t)max + 1U);
297 for(; min <= max; ++min) {
298 m_quick_set[(size_t)min] = true;
299 }
300 }
301
302 //parse with whitespace
303 virtual bool parse_non_term(_context& con) const {
304 return _parse(con);
305 }
306
307 //parse terminal
308 virtual bool parse_term(_context& con) const {
309 return _parse(con);
310 }
311
312private:
313 //set is kept as an array of flags, for quick access
314 std::vector<bool> m_quick_set;
315 std::unordered_set<size_t> m_large_set;
316
317 //add character
318 void _add(size_t i) {
319 if (i <= m_quick_set.size() || i <= 255) {
320 if (i >= m_quick_set.size()) {
321 m_quick_set.resize(i + 1);
322 }
323 m_quick_set[i] = true;
324 } else {
325 m_large_set.insert(i);
326 }
327 }
328
329 //internal parse
330 bool _parse(_context& con) const {
331 if (!con.end()) {
332 size_t ch = con.symbol();
333 if (ch < m_quick_set.size()) {
334 if (m_quick_set[ch]) {
335 con.next_col();
336 return true;
337 }
338 } else if (m_large_set.find(ch) != m_large_set.end()) {
339 con.next_col();
340 return true;
341 }
342 }
343 con.set_error_pos();
344 return false;
345 }
346};
347
348
349//base class for unary expressions
350class _unary : public _expr {
351public:
352 //constructor.
353 _unary(_expr* e) :
354 m_expr(e)
355 {
356 }
357
358 //destructor.
359 virtual ~_unary() {
360 delete m_expr;
361 }
362
363protected:
364 //expression
365 _expr *m_expr;
366};
367
368
369//terminal
370class _term : public _unary {
371public:
372 //constructor.
373 _term(_expr* e) :
374 _unary(e)
375 {
376 }
377
378 //parse with whitespace
379 virtual bool parse_non_term(_context& con) const {
380 return m_expr->parse_term(con);
381 }
382
383 //parse terminal
384 virtual bool parse_term(_context& con) const {
385 return m_expr->parse_term(con);
386 }
387};
388
389
390//user
391class _user : public _unary {
392public:
393 //constructor.
394 _user(_expr* e, const user_handler& callback) :
395 _unary(e),
396 m_handler(callback)
397 {
398 }
399
400 //parse with whitespace
401 virtual bool parse_non_term(_context& con) const {
402 pos pos = con.m_pos;
403 if (m_expr->parse_non_term(con)) {
404 item_t item = {pos.m_it, con.m_pos.m_it, con.m_user_data};
405 return m_handler(item);
406 }
407 return false;
408 }
409
410 //parse terminal
411 virtual bool parse_term(_context& con) const {
412 pos pos = con.m_pos;
413 if (m_expr->parse_term(con)) {
414 item_t item = {pos.m_it, con.m_pos.m_it, con.m_user_data};
415 return m_handler(item);
416 }
417 return false;
418 }
419private:
420 user_handler m_handler;
421};
422
423
424//loop 0
425class _loop0 : public _unary {
426public:
427 //constructor.
428 _loop0(_expr* e) :
429 _unary(e)
430 {
431 }
432
433 //parse with whitespace
434 virtual bool parse_non_term(_context& con) const {
435 //if parsing of the first fails, restore the context and stop
436 _state st(con);
437 if (!m_expr->parse_non_term(con)) {
438 con.restore(st);
439 return true;
440 }
441
442 //parse the rest
443 for(;;) {
444 _state st(con);
445 if (!m_expr->parse_non_term(con)) {
446 con.restore(st);
447 break;
448 }
449 }
450
451 return true;
452 }
453
454 //parse terminal
455 virtual bool parse_term(_context& con) const {
456 //if parsing of the first fails, restore the context and stop
457 _state st(con);
458 if (!m_expr->parse_term(con)) {
459 con.restore(st);
460 return true;
461 }
462
463 //parse the rest until no more parsing is possible
464 for(;;) {
465 _state st(con);
466 if (!m_expr->parse_term(con)) {
467 con.restore(st);
468 break;
469 }
470 }
471
472 return true;
473 }
474};
475
476
477//loop 1
478class _loop1 : public _unary {
479public:
480 //constructor.
481 _loop1(_expr* e) :
482 _unary(e)
483 {
484 }
485
486 //parse with whitespace
487 virtual bool parse_non_term(_context& con) const {
488 //parse the first; if the first fails, stop
489 if (!m_expr->parse_non_term(con)) return false;
490
491 //parse the rest until no more parsing is possible
492 for(;;) {
493 _state st(con);
494 if (!m_expr->parse_non_term(con)) {
495 con.restore(st);
496 break;
497 }
498 }
499
500 return true;
501 }
502
503 //parse terminal
504 virtual bool parse_term(_context& con) const {
505 //parse the first; if the first fails, stop
506 if (!m_expr->parse_term(con)) return false;
507
508 //parse the rest until no more parsing is possible
509 for(;;) {
510 _state st(con);
511 if (!m_expr->parse_term(con)) {
512 con.restore(st);
513 break;
514 }
515 }
516
517 return true;
518 }
519};
520
521
522//optional
523class _optional : public _unary {
524public:
525 //constructor.
526 _optional(_expr* e) :
527 _unary(e)
528 {
529 }
530
531 //parse with whitespace
532 virtual bool parse_non_term(_context& con) const {
533 _state st(con);
534 if (!m_expr->parse_non_term(con)) con.restore(st);
535 return true;
536 }
537
538 //parse terminal
539 virtual bool parse_term(_context& con) const {
540 _state st(con);
541 if (!m_expr->parse_term(con)) con.restore(st);
542 return true;
543 }
544};
545
546
547//and
548class _and : public _unary {
549public:
550 //constructor.
551 _and(_expr* e) :
552 _unary(e)
553 {
554 }
555
556 //parse with whitespace
557 virtual bool parse_non_term(_context& con) const {
558 _state st(con);
559 bool ok = m_expr->parse_non_term(con);
560 con.restore(st);
561 return ok;
562 }
563
564 //parse terminal
565 virtual bool parse_term(_context& con) const {
566 _state st(con);
567 bool ok = m_expr->parse_term(con);
568 con.restore(st);
569 return ok;
570 }
571};
572
573
574//not
575class _not : public _unary {
576public:
577 //constructor.
578 _not(_expr* e) :
579 _unary(e)
580 {
581 }
582
583 //parse with whitespace
584 virtual bool parse_non_term(_context& con) const {
585 _state st(con);
586 bool ok = !m_expr->parse_non_term(con);
587 con.restore(st);
588 return ok;
589 }
590
591 //parse terminal
592 virtual bool parse_term(_context& con) const {
593 _state st(con);
594 bool ok = !m_expr->parse_term(con);
595 con.restore(st);
596 return ok;
597 }
598};
599
600
601//newline
602class _nl : public _unary {
603public:
604 //constructor.
605 _nl(_expr* e) :
606 _unary(e)
607 {
608 }
609
610 //parse with whitespace
611 virtual bool parse_non_term(_context& con) const {
612 if (!m_expr->parse_non_term(con)) return false;
613 con.next_line();
614 return true;
615 }
616
617 //parse terminal
618 virtual bool parse_term(_context& con) const {
619 if (!m_expr->parse_term(con)) return false;
620 con.next_line();
621 return true;
622 }
623};
624
625
626//base class for binary expressions
627class _binary : public _expr {
628public:
629 //constructor.
630 _binary(_expr* left, _expr* right) :
631 m_left(left), m_right(right)
632 {
633 }
634
635 //destructor.
636 virtual ~_binary() {
637 delete m_left;
638 delete m_right;
639 }
640
641protected:
642 //left and right expressions
643 _expr* m_left, *m_right;
644};
645
646
647//sequence
648class _seq : public _binary {
649public:
650 //constructor.
651 _seq(_expr* left, _expr* right) :
652 _binary(left, right)
653 {
654 }
655
656 //parse with whitespace
657 virtual bool parse_non_term(_context& con) const {
658 if (!m_left->parse_non_term(con)) return false;
659 return m_right->parse_non_term(con);
660 }
661
662 //parse terminal
663 virtual bool parse_term(_context& con) const {
664 if (!m_left->parse_term(con)) return false;
665 return m_right->parse_term(con);
666 }
667};
668
669
670//choice
671class _choice : public _binary {
672public:
673 //constructor.
674 _choice(_expr* left, _expr* right) :
675 _binary(left, right)
676 {
677 }
678
679 //parse with whitespace
680 virtual bool parse_non_term(_context& con) const {
681 _state st(con);
682 if (m_left->parse_non_term(con)) return true;
683 con.restore(st);
684 return m_right->parse_non_term(con);
685 }
686
687 //parse terminal
688 virtual bool parse_term(_context& con) const {
689 _state st(con);
690 if (m_left->parse_term(con)) return true;
691 con.restore(st);
692 return m_right->parse_term(con);
693 }
694};
695
696
697//reference to rule
698class _ref : public _expr {
699public:
700 //constructor.
701 _ref(rule& r) :
702 m_rule(r)
703 {
704 }
705
706 //parse with whitespace
707 virtual bool parse_non_term(_context& con) const {
708 return con.parse_non_term(m_rule);
709 }
710
711 //parse terminal
712 virtual bool parse_term(_context& con) const {
713 return con.parse_term(m_rule);
714 }
715
716private:
717 //reference
718 rule &m_rule;
719};
720
721
722//eof
723class _eof : public _expr {
724public:
725 //parse with whitespace
726 virtual bool parse_non_term(_context& con) const {
727 return parse_term(con);
728 }
729
730 //parse terminal
731 virtual bool parse_term(_context& con) const {
732 return con.end();
733 }
734};
735
736
737//any
738class _any : public _expr {
739public:
740 //parse with whitespace
741 virtual bool parse_non_term(_context& con) const {
742 return parse_term(con);
743 }
744
745 //parse terminal
746 virtual bool parse_term(_context& con) const {
747 if (!con.end()) {
748 con.next_col();
749 return true;
750 }
751 con.set_error_pos();
752 return false;
753 }
754};
755
756
757//true
758class _true : public _expr {
759public:
760 //parse with whitespace
761 virtual bool parse_non_term(_context&) const {
762 return true;
763 }
764
765 //parse terminal
766 virtual bool parse_term(_context&) const {
767 return true;
768 }
769};
770
771
772//false
773class _false: public _expr {
774public:
775 //parse with whitespace
776 virtual bool parse_non_term(_context&) const {
777 return false;
778 }
779
780 //parse terminal
781 virtual bool parse_term(_context&) const {
782 return false;
783 }
784};
785
786//exception thrown when left recursion terminates successfully
787struct _lr_ok {
788 rule* m_rule;
789 _lr_ok(rule* r) : m_rule(r) {}
790};
791
792
793//constructor
794_state::_state(_context& con) :
795 m_pos(con.m_pos),
796 m_matches(con.m_matches.size())
797{
798}
799
800
801//parse non-term rule.
802bool _context::parse_non_term(rule& r) {
803 //save the state of the rule
804 rule::_state old_state = r.m_state;
805
806 //success/failure result
807 bool ok = false;
808
809 //compute the new position
810 size_t new_pos = m_pos.m_it - m_begin;
811
812 //check if we have left recursion
813 bool lr = new_pos == r.m_state.m_pos;
814
815 //update the rule's state
816 r.m_state.m_pos = new_pos;
817
818 //handle the mode of the rule
819 switch (r.m_state.m_mode) {
820 //normal parse
821 case rule::_PARSE:
822 if (lr) {
823 //first try to parse the rule by rejecting it, so alternative branches are examined
824 r.m_state.m_mode = rule::_REJECT;
825 ok = _parse_non_term(r);
826
827 //if the first try is successful, try accepting the rule,
828 //so other elements of the sequence are parsed
829 if (ok) {
830 r.m_state.m_mode = rule::_ACCEPT;
831
832 //loop until no more parsing can be done
833 for(;;) {
834 //store the correct state, in order to backtrack if the call fails
835 _state st(*this);
836
837 //update the rule position to the current position,
838 //because at this state the rule is resolving the left recursion
839 r.m_state.m_pos = m_pos.m_it - m_begin;
840
841 //if parsing fails, restore the last good state and stop
842 if (!_parse_non_term(r)) {
843 restore(st);
844 break;
845 }
846 }
847
848 //since the left recursion was resolved successfully,
849 //return via a non-local exit
850 r.m_state = old_state;
851 throw _lr_ok(r.this_ptr());
852 }
853 }
854 else {
855 try {
856 ok = _parse_non_term(r);
857 }
858 catch (const _lr_ok &ex) {
859 //since left recursions may be mutual, we must test which rule's left recursion
860 //was ended successfully
861 if (ex.m_rule == r.this_ptr()) {
862 ok = true;
863 }
864 else {
865 r.m_state = old_state;
866 throw;
867 }
868 }
869 }
870 break;
871
872 //reject the left recursive rule
873 case rule::_REJECT:
874 if (lr) {
875 ok = false;
876 }
877 else {
878 r.m_state.m_mode = rule::_PARSE;
879 ok = _parse_non_term(r);
880 r.m_state.m_mode = rule::_REJECT;
881 }
882 break;
883
884 //accept the left recursive rule
885 case rule::_ACCEPT:
886 if (lr) {
887 ok = true;
888 }
889 else {
890 r.m_state.m_mode = rule::_PARSE;
891 ok = _parse_non_term(r);
892 r.m_state.m_mode = rule::_ACCEPT;
893 }
894 break;
895 }
896
897 //restore the rule's state
898 r.m_state = old_state;
899
900 return ok;
901}
902
903
904//parse term rule.
905bool _context::parse_term(rule& r) {
906 //save the state of the rule
907 rule::_state old_state = r.m_state;
908
909 //success/failure result
910 bool ok = false;
911
912 //compute the new position
913 size_t new_pos = m_pos.m_it - m_begin;
914
915 //check if we have left recursion
916 bool lr = new_pos == r.m_state.m_pos;
917
918 //update the rule's state
919 r.m_state.m_pos = new_pos;
920
921 //handle the mode of the rule
922 switch (r.m_state.m_mode) {
923 //normal parse
924 case rule::_PARSE:
925 if (lr) {
926 //first try to parse the rule by rejecting it, so alternative branches are examined
927 r.m_state.m_mode = rule::_REJECT;
928 ok = _parse_term(r);
929
930 //if the first try is successful, try accepting the rule,
931 //so other elements of the sequence are parsed
932 if (ok) {
933 r.m_state.m_mode = rule::_ACCEPT;
934
935 //loop until no more parsing can be done
936 for(;;) {
937 //store the correct state, in order to backtrack if the call fails
938 _state st(*this);
939
940 //update the rule position to the current position,
941 //because at this state the rule is resolving the left recursion
942 r.m_state.m_pos = m_pos.m_it - m_begin;
943
944 //if parsing fails, restore the last good state and stop
945 if (!_parse_term(r)) {
946 restore(st);
947 break;
948 }
949 }
950
951 //since the left recursion was resolved successfully,
952 //return via a non-local exit
953 r.m_state = old_state;
954 throw _lr_ok(r.this_ptr());
955 }
956 } else {
957 try {
958 ok = _parse_term(r);
959 }
960 catch (const _lr_ok& ex) {
961 //since left recursions may be mutual, we must test which rule's left recursion
962 //was ended successfully
963 if (ex.m_rule == r.this_ptr()) {
964 ok = true;
965 }
966 else {
967 r.m_state = old_state;
968 throw;
969 }
970 }
971 }
972 break;
973
974 //reject the left recursive rule
975 case rule::_REJECT:
976 if (lr) {
977 ok = false;
978 } else {
979 r.m_state.m_mode = rule::_PARSE;
980 ok = _parse_term(r);
981 r.m_state.m_mode = rule::_REJECT;
982 }
983 break;
984
985 //accept the left recursive rule
986 case rule::_ACCEPT:
987 if (lr) {
988 ok = true;
989 } else {
990 r.m_state.m_mode = rule::_PARSE;
991 ok = _parse_term(r);
992 r.m_state.m_mode = rule::_ACCEPT;
993 }
994 break;
995 }
996
997 //restore the rule's state
998 r.m_state = old_state;
999
1000 return ok;
1001}
1002
1003
1004//parse non-term rule internal.
1005bool _context::_parse_non_term(rule& r) {
1006 bool ok = false;
1007 if (_private::get_parse_proc(r)) {
1008 pos b = m_pos;
1009 ok = _private::get_expr(r)->parse_non_term(*this);
1010 if (ok) {
1011 m_matches.push_back(_match(r.this_ptr(), b, m_pos));
1012 }
1013 } else {
1014 ok = _private::get_expr(r)->parse_non_term(*this);
1015 }
1016 return ok;
1017}
1018
1019
1020//parse term rule internal.
1021bool _context::_parse_term(rule& r) {
1022 bool ok = false;
1023 if (_private::get_parse_proc(r)) {
1024 pos b = m_pos;
1025 ok = _private::get_expr(r)->parse_term(*this);
1026 if (ok) {
1027 m_matches.push_back(_match(r.this_ptr(), b, m_pos));
1028 }
1029 } else {
1030 ok = _private::get_expr(r)->parse_term(*this);
1031 }
1032 return ok;
1033}
1034
1035
1036//get syntax error
1037static error _syntax_error(_context& con) {
1038 return error(con.m_error_pos, con.m_error_pos, ERROR_SYNTAX_ERROR);
1039}
1040
1041
1042//get eof error
1043static error _eof_error(_context& con) {
1044 return error(con.m_error_pos, con.m_error_pos, ERROR_INVALID_EOF);
1045}
1046
1047
1048/** constructor from input.
1049 @param i input.
1050*/
1051pos::pos(input& i) :
1052 m_it(i.begin()),
1053 m_line(1),
1054 m_col(1)
1055{
1056}
1057
1058
1059/** character terminal constructor.
1060 @param c character.
1061*/
1062expr::expr(char c) :
1063 m_expr(new _char(c))
1064{
1065}
1066
1067
1068/** null-terminated string terminal constructor.
1069 @param s null-terminated string.
1070*/
1071expr::expr(const char* s) :
1072 m_expr(new _string(s))
1073{
1074}
1075
1076
1077/** rule reference constructor.
1078 @param r rule.
1079*/
1080expr::expr(rule& r) :
1081 m_expr(new _ref(r))
1082{
1083}
1084
1085
1086/** creates a zero-or-more loop out of this expression.
1087 @return a zero-or-more loop expression.
1088*/
1089expr expr::operator*() const {
1090 return _private::construct_expr(new _loop0(m_expr));
1091}
1092
1093
1094/** creates a one-or-more loop out of this expression.
1095 @return a one-or-more loop expression.
1096*/
1097expr expr::operator+() const {
1098 return _private::construct_expr(new _loop1(m_expr));
1099}
1100
1101
1102/** creates an optional out of this expression.
1103 @return an optional expression.
1104*/
1105expr expr::operator-() const {
1106 return _private::construct_expr(new _optional(m_expr));
1107}
1108
1109
1110/** creates an AND-expression.
1111 @return an AND-expression.
1112*/
1113expr expr::operator&() const {
1114 return _private::construct_expr((new _and(m_expr)));
1115}
1116
1117
1118/** creates a NOT-expression.
1119 @return a NOT-expression.
1120*/
1121expr expr::operator!() const {
1122 return _private::construct_expr(new _not(m_expr));
1123}
1124
1125
1126/** constructor.
1127 @param b begin position.
1128 @param e end position.
1129*/
1130input_range::input_range(const pos& b, const pos& e) :
1131m_begin(b),
1132m_end(e) {}
1133
1134
1135/** constructor.
1136 @param b begin position.
1137 @param e end position.
1138 @param t error type.
1139*/
1140error::error(const pos& b, const pos& e, int t) :
1141input_range(b, e),
1142m_type(t) {}
1143
1144
1145/** compare on begin position.
1146 @param e the other error to compare this with.
1147 @return true if this comes before the previous error, false otherwise.
1148*/
1149bool error::operator<(const error& e) const {
1150 return m_begin.m_it < e.m_begin.m_it;
1151}
1152
1153rule::rule() :
1154m_expr(nullptr),
1155m_parse_proc(nullptr) {}
1156
1157/** character terminal constructor.
1158 @param c character.
1159*/
1160rule::rule(char c) :
1161m_expr(new _char(c)),
1162m_parse_proc(nullptr) {}
1163
1164/** null-terminated string terminal constructor.
1165 @param s null-terminated string.
1166*/
1167rule::rule(const char* s) :
1168m_expr(new _string(s)),
1169m_parse_proc(nullptr) {}
1170
1171/** constructor from expression.
1172 @param e expression.
1173*/
1174rule::rule(const expr& e) :
1175m_expr(_private::get_expr(e)),
1176m_parse_proc(nullptr) {}
1177
1178
1179/** constructor from rule.
1180 @param r rule.
1181*/
1182rule::rule(rule& r) :
1183m_expr(new _ref(r)),
1184m_parse_proc(nullptr) {}
1185
1186rule& rule::operator=(rule& r) {
1187 m_expr = new _ref(r);
1188 return *this;
1189}
1190
1191rule &rule::operator=(const expr& e) {
1192 m_expr = _private::get_expr(e);
1193 return *this;
1194}
1195
1196/** invalid constructor from rule (required by gcc).
1197 @exception std::logic_error always thrown.
1198*/
1199rule::rule(const rule&) {
1200 throw std::logic_error("invalid operation");
1201}
1202
1203
1204/** deletes the internal object that represents the expression.
1205*/
1206rule::~rule() {
1207 delete m_expr;
1208}
1209
1210
1211/** creates a zero-or-more loop out of this rule.
1212 @return a zero-or-more loop rule.
1213*/
1214expr rule::operator*() {
1215 return _private::construct_expr(new _loop0(new _ref(*this)));
1216}
1217
1218
1219/** creates a one-or-more loop out of this rule.
1220 @return a one-or-more loop rule.
1221*/
1222expr rule::operator+() {
1223 return _private::construct_expr(new _loop1(new _ref(*this)));
1224}
1225
1226
1227/** creates an optional out of this rule.
1228 @return an optional rule.
1229*/
1230expr rule::operator-() {
1231 return _private::construct_expr(new _optional(new _ref(*this)));
1232}
1233
1234
1235/** creates an AND-expression out of this rule.
1236 @return an AND-expression out of this rule.
1237*/
1238expr rule::operator&() {
1239 return _private::construct_expr(new _and(new _ref(*this)));
1240}
1241
1242
1243/** creates a NOT-expression out of this rule.
1244 @return a NOT-expression out of this rule.
1245*/
1246expr rule::operator!() {
1247 return _private::construct_expr(new _not(new _ref(*this)));
1248}
1249
1250
1251/** sets the parse procedure.
1252 @param p procedure.
1253*/
1254void rule::set_parse_proc(parse_proc p) {
1255 assert(p);
1256 m_parse_proc = p;
1257}
1258
1259
1260/** creates a sequence of expressions.
1261 @param left left operand.
1262 @param right right operand.
1263 @return an expression which parses a sequence.
1264*/
1265expr operator >> (const expr& left, const expr& right) {
1266 return _private::construct_expr(
1267 new _seq(_private::get_expr(left), _private::get_expr(right)));
1268}
1269
1270
1271/** creates a choice of expressions.
1272 @param left left operand.
1273 @param right right operand.
1274 @return an expression which parses a choice.
1275*/
1276expr operator | (const expr& left, const expr& right) {
1277 return _private::construct_expr(
1278 new _choice(_private::get_expr(left), _private::get_expr(right)));
1279}
1280
1281
1282/** converts a parser expression into a terminal.
1283 @param e expression.
1284 @return an expression which parses a terminal.
1285*/
1286expr term(const expr& e) {
1287 return _private::construct_expr(
1288 new _term(_private::get_expr(e)));
1289}
1290
1291
1292/** creates a set expression from a null-terminated string.
1293 @param s null-terminated string with characters of the set.
1294 @return an expression which parses a single character out of a set.
1295*/
1296expr set(const char* s) {
1297 return _private::construct_expr(new _set(s));
1298}
1299
1300
1301/** creates a range expression.
1302 @param min min character.
1303 @param max max character.
1304 @return an expression which parses a single character out of range.
1305*/
1306expr range(int min, int max) {
1307 return _private::construct_expr(new _set(min, max));
1308}
1309
1310
1311/** creates an expression which increments the line counter
1312 and resets the column counter when the given expression
1313 is parsed successfully; used for newline characters.
1314 @param e expression to wrap into a newline parser.
1315 @return an expression that handles newlines.
1316*/
1317expr nl(const expr& e) {
1318 return _private::construct_expr(new _nl(_private::get_expr(e)));
1319}
1320
1321
1322/** creates an expression which tests for the end of input.
1323 @return an expression that handles the end of input.
1324*/
1325expr eof() {
1326 return _private::construct_expr(new _eof());
1327}
1328
1329
1330/** creates a not expression.
1331 @param e expression.
1332 @return the appropriate expression.
1333*/
1334expr not_(const expr& e) {
1335 return !e;
1336}
1337
1338
1339/** creates an and expression.
1340 @param e expression.
1341 @return the appropriate expression.
1342*/
1343expr and_(const expr& e) {
1344 return &e;
1345}
1346
1347
1348/** creates an expression that parses any character.
1349 @return the appropriate expression.
1350*/
1351expr any() {
1352 return _private::construct_expr(new _any());
1353}
1354
1355
1356/** parsing succeeds without consuming any input.
1357*/
1358expr true_() {
1359 return _private::construct_expr(new _true());
1360}
1361
1362
1363/** parsing fails without consuming any input.
1364*/
1365expr false_() {
1366 return _private::construct_expr(new _false());
1367}
1368
1369
1370/** parse with target expression and let user handle result.
1371*/
1372expr user(const expr& e, const user_handler& handler) {
1373 return _private::construct_expr(new _user(_private::get_expr(e), handler));
1374}
1375
1376
1377/** parses the given input.
1378 The parse procedures of each rule parsed are executed
1379 before this function returns, if parsing succeeds.
1380 @param i input.
1381 @param g root rule of grammar.
1382 @param el list of errors.
1383 @param d user data, passed to the parse procedures.
1384 @return true on parsing success, false on failure.
1385*/
1386bool parse(input& i, rule& g, error_list& el, void* d, void* ud) {
1387 //prepare context
1388 _context con(i, ud);
1389
1390 //parse grammar
1391 if (!con.parse_non_term(g)) {
1392 el.push_back(_syntax_error(con));
1393 return false;
1394 }
1395
1396 //if end is not reached, there was an error
1397 if (!con.end()) {
1398 if (con.m_error_pos.m_it < con.m_end) {
1399 el.push_back(_syntax_error(con));
1400 } else {
1401 el.push_back(_eof_error(con));
1402 }
1403 return false;
1404 }
1405
1406 //success; execute the parse procedures
1407 con.do_parse_procs(d);
1408 return true;
1409}
1410
1411
1412} //namespace parserlib
diff --git a/src/MoonP/parser.hpp b/src/MoonP/parser.hpp
deleted file mode 100644
index f70475f..0000000
--- a/src/MoonP/parser.hpp
+++ /dev/null
@@ -1,422 +0,0 @@
1/* Copyright (c) 2012, Achilleas Margaritis, modified by Jin Li
2All rights reserved.
3
4Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
6Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
8Redistributions 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.
9
10THIS 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.*/
11
12#pragma once
13
14
15//gcc chokes without rule::rule(const rule &),
16//msvc complains when rule::rule(const rule &) is defined.
17#ifdef _MSC_VER
18#pragma warning (disable: 4521)
19#endif
20
21
22#include <vector>
23#include <string>
24#include <list>
25#include <functional>
26#include <codecvt>
27#include <locale>
28
29namespace parserlib {
30
31///type of the parser's input.
32typedef std::basic_string<wchar_t> input;
33typedef input::iterator input_it;
34typedef std::wstring_convert<std::codecvt_utf8_utf16<input::value_type>> Converter;
35
36class _private;
37class _expr;
38class _context;
39class rule;
40
41
42struct item_t {
43 input_it begin;
44 input_it end;
45 void* user_data;
46};
47typedef std::function<bool(const item_t&)> user_handler;
48
49
50///position into the input.
51class pos {
52public:
53 ///interator into the input.
54 input::iterator m_it;
55
56 ///line.
57 int m_line;
58
59 ///column.
60 int m_col;
61
62 ///null constructor.
63 pos():m_line(0),m_col(0) {}
64
65 /** constructor from input.
66 @param i input.
67 */
68 pos(input &i);
69};
70
71
72/** a grammar expression.
73*/
74class expr {
75public:
76 /** character terminal constructor.
77 @param c character.
78 */
79 expr(char c);
80
81 /** null-terminated string terminal constructor.
82 @param s null-terminated string.
83 */
84 expr(const char* s);
85
86 /** rule reference constructor.
87 @param r rule.
88 */
89 expr(rule& r);
90
91 /** creates a zero-or-more loop out of this expression.
92 @return a zero-or-more loop expression.
93 */
94 expr operator*() const;
95
96 /** creates a one-or-more loop out of this expression.
97 @return a one-or-more loop expression.
98 */
99 expr operator+() const;
100
101 /** creates an optional out of this expression.
102 @return an optional expression.
103 */
104 expr operator-() const;
105
106 /** creates an AND-expression.
107 @return an AND-expression.
108 */
109 expr operator&() const;
110
111 /** creates a NOT-expression.
112 @return a NOT-expression.
113 */
114 expr operator!() const;
115
116private:
117 //internal expression
118 _expr* m_expr;
119
120 //internal constructor from internal expression
121 expr(_expr* e) : m_expr(e) {}
122
123 //assignment not allowed
124 expr& operator=(expr&);
125
126 friend class _private;
127};
128
129
130/** type of procedure to invoke when a rule is successfully parsed.
131 @param b begin position of input.
132 @param e end position of input.
133 @param d pointer to user data.
134*/
135typedef void (*parse_proc)(const pos& b, const pos& e, void* d);
136
137
138///input range.
139class input_range {
140public:
141 virtual ~input_range() {}
142
143 ///begin position.
144 pos m_begin;
145
146 ///end position.
147 pos m_end;
148
149 ///empty constructor.
150 input_range() {}
151
152 /** constructor.
153 @param b begin position.
154 @param e end position.
155 */
156 input_range(const pos& b, const pos& e);
157};
158
159
160///enum with error types.
161enum ERROR_TYPE {
162 ///syntax error
163 ERROR_SYNTAX_ERROR = 1,
164
165 ///invalid end of file
166 ERROR_INVALID_EOF,
167
168 ///first user error
169 ERROR_USER = 100
170};
171
172
173///error.
174class error : public input_range {
175public:
176 ///type
177 int m_type;
178
179 /** constructor.
180 @param b begin position.
181 @param e end position.
182 @param t type.
183 */
184 error(const pos& b, const pos& e, int t);
185
186 /** compare on begin position.
187 @param e the other error to compare this with.
188 @return true if this comes before the previous error, false otherwise.
189 */
190 bool operator<(const error& e) const;
191};
192
193
194///type of error list.
195typedef std::list<error> error_list;
196
197
198/** represents a rule.
199*/
200class rule {
201public:
202 /** character terminal constructor.
203 @param c character.
204 */
205 rule();
206 rule(char c);
207
208 /** null-terminated string terminal constructor.
209 @param s null-terminated string.
210 */
211 rule(const char* s);
212
213 /** constructor from expression.
214 @param e expression.
215 */
216 rule(const expr& e);
217
218 /** constructor from rule.
219 @param r rule.
220 */
221 rule(rule& r);
222
223 /** invalid constructor from rule (required by gcc).
224 @param r rule.
225 @exception std::logic_error always thrown.
226 */
227 rule(const rule& r);
228
229 /** deletes the internal object that represents the expression.
230 */
231 ~rule();
232
233 /** creates a zero-or-more loop out of this rule.
234 @return a zero-or-more loop rule.
235 */
236 expr operator*();
237
238 /** creates a one-or-more loop out of this rule.
239 @return a one-or-more loop rule.
240 */
241 expr operator+();
242
243 /** creates an optional out of this rule.
244 @return an optional rule.
245 */
246 expr operator-();
247
248 /** creates an AND-expression out of this rule.
249 @return an AND-expression out of this rule.
250 */
251 expr operator&();
252
253 /** creates a NOT-expression out of this rule.
254 @return a NOT-expression out of this rule.
255 */
256 expr operator!();
257
258 /** sets the parse procedure.
259 @param p procedure.
260 */
261 void set_parse_proc(parse_proc p);
262
263 /** get the this ptr (since operator & is overloaded).
264 @return pointer to this.
265 */
266 rule* this_ptr() { return this; }
267
268 rule& operator=(rule&);
269
270 rule& operator=(const expr&);
271
272private:
273 //mode
274 enum _MODE {
275 _PARSE,
276 _REJECT,
277 _ACCEPT
278 };
279
280 //state
281 struct _state {
282 //position in source code, relative to start
283 size_t m_pos;
284
285 //mode
286 _MODE m_mode;
287
288 //constructor
289 _state(size_t pos = -1, _MODE mode = _PARSE) :
290 m_pos(pos), m_mode(mode) {}
291 };
292
293 //internal expression
294 _expr* m_expr;
295
296 //associated parse procedure.
297 parse_proc m_parse_proc;
298
299 //state
300 _state m_state;
301
302 friend class _private;
303 friend class _context;
304};
305
306
307/** creates a sequence of expressions.
308 @param left left operand.
309 @param right right operand.
310 @return an expression which parses a sequence.
311*/
312expr operator>>(const expr& left, const expr& right);
313
314
315/** creates a choice of expressions.
316 @param left left operand.
317 @param right right operand.
318 @return an expression which parses a choice.
319*/
320expr operator|(const expr& left, const expr& right);
321
322
323/** converts a parser expression into a terminal.
324 @param e expression.
325 @return an expression which parses a terminal.
326*/
327expr term(const expr& e);
328
329
330/** creates a set expression from a null-terminated string.
331 @param s null-terminated string with characters of the set.
332 @return an expression which parses a single character out of a set.
333*/
334expr set(const char* s);
335
336
337/** creates a range expression.
338 @param min min character.
339 @param max max character.
340 @return an expression which parses a single character out of range.
341*/
342expr range(int min, int max);
343
344
345/** creates an expression which increments the line counter
346 and resets the column counter when the given expression
347 is parsed successfully; used for newline characters.
348 @param e expression to wrap into a newline parser.
349 @return an expression that handles newlines.
350*/
351expr nl(const expr& e);
352
353
354/** creates an expression which tests for the end of input.
355 @return an expression that handles the end of input.
356*/
357expr eof();
358
359
360/** creates a not expression.
361 @param e expression.
362 @return the appropriate expression.
363*/
364expr not_(const expr& e);
365
366
367/** creates an and expression.
368 @param e expression.
369 @return the appropriate expression.
370*/
371expr and_(const expr& e);
372
373
374/** creates an expression that parses any character.
375 @return the appropriate expression.
376*/
377expr any();
378
379
380/** parsing succeeds without consuming any input.
381*/
382expr true_();
383
384
385/** parsing fails without consuming any input.
386*/
387expr false_();
388
389
390/** parse with target expression and let user handle result.
391*/
392expr user(const expr& e, const user_handler& handler);
393
394
395/** parses the given input.
396 The parse procedures of each rule parsed are executed
397 before this function returns, if parsing succeeds.
398 @param i input.
399 @param g root rule of grammar.
400 @param el list of errors.
401 @param d user data, passed to the parse procedures.
402 @return true on parsing success, false on failure.
403*/
404bool parse(input& i, rule& g, error_list& el, void* d, void* ud);
405
406
407/** output the specific input range to the specific stream.
408 @param stream stream.
409 @param ir input range.
410 @return the stream.
411*/
412template <class T> T& operator<<(T& stream, const input_range& ir) {
413 for(input::const_iterator it = ir.m_begin.m_it;
414 it != ir.m_end.m_it;
415 ++it) {
416 stream << (typename T::char_type)*it;
417 }
418 return stream;
419}
420
421
422} //namespace parserlib
diff --git a/src/MoonP/stacktraceplus.h b/src/MoonP/stacktraceplus.h
deleted file mode 100644
index e884a2c..0000000
--- a/src/MoonP/stacktraceplus.h
+++ /dev/null
@@ -1,528 +0,0 @@
1R"lua_codes(
2--[[
3Copyright (c) 2010 Ignacio Burgueño, modified by Li Jin
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.]]
22
23-- tables
24local _G = _G
25local string, io, debug, coroutine = string, io, debug, coroutine
26
27-- functions
28local tostring, require = tostring, require
29local next, assert = next, assert
30local pcall, type, pairs, ipairs = pcall, type, pairs, ipairs
31local error = error
32
33assert(debug, "debug table must be available at this point")
34
35local string_gmatch = string.gmatch
36local string_sub = string.sub
37local table_concat = table.concat
38
39local moonp = require("moonp")
40
41local _M = {
42 max_tb_output_len = 70, -- controls the maximum length of the 'stringified' table before cutting with ' (more...)'
43 dump_locals = true,
44 simplified = false
45}
46
47-- this tables should be weak so the elements in them won't become uncollectable
48local m_known_tables = { [_G] = "_G (global table)" }
49local function add_known_module(name, desc)
50 local ok, mod = pcall(require, name)
51 if ok then
52 m_known_tables[mod] = desc
53 end
54end
55
56add_known_module("string", "string module")
57add_known_module("io", "io module")
58add_known_module("os", "os module")
59add_known_module("table", "table module")
60add_known_module("math", "math module")
61add_known_module("package", "package module")
62add_known_module("debug", "debug module")
63add_known_module("coroutine", "coroutine module")
64
65-- lua5.2
66add_known_module("bit32", "bit32 module")
67-- luajit
68add_known_module("bit", "bit module")
69add_known_module("jit", "jit module")
70-- lua5.3
71if _VERSION >= "Lua 5.3" then
72 add_known_module("utf8", "utf8 module")
73end
74
75
76local m_user_known_tables = {}
77
78local m_known_functions = {}
79for _, name in ipairs{
80 -- Lua 5.2, 5.1
81 "assert",
82 "collectgarbage",
83 "dofile",
84 "error",
85 "getmetatable",
86 "ipairs",
87 "load",
88 "loadfile",
89 "next",
90 "pairs",
91 "pcall",
92 "print",
93 "rawequal",
94 "rawget",
95 "rawlen",
96 "rawset",
97 "require",
98 "select",
99 "setmetatable",
100 "tonumber",
101 "tostring",
102 "type",
103 "xpcall",
104
105 -- Lua 5.1
106 "gcinfo",
107 "getfenv",
108 "loadstring",
109 "module",
110 "newproxy",
111 "setfenv",
112 "unpack",
113 -- TODO: add table.* etc functions
114} do
115 if _G[name] then
116 m_known_functions[_G[name]] = name
117 end
118end
119
120local m_user_known_functions = {}
121
122local function safe_tostring (value)
123 local ok, err = pcall(tostring, value)
124 if ok then return err else return ("<failed to get printable value>: '%s'"):format(err) end
125end
126
127-- Private:
128-- Parses a line, looking for possible function definitions (in a very naive way)
129-- Returns '(anonymous)' if no function name was found in the line
130local function ParseLine(line)
131 assert(type(line) == "string")
132 local match = line:match("^%s*function%s+(%w+)")
133 if match then
134 --print("+++++++++++++function", match)
135 return match
136 end
137 match = line:match("^%s*local%s+function%s+(%w+)")
138 if match then
139 --print("++++++++++++local", match)
140 return match
141 end
142 match = line:match("^%s*local%s+(%w+)%s+=%s+function")
143 if match then
144 --print("++++++++++++local func", match)
145 return match
146 end
147 match = line:match("%s*function%s*%(") -- this is an anonymous function
148 if match then
149 --print("+++++++++++++function2", match)
150 return "(anonymous)"
151 end
152 return "(anonymous)"
153end
154
155-- Private:
156-- Tries to guess a function's name when the debug info structure does not have it.
157-- It parses either the file or the string where the function is defined.
158-- Returns '?' if the line where the function is defined is not found
159local function GuessFunctionName(info)
160 -- print("guessing function name")
161 if type(info.source) == "string" and info.source:sub(1,1) == "@" then
162 local fname = info.source:sub(2)
163 local text
164 if moonp.file_exist(fname) then
165 text = moonp.read_file(fname)
166 end
167 if not text then
168 -- print("file not found: "..tostring(err)) -- whoops!
169 return "?"
170 end
171 local line
172 local count = 0
173 for lineText in (text.."\n"):gmatch("(.-)\n") do
174 line = lineText
175 count = count + 1
176 if count == info.linedefined then
177 break
178 end
179 end
180 if not line then
181 --print("line not found") -- whoops!
182 return "?"
183 end
184 return ParseLine(line)
185 else
186 local line
187 local lineNumber = 0
188 for l in string_gmatch(info.source, "([^\n]+)\n-") do
189 lineNumber = lineNumber + 1
190 if lineNumber == info.linedefined then
191 line = l
192 break
193 end
194 end
195 if not line then
196 -- print("line not found") -- whoops!
197 return "?"
198 end
199 return ParseLine(line)
200 end
201end
202
203---
204-- Dumper instances are used to analyze stacks and collect its information.
205--
206local Dumper = {}
207
208Dumper.new = function(thread)
209 local t = { lines = {} }
210 for k,v in pairs(Dumper) do t[k] = v end
211
212 t.dumping_same_thread = (thread == coroutine.running())
213
214 -- if a thread was supplied, bind it to debug.info and debug.get
215 -- we also need to skip this additional level we are introducing in the callstack (only if we are running
216 -- in the same thread we're inspecting)
217 if type(thread) == "thread" then
218 t.getinfo = function(level, what)
219 if t.dumping_same_thread and type(level) == "number" then
220 level = level + 1
221 end
222 return debug.getinfo(thread, level, what)
223 end
224 t.getlocal = function(level, loc)
225 if t.dumping_same_thread then
226 level = level + 1
227 end
228 return debug.getlocal(thread, level, loc)
229 end
230 else
231 t.getinfo = debug.getinfo
232 t.getlocal = debug.getlocal
233 end
234
235 return t
236end
237
238-- helpers for collecting strings to be used when assembling the final trace
239function Dumper:add (text)
240 self.lines[#self.lines + 1] = text
241end
242function Dumper:add_f (fmt, ...)
243 self:add(fmt:format(...))
244end
245function Dumper:concat_lines ()
246 return table_concat(self.lines)
247end
248
249---
250-- Private:
251-- Iterates over the local variables of a given function.
252--
253-- @param level The stack level where the function is.
254--
255function Dumper:DumpLocals (level)
256 if not _M.dump_locals then return end
257
258 local prefix = "\t "
259 local i = 1
260
261 if self.dumping_same_thread then
262 level = level + 1
263 end
264
265 local name, value = self.getlocal(level, i)
266 if not name then
267 return
268 end
269 self:add("\tLocal variables:\r\n")
270 while name do
271 if type(value) == "number" then
272 self:add_f("%s%s = number: %g\r\n", prefix, name, value)
273 elseif type(value) == "boolean" then
274 self:add_f("%s%s = boolean: %s\r\n", prefix, name, tostring(value))
275 elseif type(value) == "string" then
276 self:add_f("%s%s = string: %q\r\n", prefix, name, value)
277 elseif type(value) == "userdata" then
278 self:add_f("%s%s = %s\r\n", prefix, name, safe_tostring(value))
279 elseif type(value) == "nil" then
280 self:add_f("%s%s = nil\r\n", prefix, name)
281 elseif type(value) == "table" then
282 if m_known_tables[value] then
283 self:add_f("%s%s = %s\r\n", prefix, name, m_known_tables[value])
284 elseif m_user_known_tables[value] then
285 self:add_f("%s%s = %s\r\n", prefix, name, m_user_known_tables[value])
286 else
287 local txt = "{"
288 for k,v in pairs(value) do
289 txt = txt..safe_tostring(k)..":"..safe_tostring(v)
290 if #txt > _M.max_tb_output_len then
291 txt = txt.." (more...)"
292 break
293 end
294 if next(value, k) then txt = txt..", " end
295 end
296 self:add_f("%s%s = %s %s\r\n", prefix, name, safe_tostring(value), txt.."}")
297 end
298 elseif type(value) == "function" then
299 local info = self.getinfo(value, "nS")
300 local fun_name = info.name or m_known_functions[value] or m_user_known_functions[value]
301 if info.what == "C" then
302 self:add_f("%s%s = C %s\r\n", prefix, name, (fun_name and ("function: " .. fun_name) or tostring(value)))
303 else
304 local source = info.short_src
305 if source:sub(2,7) == "string" then
306 source = source:sub(9)
307 end
308 --for k,v in pairs(info) do print(k,v) end
309 fun_name = fun_name or GuessFunctionName(info)
310 self:add_f("%s%s = Lua function '%s' (defined at line %d of chunk %s)\r\n", prefix, name, fun_name, info.linedefined, source)
311 end
312 elseif type(value) == "thread" then
313 self:add_f("%sthread %q = %s\r\n", prefix, name, tostring(value))
314 end
315 i = i + 1
316 name, value = self.getlocal(level, i)
317 end
318end
319
320local function getMoonLineNumber(fname, line)
321 local moonCompiled = require("moonp").moon_compiled
322 local source = moonCompiled["@"..fname]
323 if not source then
324 source = moonCompiled["@="..fname]
325 end
326 if not source then
327 local name_path = fname:gsub("%.", moonp.dirsep)
328 local file_exist, file_path
329 for path in package.path:gmatch("[^;]+") do
330 file_path = path:gsub("?", name_path)
331 file_exist = moonp.file_exist(file_path)
332 if file_exist then
333 break
334 end
335 end
336 if file_exist then
337 local codes = moonp.read_file(file_path)
338 local moonFile = codes:match("^%s*--%s*%[moonp%]:%s*([^\n]*)")
339 if moonFile then
340 fname = moonFile:gsub("^%s*(.-)%s*$", "%1")
341 source = codes
342 end
343 end
344 end
345 if source then
346 local current, target = 1, tonumber(line)
347 local findLine = line
348 for lineCode in source:gmatch("([^\n]*)\n") do
349 local num = lineCode:match("--%s*(%d+)%s*$")
350 if num then
351 findLine = num
352 end
353 if current == target then
354 return fname, findLine or line
355 end
356 current = current + 1
357 end
358 end
359 return fname, line
360end
361
362---
363-- Public:
364-- Collects a detailed stack trace, dumping locals, resolving function names when they're not available, etc.
365-- This function is suitable to be used as an error handler with pcall or xpcall
366--
367-- @param thread An optional thread whose stack is to be inspected (defaul is the current thread)
368-- @param message An optional error string or object.
369-- @param level An optional number telling at which level to start the traceback (default is 1)
370--
371-- Returns a string with the stack trace.
372--
373function _M.stacktrace(thread, message, level)
374 if type(thread) ~= "thread" then
375 -- shift parameters left
376 thread, message, level = nil, thread, message
377 end
378
379 thread = thread or coroutine.running()
380
381 level = level or 1
382
383 local dumper = Dumper.new(thread)
384
385 if type(message) == "table" then
386 dumper:add("an error object {\r\n")
387 local first = true
388 for k,v in pairs(message) do
389 if first then
390 dumper:add(" ")
391 first = false
392 else
393 dumper:add(",\r\n ")
394 end
395 dumper:add(safe_tostring(k))
396 dumper:add(": ")
397 dumper:add(safe_tostring(v))
398 end
399 dumper:add("\r\n}")
400 elseif type(message) == "string" then
401 local fname, line, msg = message:match('(.+):(%d+): (.*)$')
402 if fname then
403 local nfname, nline, nmsg = fname:match('(.+):(%d+): (.*)$')
404 if nfname then
405 fname = nmsg
406 end
407 end
408 if fname then
409 local fn = fname:match("%[string \"(.-)\"%]")
410 if fn then fname = fn end
411 fname = fname:gsub("^%s*(.-)%s*$", "%1")
412 fname, line = getMoonLineNumber(fname, line)
413 if _M.simplified then
414 message = table.concat({
415 "", fname, ":",
416 line, ": ", msg})
417 message = message:gsub("^%(moonplus%):%s*%d+:%s*", "")
418 message = message:gsub("%s(%d+):", "%1:")
419 else
420 message = table.concat({
421 "[string \"", fname, "\"]:",
422 line, ": ", msg})
423 end
424 end
425 dumper:add(message)
426 end
427
428 dumper:add("\r\n")
429 dumper:add[[
430Stack Traceback
431===============
432]]
433
434 local level_to_show = 1
435 if dumper.dumping_same_thread then level = level + 1 end
436
437 local info = dumper.getinfo(level, "nSlf")
438 while info do
439 if info.source and info.source:sub(1,1) == "@" then
440 info.source = info.source:sub(2)
441 elseif info.what == "main" or info.what == "Lua" then
442 info.source = info.source
443 end
444 info.source, info.currentline = getMoonLineNumber(info.source, info.currentline)
445 if info.what == "main" then
446 if _M.simplified then
447 dumper:add_f("(%d) '%s':%d\r\n", level_to_show, info.source, info.currentline)
448 else
449 dumper:add_f("(%d) main chunk of file '%s' at line %d\r\n", level_to_show, info.source, info.currentline)
450 end
451 elseif info.what == "C" then
452 --print(info.namewhat, info.name)
453 --for k,v in pairs(info) do print(k,v, type(v)) end
454 local function_name = m_user_known_functions[info.func] or m_known_functions[info.func] or info.name or tostring(info.func)
455 dumper:add_f("(%d) %s C function '%s'\r\n", level_to_show, info.namewhat, function_name)
456 --dumper:add_f("%s%s = C %s\r\n", prefix, name, (m_known_functions[value] and ("function: " .. m_known_functions[value]) or tostring(value)))
457 elseif info.what == "tail" then
458 --print("tail")
459 --for k,v in pairs(info) do print(k,v, type(v)) end--print(info.namewhat, info.name)
460 dumper:add_f("(%d) tail call\r\n", level_to_show)
461 dumper:DumpLocals(level)
462 elseif info.what == "Lua" then
463 local source = info.source
464 local function_name = m_user_known_functions[info.func] or m_known_functions[info.func] or info.name
465 if source:sub(2, 7) == "string" then
466 source = source:sub(10,-3)
467 end
468 local was_guessed = false
469 if not function_name or function_name == "?" then
470 --for k,v in pairs(info) do print(k,v, type(v)) end
471 function_name = GuessFunctionName(info)
472 was_guessed = true
473 end
474 -- test if we have a file name
475 local function_type = (info.namewhat == "") and "function" or info.namewhat
476 if info.source and info.source:sub(1, 1) == "@" then
477 if _M.simplified then
478 dumper:add_f("(%d) '%s':%d%s\r\n", level_to_show, info.source:sub(2), info.currentline, was_guessed and " (guess)" or "")
479 else
480 dumper:add_f("(%d) Lua %s '%s' at file '%s':%d%s\r\n", level_to_show, function_type, function_name, info.source:sub(2), info.currentline, was_guessed and " (best guess)" or "")
481 end
482 elseif info.source and info.source:sub(1,1) == '#' then
483 if _M.simplified then
484 dumper:add_f("(%d) '%s':%d%s\r\n", level_to_show, info.source:sub(2), info.currentline, was_guessed and " (guess)" or "")
485 else
486 dumper:add_f("(%d) Lua %s '%s' at template '%s':%d%s\r\n", level_to_show, function_type, function_name, info.source:sub(2), info.currentline, was_guessed and " (best guess)" or "")
487 end
488 else
489 if _M.simplified then
490 dumper:add_f("(%d) '%s':%d\r\n", level_to_show, source, info.currentline)
491 else
492 dumper:add_f("(%d) Lua %s '%s' at chunk '%s':%d\r\n", level_to_show, function_type, function_name, source, info.currentline)
493 end
494 end
495 dumper:DumpLocals(level)
496 else
497 dumper:add_f("(%d) unknown frame %s\r\n", level_to_show, info.what)
498 end
499
500 level = level + 1
501 level_to_show = level_to_show + 1
502 info = dumper.getinfo(level, "nSlf")
503 end
504
505 return dumper:concat_lines()
506end
507
508--
509-- Adds a table to the list of known tables
510function _M.add_known_table(tab, description)
511 if m_known_tables[tab] then
512 error("Cannot override an already known table")
513 end
514 m_user_known_tables[tab] = description
515end
516
517--
518-- Adds a function to the list of known functions
519function _M.add_known_function(fun, description)
520 if m_known_functions[fun] then
521 error("Cannot override an already known function")
522 end
523 m_user_known_functions[fun] = description
524end
525
526return _M
527
528)lua_codes";