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