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