diff options
author | Li Jin <dragon-fly@qq.com> | 2020-01-10 16:30:34 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2020-01-10 16:30:34 +0800 |
commit | 52a6536103f46c26a3ba9b149b0fe7b40d524d8c (patch) | |
tree | 67e4759f8e1ea922079d0e162d84ecba5e558261 /src | |
parent | 975167856ed0b11c2ede03c6eb750ca4e4a6a7fc (diff) | |
download | yuescript-52a6536103f46c26a3ba9b149b0fe7b40d524d8c.tar.gz yuescript-52a6536103f46c26a3ba9b149b0fe7b40d524d8c.tar.bz2 yuescript-52a6536103f46c26a3ba9b149b0fe7b40d524d8c.zip |
update.
Diffstat (limited to 'src')
-rw-r--r-- | src/MoonP/ast.cpp | 132 | ||||
-rw-r--r-- | src/MoonP/ast.hpp | 565 | ||||
-rw-r--r-- | src/MoonP/moon_ast.cpp | 113 | ||||
-rw-r--r-- | src/MoonP/moon_ast.h | 587 | ||||
-rw-r--r-- | src/MoonP/moon_compiler.cpp | 3865 | ||||
-rw-r--r-- | src/MoonP/moon_compiler.h | 39 | ||||
-rw-r--r-- | src/MoonP/moon_parser.cpp | 526 | ||||
-rw-r--r-- | src/MoonP/moon_parser.h | 35 | ||||
-rw-r--r-- | src/MoonP/parser.cpp | 1439 | ||||
-rw-r--r-- | src/MoonP/parser.hpp | 435 | ||||
-rw-r--r-- | src/moonc.cpp | 178 |
11 files changed, 7914 insertions, 0 deletions
diff --git a/src/MoonP/ast.cpp b/src/MoonP/ast.cpp new file mode 100644 index 0000000..cda2339 --- /dev/null +++ b/src/MoonP/ast.cpp | |||
@@ -0,0 +1,132 @@ | |||
1 | /* Copyright (c) 2012, Achilleas Margaritis, modified by Jin Li | ||
2 | All rights reserved. | ||
3 | |||
4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | ||
5 | |||
6 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | ||
7 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | ||
8 | |||
9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | ||
10 | |||
11 | #include <cassert> | ||
12 | #include "MoonP/ast.hpp" | ||
13 | |||
14 | |||
15 | namespace parserlib { | ||
16 | |||
17 | int ast_type_id = 0; | ||
18 | |||
19 | traversal ast_node::traverse(const std::function<traversal (ast_node*)>& func) { | ||
20 | return func(this); | ||
21 | } | ||
22 | |||
23 | ast_node* ast_node::getByTypeIds(int* begin, int* end) { | ||
24 | ast_node* current = this; | ||
25 | auto it = begin; | ||
26 | while (it != end) { | ||
27 | ast_node* findNode = nullptr; | ||
28 | int type = *it; | ||
29 | current->visitChild([&](ast_node* node) { | ||
30 | if (node->get_type() == type) { | ||
31 | findNode = node; | ||
32 | return true; | ||
33 | } | ||
34 | return false; | ||
35 | }); | ||
36 | if (findNode) { | ||
37 | current = findNode; | ||
38 | } else { | ||
39 | current = nullptr; | ||
40 | break; | ||
41 | } | ||
42 | ++it; | ||
43 | } | ||
44 | return current; | ||
45 | } | ||
46 | |||
47 | bool ast_node::visitChild(const std::function<bool (ast_node*)>&) { | ||
48 | return false; | ||
49 | } | ||
50 | |||
51 | |||
52 | /** Asks all members to construct themselves from the stack. | ||
53 | The members are asked to construct themselves in reverse order. | ||
54 | from a node stack. | ||
55 | @param st stack. | ||
56 | */ | ||
57 | void ast_container::construct(ast_stack &st) { | ||
58 | for(ast_member_vector::reverse_iterator it = m_members.rbegin(); | ||
59 | it != m_members.rend(); | ||
60 | ++it) | ||
61 | { | ||
62 | ast_member* member = *it; | ||
63 | member->construct(st); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | traversal ast_container::traverse(const std::function<traversal (ast_node*)>& func) { | ||
68 | traversal action = func(this); | ||
69 | switch (action) { | ||
70 | case traversal::Stop: return traversal::Stop; | ||
71 | case traversal::Return: return traversal::Continue; | ||
72 | default: break; | ||
73 | } | ||
74 | const auto& members = this->members(); | ||
75 | for (auto member : members) { | ||
76 | if (_ast_ptr* ptr = ast_cast<_ast_ptr>(member)) { | ||
77 | if (ptr->get() && ptr->get()->traverse(func) == traversal::Stop) { | ||
78 | return traversal::Stop; | ||
79 | } | ||
80 | } else if (_ast_list* list = ast_cast<_ast_list>(member)) { | ||
81 | for (auto obj : list->objects()) { | ||
82 | if (obj->traverse(func) == traversal::Stop) { | ||
83 | return traversal::Stop; | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | return traversal::Continue; | ||
89 | } | ||
90 | |||
91 | bool ast_container::visitChild(const std::function<bool (ast_node*)>& func) { | ||
92 | const auto& members = this->members(); | ||
93 | for (auto member : members) { | ||
94 | if (_ast_ptr* ptr = ast_cast<_ast_ptr>(member)) { | ||
95 | if (ptr->get()) { | ||
96 | if (func(ptr->get())) return true; | ||
97 | } | ||
98 | } else if (_ast_list* list = ast_cast<_ast_list>(member)) { | ||
99 | for (auto obj : list->objects()) { | ||
100 | if (obj) { | ||
101 | if (func(obj)) return true; | ||
102 | } | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | return false; | ||
107 | } | ||
108 | |||
109 | |||
110 | /** parses the given input. | ||
111 | @param i input. | ||
112 | @param g root rule of grammar. | ||
113 | @param el list of errors. | ||
114 | @param ud user data, passed to the parse procedures. | ||
115 | @return pointer to ast node created, or null if there was an error. | ||
116 | The return object must be deleted by the caller. | ||
117 | */ | ||
118 | ast_node* _parse(input &i, rule &g, error_list &el, void* ud) { | ||
119 | ast_stack st; | ||
120 | if (!parse(i, g, el, &st, ud)) { | ||
121 | for (auto node : st) { | ||
122 | delete node; | ||
123 | } | ||
124 | st.clear(); | ||
125 | return nullptr; | ||
126 | } | ||
127 | assert(st.size() == 1); | ||
128 | return st.front(); | ||
129 | } | ||
130 | |||
131 | |||
132 | } //namespace parserlib | ||
diff --git a/src/MoonP/ast.hpp b/src/MoonP/ast.hpp new file mode 100644 index 0000000..f2ef76c --- /dev/null +++ b/src/MoonP/ast.hpp | |||
@@ -0,0 +1,565 @@ | |||
1 | /* Copyright (c) 2012, Achilleas Margaritis, modified by Jin Li | ||
2 | All rights reserved. | ||
3 | |||
4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | ||
5 | |||
6 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | ||
7 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | ||
8 | |||
9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | ||
10 | |||
11 | #pragma once | ||
12 | |||
13 | |||
14 | #include <cassert> | ||
15 | #include <list> | ||
16 | #include <stdexcept> | ||
17 | #include <type_traits> | ||
18 | #include "MoonP/parser.hpp" | ||
19 | |||
20 | |||
21 | namespace parserlib { | ||
22 | |||
23 | |||
24 | class ast_node; | ||
25 | template <bool Required, class T> class ast_ptr; | ||
26 | template <bool Required, class T> class ast_list; | ||
27 | template <class T> class ast; | ||
28 | |||
29 | |||
30 | /** type of AST node stack. | ||
31 | */ | ||
32 | typedef std::vector<ast_node*> ast_stack; | ||
33 | typedef std::list<ast_node*> node_container; | ||
34 | |||
35 | extern int ast_type_id; | ||
36 | |||
37 | template<class T> | ||
38 | int ast_type() { | ||
39 | static int type = ast_type_id++; | ||
40 | return type; | ||
41 | } | ||
42 | |||
43 | enum class traversal { | ||
44 | Continue, | ||
45 | Return, | ||
46 | Stop | ||
47 | }; | ||
48 | |||
49 | /** Base class for AST nodes. | ||
50 | */ | ||
51 | class ast_node : public input_range { | ||
52 | public: | ||
53 | ast_node() : _ref(0) {} | ||
54 | |||
55 | void retain() { | ||
56 | ++_ref; | ||
57 | } | ||
58 | |||
59 | void release() { | ||
60 | --_ref; | ||
61 | if (_ref == 0) { | ||
62 | delete this; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | /** interface for filling the contents of the node | ||
67 | from a node stack. | ||
68 | @param st stack. | ||
69 | */ | ||
70 | virtual void construct(ast_stack&) {} | ||
71 | |||
72 | /** interface for visiting AST tree use. | ||
73 | */ | ||
74 | virtual traversal traverse(const std::function<traversal (ast_node*)>& func); | ||
75 | |||
76 | template <typename... Ts> | ||
77 | struct select_last { | ||
78 | using type = typename decltype((std::enable_if<true,Ts>{}, ...))::type; | ||
79 | }; | ||
80 | template <typename... Ts> | ||
81 | using select_last_t = typename select_last<Ts...>::type; | ||
82 | |||
83 | template <class ...Args> | ||
84 | select_last_t<Args...>* getByPath() { | ||
85 | int types[] = {ast_type<Args>()...}; | ||
86 | return static_cast<select_last_t<Args...>*>(getByTypeIds(std::begin(types), std::end(types))); | ||
87 | } | ||
88 | |||
89 | virtual bool visitChild(const std::function<bool (ast_node*)>& func); | ||
90 | |||
91 | virtual size_t getId() const = 0; | ||
92 | |||
93 | virtual int get_type() = 0; | ||
94 | |||
95 | template<class T> | ||
96 | inline ast_ptr<false, T> new_ptr() { | ||
97 | auto item = new T; | ||
98 | item->m_begin.m_line = m_begin.m_line; | ||
99 | item->m_end.m_line = m_begin.m_line; | ||
100 | return ast_ptr<false, T>(item); | ||
101 | } | ||
102 | private: | ||
103 | int _ref; | ||
104 | ast_node* getByTypeIds(int* begin, int* end); | ||
105 | }; | ||
106 | |||
107 | template<class T> | ||
108 | T* ast_cast(ast_node* node) { | ||
109 | return node && ast_type<T>() == node->get_type() ? static_cast<T*>(node) : nullptr; | ||
110 | } | ||
111 | |||
112 | template<class T> | ||
113 | T* ast_to(ast_node* node) { | ||
114 | assert(node->get_type() == ast_type<T>()); | ||
115 | return static_cast<T*>(node); | ||
116 | } | ||
117 | |||
118 | template <class ...Args> | ||
119 | bool ast_is(ast_node* node) { | ||
120 | if (!node) return false; | ||
121 | bool result = false; | ||
122 | int type = node->get_type(); | ||
123 | using swallow = bool[]; | ||
124 | (void)swallow{result || (result = ast_type<Args>() == type)...}; | ||
125 | return result; | ||
126 | } | ||
127 | |||
128 | class ast_member; | ||
129 | |||
130 | /** type of ast member vector. | ||
131 | */ | ||
132 | typedef std::vector<ast_member*> ast_member_vector; | ||
133 | |||
134 | |||
135 | /** base class for AST nodes with children. | ||
136 | */ | ||
137 | class ast_container : public ast_node { | ||
138 | public: | ||
139 | void add_members(std::initializer_list<ast_member*> members) { | ||
140 | for (auto member : members) { | ||
141 | m_members.push_back(member); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | /** returns the vector of AST members. | ||
146 | @return the vector of AST members. | ||
147 | */ | ||
148 | const ast_member_vector& members() const { | ||
149 | return m_members; | ||
150 | } | ||
151 | |||
152 | /** Asks all members to construct themselves from the stack. | ||
153 | The members are asked to construct themselves in reverse order. | ||
154 | from a node stack. | ||
155 | @param st stack. | ||
156 | */ | ||
157 | virtual void construct(ast_stack& st) override; | ||
158 | |||
159 | virtual traversal traverse(const std::function<traversal (ast_node*)>& func) override; | ||
160 | |||
161 | virtual bool visitChild(const std::function<bool (ast_node*)>& func) override; | ||
162 | private: | ||
163 | ast_member_vector m_members; | ||
164 | |||
165 | friend class ast_member; | ||
166 | }; | ||
167 | |||
168 | |||
169 | /** Base class for children of ast_container. | ||
170 | */ | ||
171 | class ast_member { | ||
172 | public: | ||
173 | virtual ~ast_member() {} | ||
174 | |||
175 | /** interface for filling the the member from a node stack. | ||
176 | @param st stack. | ||
177 | */ | ||
178 | virtual void construct(ast_stack& st) = 0; | ||
179 | |||
180 | virtual bool accept(ast_node* node) = 0; | ||
181 | |||
182 | virtual int get_type() { return ast_type<ast_member>(); } | ||
183 | }; | ||
184 | |||
185 | template<class T> | ||
186 | T* ast_cast(ast_member* member) { | ||
187 | return member && ast_type<T>() == member->get_type() ? static_cast<T*>(member) : nullptr; | ||
188 | } | ||
189 | |||
190 | class _ast_ptr : public ast_member { | ||
191 | public: | ||
192 | _ast_ptr(ast_node* node) : m_ptr(node) { | ||
193 | if (node) node->retain(); | ||
194 | } | ||
195 | |||
196 | virtual ~_ast_ptr() { | ||
197 | if (m_ptr) { | ||
198 | m_ptr->release(); | ||
199 | m_ptr = nullptr; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | ast_node* get() const { | ||
204 | return m_ptr; | ||
205 | } | ||
206 | |||
207 | template <class T> | ||
208 | T* as() const { | ||
209 | return ast_cast<T>(m_ptr); | ||
210 | } | ||
211 | |||
212 | template <class T> | ||
213 | T* to() const { | ||
214 | assert(m_ptr && m_ptr->get_type() == ast_type<T>()); | ||
215 | return static_cast<T*>(m_ptr); | ||
216 | } | ||
217 | |||
218 | template <class T> | ||
219 | bool is() const { | ||
220 | return m_ptr && m_ptr->get_type() == ast_type<T>(); | ||
221 | } | ||
222 | |||
223 | void set(ast_node* node) { | ||
224 | if (node == m_ptr) { | ||
225 | return; | ||
226 | } else if (!node) { | ||
227 | if (m_ptr) m_ptr->release(); | ||
228 | m_ptr = nullptr; | ||
229 | } else { | ||
230 | assert(accept(node)); | ||
231 | if (m_ptr) m_ptr->release(); | ||
232 | m_ptr = node; | ||
233 | node->retain(); | ||
234 | } | ||
235 | } | ||
236 | |||
237 | virtual int get_type() override { | ||
238 | return ast_type<_ast_ptr>(); | ||
239 | } | ||
240 | protected: | ||
241 | ast_node* m_ptr; | ||
242 | }; | ||
243 | |||
244 | /** pointer to an AST object. | ||
245 | It assumes ownership of the object. | ||
246 | It pops an object of the given type from the stack. | ||
247 | @tparam Required if true, the object is required. | ||
248 | @tparam T type of object to control. | ||
249 | */ | ||
250 | template <bool Required, class T> class ast_ptr : public _ast_ptr { | ||
251 | public: | ||
252 | ast_ptr(T* node = nullptr) : _ast_ptr(node) {} | ||
253 | |||
254 | ast_ptr(const ast_ptr& other) : _ast_ptr(other.get()) {} | ||
255 | |||
256 | ast_ptr& operator=(const ast_ptr& other) { | ||
257 | set(other.get()); | ||
258 | return *this; | ||
259 | } | ||
260 | |||
261 | /** gets the underlying ptr value. | ||
262 | @return the underlying ptr value. | ||
263 | */ | ||
264 | T* get() const { | ||
265 | return static_cast<T*>(m_ptr); | ||
266 | } | ||
267 | |||
268 | /** auto conversion to the underlying object ptr. | ||
269 | @return the underlying ptr value. | ||
270 | */ | ||
271 | operator T*() const { | ||
272 | return static_cast<T*>(m_ptr); | ||
273 | } | ||
274 | |||
275 | /** member access. | ||
276 | @return the underlying ptr value. | ||
277 | */ | ||
278 | T* operator->() const { | ||
279 | assert(m_ptr); | ||
280 | return static_cast<T*>(m_ptr); | ||
281 | } | ||
282 | |||
283 | /** Pops a node from the stack. | ||
284 | @param st stack. | ||
285 | @exception std::logic_error thrown if the node is not of the appropriate type; | ||
286 | thrown only if Required == true or if the stack is empty. | ||
287 | */ | ||
288 | virtual void construct(ast_stack& st) override { | ||
289 | // check the stack node | ||
290 | if (st.empty()) { | ||
291 | if (!Required) return; | ||
292 | throw std::logic_error("Invalid AST stack."); | ||
293 | } | ||
294 | ast_node* node = st.back(); | ||
295 | if (!ast_ptr::accept(node)) { | ||
296 | // if the object is not required, simply return | ||
297 | if (!Required) return; | ||
298 | // else if the object is mandatory, throw an exception | ||
299 | throw std::logic_error("Invalid AST node."); | ||
300 | } | ||
301 | st.pop_back(); | ||
302 | m_ptr = node; | ||
303 | node->retain(); | ||
304 | } | ||
305 | private: | ||
306 | virtual bool accept(ast_node* node) override { | ||
307 | return node && (std::is_same<ast_node,T>() || ast_type<T>() == node->get_type()); | ||
308 | } | ||
309 | }; | ||
310 | |||
311 | template <bool Required, class ...Args> class ast_sel : public _ast_ptr { | ||
312 | public: | ||
313 | ast_sel() : _ast_ptr(nullptr) {} | ||
314 | |||
315 | ast_sel(const ast_sel& other) : _ast_ptr(other.get()) {} | ||
316 | |||
317 | ast_sel& operator=(const ast_sel& other) { | ||
318 | set(other.get()); | ||
319 | return *this; | ||
320 | } | ||
321 | |||
322 | operator ast_node*() const { | ||
323 | return m_ptr; | ||
324 | } | ||
325 | |||
326 | ast_node* operator->() const { | ||
327 | assert(m_ptr); | ||
328 | return m_ptr; | ||
329 | } | ||
330 | |||
331 | virtual void construct(ast_stack& st) override { | ||
332 | if (st.empty()) { | ||
333 | if (!Required) return; | ||
334 | throw std::logic_error("Invalid AST stack."); | ||
335 | } | ||
336 | ast_node* node = st.back(); | ||
337 | if (!ast_sel::accept(node)) { | ||
338 | if (!Required) return; | ||
339 | throw std::logic_error("Invalid AST node."); | ||
340 | } | ||
341 | st.pop_back(); | ||
342 | m_ptr = node; | ||
343 | node->retain(); | ||
344 | } | ||
345 | private: | ||
346 | virtual bool accept(ast_node* node) override { | ||
347 | if (!node) return false; | ||
348 | using swallow = bool[]; | ||
349 | bool result = false; | ||
350 | (void)swallow{result || (result = ast_type<Args>() == node->get_type())...}; | ||
351 | return result; | ||
352 | } | ||
353 | }; | ||
354 | |||
355 | class _ast_list : public ast_member { | ||
356 | public: | ||
357 | ~_ast_list() { | ||
358 | clear(); | ||
359 | } | ||
360 | |||
361 | inline ast_node* back() const { | ||
362 | return m_objects.back(); | ||
363 | } | ||
364 | |||
365 | inline ast_node* front() const { | ||
366 | return m_objects.front(); | ||
367 | } | ||
368 | |||
369 | inline size_t size() const { | ||
370 | return m_objects.size(); | ||
371 | } | ||
372 | |||
373 | inline bool empty() const { | ||
374 | return m_objects.empty(); | ||
375 | } | ||
376 | |||
377 | void push_back(ast_node* node) { | ||
378 | assert(node && accept(node)); | ||
379 | m_objects.push_back(node); | ||
380 | node->retain(); | ||
381 | } | ||
382 | |||
383 | void push_front(ast_node* node) { | ||
384 | assert(node && accept(node)); | ||
385 | m_objects.push_front(node); | ||
386 | node->retain(); | ||
387 | } | ||
388 | |||
389 | void pop_front() { | ||
390 | auto node = m_objects.front(); | ||
391 | m_objects.pop_front(); | ||
392 | node->release(); | ||
393 | } | ||
394 | |||
395 | const node_container& objects() const { | ||
396 | return m_objects; | ||
397 | } | ||
398 | |||
399 | void clear() { | ||
400 | for(ast_node* obj : m_objects) { | ||
401 | if (obj) obj->release(); | ||
402 | } | ||
403 | m_objects.clear(); | ||
404 | } | ||
405 | |||
406 | void dup(const _ast_list& src) { | ||
407 | for(ast_node* obj : src.m_objects) { | ||
408 | m_objects.push_back(obj); | ||
409 | obj->retain(); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | virtual int get_type() override { return ast_type<_ast_list>(); } | ||
414 | protected: | ||
415 | node_container m_objects; | ||
416 | }; | ||
417 | |||
418 | /** A list of objects. | ||
419 | It pops objects of the given type from the ast stack, until no more objects can be popped. | ||
420 | It assumes ownership of objects. | ||
421 | @tparam Required if true, the object is required. | ||
422 | @tparam T type of object to control. | ||
423 | */ | ||
424 | template <bool Required, class T> class ast_list : public _ast_list { | ||
425 | public: | ||
426 | ast_list() { } | ||
427 | |||
428 | ast_list(const ast_list& other) { | ||
429 | dup(other); | ||
430 | } | ||
431 | |||
432 | ast_list& operator=(const ast_list& other) { | ||
433 | clear(); | ||
434 | dup(other); | ||
435 | return *this; | ||
436 | } | ||
437 | |||
438 | /** Pops objects of type T from the stack until no more objects can be popped. | ||
439 | @param st stack. | ||
440 | */ | ||
441 | virtual void construct(ast_stack &st) override { | ||
442 | while (!st.empty()) { | ||
443 | ast_node* node = st.back(); | ||
444 | // if the object was not not of the appropriate type, | ||
445 | // end the list parsing | ||
446 | if (!ast_list::accept(node)) { | ||
447 | if (Required && m_objects.empty()) { | ||
448 | throw std::logic_error("Invalid AST node."); | ||
449 | } | ||
450 | return; | ||
451 | } | ||
452 | st.pop_back(); | ||
453 | // insert the object in the list, in reverse order | ||
454 | m_objects.push_front(node); | ||
455 | node->retain(); | ||
456 | } | ||
457 | if (Required && m_objects.empty()) { | ||
458 | throw std::logic_error("Invalid AST stack."); | ||
459 | } | ||
460 | } | ||
461 | private: | ||
462 | virtual bool accept(ast_node* node) override { | ||
463 | return node && (std::is_same<ast_node,T>() || ast_type<T>() == node->get_type()); | ||
464 | } | ||
465 | }; | ||
466 | |||
467 | template <bool Required, class ...Args> class ast_sel_list : public _ast_list { | ||
468 | public: | ||
469 | ast_sel_list() { } | ||
470 | |||
471 | ast_sel_list(const ast_sel_list& other) { | ||
472 | dup(other); | ||
473 | } | ||
474 | |||
475 | ast_sel_list& operator=(const ast_sel_list& other) { | ||
476 | clear(); | ||
477 | dup(other); | ||
478 | return *this; | ||
479 | } | ||
480 | |||
481 | virtual void construct(ast_stack &st) override { | ||
482 | while (!st.empty()) { | ||
483 | ast_node* node = st.back(); | ||
484 | if (!ast_sel_list::accept(node)) { | ||
485 | if (Required && m_objects.empty()) { | ||
486 | throw std::logic_error("Invalid AST node."); | ||
487 | } | ||
488 | return; | ||
489 | } | ||
490 | st.pop_back(); | ||
491 | m_objects.push_front(node); | ||
492 | node->retain(); | ||
493 | } | ||
494 | if (Required && m_objects.empty()) { | ||
495 | throw std::logic_error("Invalid AST stack."); | ||
496 | } | ||
497 | } | ||
498 | private: | ||
499 | virtual bool accept(ast_node* node) override { | ||
500 | if (!node) return false; | ||
501 | using swallow = bool[]; | ||
502 | bool result = false; | ||
503 | (void)swallow{result || (result = ast_type<Args>() == node->get_type())...}; | ||
504 | return result; | ||
505 | } | ||
506 | }; | ||
507 | |||
508 | /** AST function which creates an object of type T | ||
509 | and pushes it to the node stack. | ||
510 | */ | ||
511 | template <class T> class ast { | ||
512 | public: | ||
513 | /** constructor. | ||
514 | @param r rule to attach the AST function to. | ||
515 | */ | ||
516 | ast(rule& r) { | ||
517 | r.set_parse_proc(&_parse_proc); | ||
518 | } | ||
519 | |||
520 | private: | ||
521 | //parse proc | ||
522 | static void _parse_proc(const pos& b, const pos& e, void* d) { | ||
523 | ast_stack* st = reinterpret_cast<ast_stack*>(d); | ||
524 | T* obj = new T; | ||
525 | obj->m_begin = b; | ||
526 | obj->m_end = e; | ||
527 | obj->construct(*st); | ||
528 | st->push_back(obj); | ||
529 | } | ||
530 | }; | ||
531 | |||
532 | |||
533 | /** parses the given input. | ||
534 | @param i input. | ||
535 | @param g root rule of grammar. | ||
536 | @param el list of errors. | ||
537 | @param ud user data, passed to the parse procedures. | ||
538 | @return pointer to ast node created, or null if there was an error. | ||
539 | The return object must be deleted by the caller. | ||
540 | */ | ||
541 | ast_node* _parse(input& i, rule& g, error_list& el, void* ud); | ||
542 | |||
543 | |||
544 | /** parses the given input. | ||
545 | @param i input. | ||
546 | @param g root rule of grammar. | ||
547 | @param el list of errors. | ||
548 | @param ud user data, passed to the parse procedures. | ||
549 | @return ast nodes. | ||
550 | */ | ||
551 | template <class T> ast_ptr<false, T> parse(input& i, rule& g, error_list& el, void* ud = nullptr) { | ||
552 | ast_node* node = _parse(i, g, el, ud); | ||
553 | T* ast = ast_cast<T>(node); | ||
554 | ast_ptr<false, T> ptr; | ||
555 | if (ast) { | ||
556 | ast_stack st{node}; | ||
557 | ptr.construct(st); | ||
558 | } else if (node) { | ||
559 | delete node; | ||
560 | } | ||
561 | return ptr; | ||
562 | } | ||
563 | |||
564 | |||
565 | } //namespace parserlib | ||
diff --git a/src/MoonP/moon_ast.cpp b/src/MoonP/moon_ast.cpp new file mode 100644 index 0000000..0ccd0ed --- /dev/null +++ b/src/MoonP/moon_ast.cpp | |||
@@ -0,0 +1,113 @@ | |||
1 | /* Copyright (c) 2020 Jin Li, http://www.luvfight.me | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
4 | |||
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
6 | |||
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ | ||
8 | |||
9 | #include "MoonP/moon_ast.h" | ||
10 | |||
11 | namespace MoonP { | ||
12 | |||
13 | #define AST_IMPL(type) \ | ||
14 | ast<type##_t> __##type##_t(type); | ||
15 | |||
16 | AST_IMPL(Num) | ||
17 | AST_IMPL(Name) | ||
18 | AST_IMPL(Variable) | ||
19 | AST_IMPL(LuaKeyword) | ||
20 | AST_IMPL(self) | ||
21 | AST_IMPL(self_name) | ||
22 | AST_IMPL(self_class) | ||
23 | AST_IMPL(self_class_name) | ||
24 | AST_IMPL(SelfName) | ||
25 | AST_IMPL(KeyName) | ||
26 | AST_IMPL(VarArg) | ||
27 | AST_IMPL(local_flag) | ||
28 | AST_IMPL(Seperator) | ||
29 | AST_IMPL(NameList) | ||
30 | AST_IMPL(Local) | ||
31 | AST_IMPL(colon_import_name) | ||
32 | AST_IMPL(Import) | ||
33 | AST_IMPL(ExpListLow) | ||
34 | AST_IMPL(ExpList) | ||
35 | AST_IMPL(Return) | ||
36 | AST_IMPL(With) | ||
37 | AST_IMPL(SwitchCase) | ||
38 | AST_IMPL(Switch) | ||
39 | AST_IMPL(IfCond) | ||
40 | AST_IMPL(If) | ||
41 | AST_IMPL(Unless) | ||
42 | AST_IMPL(While) | ||
43 | AST_IMPL(for_step_value) | ||
44 | AST_IMPL(For) | ||
45 | AST_IMPL(ForEach) | ||
46 | AST_IMPL(Do) | ||
47 | AST_IMPL(Comprehension) | ||
48 | AST_IMPL(comp_value) | ||
49 | AST_IMPL(TblComprehension) | ||
50 | AST_IMPL(star_exp) | ||
51 | AST_IMPL(CompForEach) | ||
52 | AST_IMPL(CompFor) | ||
53 | AST_IMPL(CompInner) | ||
54 | AST_IMPL(Assign) | ||
55 | AST_IMPL(update_op) | ||
56 | AST_IMPL(Update) | ||
57 | AST_IMPL(BinaryOperator) | ||
58 | AST_IMPL(Assignable) | ||
59 | AST_IMPL(AssignableChain) | ||
60 | AST_IMPL(exp_op_value) | ||
61 | AST_IMPL(Exp) | ||
62 | AST_IMPL(Callable) | ||
63 | AST_IMPL(ChainValue) | ||
64 | AST_IMPL(simple_table) | ||
65 | AST_IMPL(SimpleValue) | ||
66 | AST_IMPL(Value) | ||
67 | AST_IMPL(LuaStringOpen); | ||
68 | AST_IMPL(LuaStringContent); | ||
69 | AST_IMPL(LuaStringClose); | ||
70 | AST_IMPL(LuaString) | ||
71 | AST_IMPL(SingleString) | ||
72 | AST_IMPL(double_string_inner) | ||
73 | AST_IMPL(double_string_content) | ||
74 | AST_IMPL(DoubleString) | ||
75 | AST_IMPL(String) | ||
76 | AST_IMPL(Parens) | ||
77 | AST_IMPL(DotChainItem) | ||
78 | AST_IMPL(ColonChainItem) | ||
79 | AST_IMPL(default_value) | ||
80 | AST_IMPL(Slice) | ||
81 | AST_IMPL(Invoke) | ||
82 | AST_IMPL(TableLit) | ||
83 | AST_IMPL(TableBlock) | ||
84 | AST_IMPL(class_member_list) | ||
85 | AST_IMPL(ClassBlock) | ||
86 | AST_IMPL(ClassDecl) | ||
87 | AST_IMPL(export_values) | ||
88 | AST_IMPL(export_op) | ||
89 | AST_IMPL(Export) | ||
90 | AST_IMPL(variable_pair) | ||
91 | AST_IMPL(normal_pair) | ||
92 | AST_IMPL(FnArgDef) | ||
93 | AST_IMPL(FnArgDefList) | ||
94 | AST_IMPL(outer_var_shadow) | ||
95 | AST_IMPL(FnArgsDef) | ||
96 | AST_IMPL(fn_arrow) | ||
97 | AST_IMPL(FunLit) | ||
98 | AST_IMPL(NameOrDestructure) | ||
99 | AST_IMPL(AssignableNameList) | ||
100 | AST_IMPL(InvokeArgs) | ||
101 | AST_IMPL(const_value) | ||
102 | AST_IMPL(unary_exp) | ||
103 | AST_IMPL(ExpListAssign) | ||
104 | AST_IMPL(if_else_line) | ||
105 | AST_IMPL(unless_line) | ||
106 | AST_IMPL(statement_appendix) | ||
107 | AST_IMPL(BreakLoop) | ||
108 | AST_IMPL(Statement) | ||
109 | AST_IMPL(Body) | ||
110 | AST_IMPL(Block) | ||
111 | AST_IMPL(File) | ||
112 | |||
113 | } // namespace MoonP | ||
diff --git a/src/MoonP/moon_ast.h b/src/MoonP/moon_ast.h new file mode 100644 index 0000000..a614465 --- /dev/null +++ b/src/MoonP/moon_ast.h | |||
@@ -0,0 +1,587 @@ | |||
1 | /* Copyright (c) 2020 Jin Li, http://www.luvfight.me | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
4 | |||
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
6 | |||
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ | ||
8 | |||
9 | #pragma once | ||
10 | |||
11 | #include "MoonP/moon_parser.h" | ||
12 | |||
13 | namespace MoonP { | ||
14 | |||
15 | #define AST_LEAF(type, id) \ | ||
16 | extern rule type; \ | ||
17 | class type##_t : public ast_node \ | ||
18 | { \ | ||
19 | public: \ | ||
20 | virtual int get_type() override { return ast_type<type##_t>(); } \ | ||
21 | virtual size_t getId() const override { return id; } \ | ||
22 | |||
23 | #define AST_NODE(type, id) \ | ||
24 | extern rule type; \ | ||
25 | class type##_t : public ast_container \ | ||
26 | { \ | ||
27 | public: \ | ||
28 | virtual int get_type() override { return ast_type<type##_t>(); } \ | ||
29 | virtual size_t getId() const override { return id; } \ | ||
30 | |||
31 | #define AST_MEMBER(type, ...) \ | ||
32 | type##_t() { \ | ||
33 | add_members({__VA_ARGS__}); \ | ||
34 | } | ||
35 | |||
36 | #define AST_END(type) \ | ||
37 | }; | ||
38 | |||
39 | AST_LEAF(Num, "Num"_id) | ||
40 | AST_END(Num) | ||
41 | |||
42 | AST_LEAF(Name, "Name"_id) | ||
43 | AST_END(Name) | ||
44 | |||
45 | AST_NODE(Variable, "Variable"_id) | ||
46 | ast_ptr<true, Name_t> name; | ||
47 | AST_MEMBER(Variable, &name) | ||
48 | AST_END(Variable) | ||
49 | |||
50 | AST_NODE(LuaKeyword, "LuaKeyword"_id) | ||
51 | ast_ptr<true, Name_t> name; | ||
52 | AST_MEMBER(LuaKeyword, &name) | ||
53 | AST_END(LuaKeyword) | ||
54 | |||
55 | AST_LEAF(self, "self"_id) | ||
56 | AST_END(self) | ||
57 | |||
58 | AST_NODE(self_name, "self_name"_id) | ||
59 | ast_ptr<true, Name_t> name; | ||
60 | AST_MEMBER(self_name, &name) | ||
61 | AST_END(self_name) | ||
62 | |||
63 | AST_LEAF(self_class, "self_class"_id) | ||
64 | AST_END(self_class) | ||
65 | |||
66 | AST_NODE(self_class_name, "self_class_name"_id) | ||
67 | ast_ptr<true, Name_t> name; | ||
68 | AST_MEMBER(self_class_name, &name) | ||
69 | AST_END(self_class_name) | ||
70 | |||
71 | AST_NODE(SelfName, "SelfName"_id) | ||
72 | ast_sel<true, self_class_name_t, self_class_t, self_name_t, self_t> name; | ||
73 | AST_MEMBER(SelfName, &name) | ||
74 | AST_END(SelfName) | ||
75 | |||
76 | AST_NODE(KeyName, "KeyName"_id) | ||
77 | ast_sel<true, SelfName_t, Name_t> name; | ||
78 | AST_MEMBER(KeyName, &name) | ||
79 | AST_END(KeyName) | ||
80 | |||
81 | AST_LEAF(VarArg, "VarArg"_id) | ||
82 | AST_END(VarArg) | ||
83 | |||
84 | AST_LEAF(local_flag, "local_flag"_id) | ||
85 | AST_END(local_flag) | ||
86 | |||
87 | AST_LEAF(Seperator, "Seperator"_id) | ||
88 | AST_END(Seperator) | ||
89 | |||
90 | AST_NODE(NameList, "NameList"_id) | ||
91 | ast_ptr<true, Seperator_t> sep; | ||
92 | ast_list<true, Variable_t> names; | ||
93 | AST_MEMBER(NameList, &sep, &names) | ||
94 | AST_END(NameList) | ||
95 | |||
96 | AST_NODE(Local, "Local"_id) | ||
97 | ast_sel<true, local_flag_t, NameList_t> name; | ||
98 | std::list<std::string> forceDecls; | ||
99 | std::list<std::string> decls; | ||
100 | AST_MEMBER(Local, &name) | ||
101 | AST_END(Local) | ||
102 | |||
103 | AST_NODE(colon_import_name, "colon_import_name"_id) | ||
104 | ast_ptr<true, Variable_t> name; | ||
105 | AST_MEMBER(colon_import_name, &name) | ||
106 | AST_END(colon_import_name) | ||
107 | |||
108 | class Exp_t; | ||
109 | |||
110 | AST_NODE(Import, "Import"_id) | ||
111 | ast_ptr<true, Seperator_t> sep; | ||
112 | ast_sel_list<true, colon_import_name_t, Variable_t> names; | ||
113 | ast_ptr<true, Exp_t> exp; | ||
114 | AST_MEMBER(Import, &sep, &names, &exp) | ||
115 | AST_END(Import) | ||
116 | |||
117 | AST_NODE(ExpListLow, "ExpListLow"_id) | ||
118 | ast_ptr<true, Seperator_t> sep; | ||
119 | ast_list<true, Exp_t> exprs; | ||
120 | AST_MEMBER(ExpListLow, &sep, &exprs) | ||
121 | AST_END(ExpListLow) | ||
122 | |||
123 | AST_NODE(ExpList, "ExpList"_id) | ||
124 | ast_ptr<true, Seperator_t> sep; | ||
125 | ast_list<true, Exp_t> exprs; | ||
126 | AST_MEMBER(ExpList, &sep, &exprs) | ||
127 | AST_END(ExpList) | ||
128 | |||
129 | AST_NODE(Return, "Return"_id) | ||
130 | ast_ptr<false, ExpListLow_t> valueList; | ||
131 | AST_MEMBER(Return, &valueList) | ||
132 | AST_END(Return) | ||
133 | |||
134 | class Assign_t; | ||
135 | class Body_t; | ||
136 | |||
137 | AST_NODE(With, "With"_id) | ||
138 | ast_ptr<true, ExpList_t> valueList; | ||
139 | ast_ptr<false, Assign_t> assigns; | ||
140 | ast_ptr<true, Body_t> body; | ||
141 | AST_MEMBER(With, &valueList, &assigns, &body) | ||
142 | AST_END(With) | ||
143 | |||
144 | AST_NODE(SwitchCase, "SwitchCase"_id) | ||
145 | ast_ptr<true, ExpList_t> valueList; | ||
146 | ast_ptr<true, Body_t> body; | ||
147 | AST_MEMBER(SwitchCase, &valueList, &body) | ||
148 | AST_END(SwitchCase) | ||
149 | |||
150 | AST_NODE(Switch, "Switch"_id) | ||
151 | ast_ptr<true, Exp_t> target; | ||
152 | ast_ptr<true, Seperator_t> sep; | ||
153 | ast_list<true, SwitchCase_t> branches; | ||
154 | ast_ptr<false, Body_t> lastBranch; | ||
155 | AST_MEMBER(Switch, &target, &sep, &branches, &lastBranch) | ||
156 | AST_END(Switch) | ||
157 | |||
158 | AST_NODE(IfCond, "IfCond"_id) | ||
159 | ast_ptr<true, Exp_t> condition; | ||
160 | ast_ptr<false, Assign_t> assign; | ||
161 | AST_MEMBER(IfCond, &condition, &assign) | ||
162 | AST_END(IfCond) | ||
163 | |||
164 | AST_NODE(If, "If"_id) | ||
165 | ast_ptr<true, Seperator_t> sep; | ||
166 | ast_sel_list<true, IfCond_t, Body_t> nodes; | ||
167 | AST_MEMBER(If, &sep, &nodes) | ||
168 | AST_END(If) | ||
169 | |||
170 | AST_NODE(Unless, "Unless"_id) | ||
171 | ast_ptr<true, Seperator_t> sep; | ||
172 | ast_sel_list<true, IfCond_t, Body_t> nodes; | ||
173 | AST_MEMBER(Unless, &sep, &nodes) | ||
174 | AST_END(Unless) | ||
175 | |||
176 | AST_NODE(While, "While"_id) | ||
177 | ast_ptr<true, Exp_t> condition; | ||
178 | ast_ptr<true, Body_t> body; | ||
179 | AST_MEMBER(While, &condition, &body) | ||
180 | AST_END(While) | ||
181 | |||
182 | AST_NODE(for_step_value, "for_step_value"_id) | ||
183 | ast_ptr<true, Exp_t> value; | ||
184 | AST_MEMBER(for_step_value, &value) | ||
185 | AST_END(for_step_value) | ||
186 | |||
187 | AST_NODE(For, "For"_id) | ||
188 | ast_ptr<true, Variable_t> varName; | ||
189 | ast_ptr<true, Exp_t> startValue; | ||
190 | ast_ptr<true, Exp_t> stopValue; | ||
191 | ast_ptr<false, for_step_value_t> stepValue; | ||
192 | ast_ptr<true, Body_t> body; | ||
193 | AST_MEMBER(For, &varName, &startValue, &stopValue, &stepValue, &body) | ||
194 | AST_END(For) | ||
195 | |||
196 | class AssignableNameList_t; | ||
197 | class star_exp_t; | ||
198 | |||
199 | AST_NODE(ForEach, "ForEach"_id) | ||
200 | ast_ptr<true, AssignableNameList_t> nameList; | ||
201 | ast_sel<true, star_exp_t, ExpList_t> loopValue; | ||
202 | ast_ptr<true, Body_t> body; | ||
203 | AST_MEMBER(ForEach, &nameList, &loopValue, &body) | ||
204 | AST_END(ForEach) | ||
205 | |||
206 | AST_NODE(Do, "Do"_id) | ||
207 | ast_ptr<true, Body_t> body; | ||
208 | AST_MEMBER(Do, &body) | ||
209 | AST_END(Do) | ||
210 | |||
211 | class CompInner_t; | ||
212 | class Statement_t; | ||
213 | |||
214 | AST_NODE(Comprehension, "Comprehension"_id) | ||
215 | ast_sel<true, Exp_t, Statement_t> value; | ||
216 | ast_ptr<true, CompInner_t> forLoop; | ||
217 | AST_MEMBER(Comprehension, &value, &forLoop) | ||
218 | AST_END(Comprehension) | ||
219 | |||
220 | AST_NODE(comp_value, "comp_value"_id) | ||
221 | ast_ptr<true, Exp_t> value; | ||
222 | AST_MEMBER(comp_value, &value) | ||
223 | AST_END(comp_value) | ||
224 | |||
225 | AST_NODE(TblComprehension, "TblComprehension"_id) | ||
226 | ast_ptr<true, Exp_t> key; | ||
227 | ast_ptr<false, comp_value_t> value; | ||
228 | ast_ptr<true, CompInner_t> forLoop; | ||
229 | AST_MEMBER(TblComprehension, &key, &value, &forLoop) | ||
230 | AST_END(TblComprehension) | ||
231 | |||
232 | AST_NODE(star_exp, "star_exp"_id) | ||
233 | ast_ptr<true, Exp_t> value; | ||
234 | AST_MEMBER(star_exp, &value) | ||
235 | AST_END(star_exp) | ||
236 | |||
237 | AST_NODE(CompForEach, "CompForEach"_id) | ||
238 | ast_ptr<true, AssignableNameList_t> nameList; | ||
239 | ast_sel<true, star_exp_t, Exp_t> loopValue; | ||
240 | AST_MEMBER(CompForEach, &nameList, &loopValue) | ||
241 | AST_END(CompForEach) | ||
242 | |||
243 | AST_NODE(CompFor, "CompFor"_id) | ||
244 | ast_ptr<true, Variable_t> varName; | ||
245 | ast_ptr<true, Exp_t> startValue; | ||
246 | ast_ptr<true, Exp_t> stopValue; | ||
247 | ast_ptr<false, for_step_value_t> stepValue; | ||
248 | AST_MEMBER(CompFor, &varName, &startValue, &stopValue, &stepValue) | ||
249 | AST_END(CompFor) | ||
250 | |||
251 | AST_NODE(CompInner, "CompInner"_id) | ||
252 | ast_ptr<true, Seperator_t> sep; | ||
253 | ast_sel_list<true, CompFor_t, CompForEach_t, Exp_t> items; | ||
254 | AST_MEMBER(CompInner, &sep, &items) | ||
255 | AST_END(CompInner) | ||
256 | |||
257 | class TableBlock_t; | ||
258 | |||
259 | AST_NODE(Assign, "Assign"_id) | ||
260 | ast_ptr<true, Seperator_t> sep; | ||
261 | ast_sel_list<true, With_t, If_t, Switch_t, TableBlock_t, Exp_t> values; | ||
262 | AST_MEMBER(Assign, &sep, &values) | ||
263 | AST_END(Assign) | ||
264 | |||
265 | AST_LEAF(update_op, "update_op"_id) | ||
266 | AST_END(update_op) | ||
267 | |||
268 | AST_NODE(Update, "Update"_id) | ||
269 | ast_ptr<true, update_op_t> op; | ||
270 | ast_ptr<true, Exp_t> value; | ||
271 | AST_MEMBER(Update, &op, &value) | ||
272 | AST_END(Update) | ||
273 | |||
274 | AST_LEAF(BinaryOperator, "BinaryOperator"_id) | ||
275 | AST_END(BinaryOperator) | ||
276 | |||
277 | class AssignableChain_t; | ||
278 | |||
279 | AST_NODE(Assignable, "Assignable"_id) | ||
280 | ast_sel<true, AssignableChain_t, Variable_t, SelfName_t> item; | ||
281 | AST_MEMBER(Assignable, &item) | ||
282 | AST_END(Assignable) | ||
283 | |||
284 | class Value_t; | ||
285 | |||
286 | AST_NODE(exp_op_value, "exp_op_value"_id) | ||
287 | ast_ptr<true, BinaryOperator_t> op; | ||
288 | ast_ptr<true, Value_t> value; | ||
289 | AST_MEMBER(exp_op_value, &op, &value) | ||
290 | AST_END(exp_op_value) | ||
291 | |||
292 | AST_NODE(Exp, "Exp"_id) | ||
293 | ast_ptr<true, Value_t> value; | ||
294 | ast_list<false, exp_op_value_t> opValues; | ||
295 | AST_MEMBER(Exp, &value, &opValues) | ||
296 | AST_END(Exp) | ||
297 | |||
298 | class Parens_t; | ||
299 | |||
300 | AST_NODE(Callable, "Callable"_id) | ||
301 | ast_sel<true, Variable_t, SelfName_t, VarArg_t, Parens_t> item; | ||
302 | AST_MEMBER(Callable, &item) | ||
303 | AST_END(Callable) | ||
304 | |||
305 | AST_NODE(variable_pair, "variable_pair"_id) | ||
306 | ast_ptr<true, Variable_t> name; | ||
307 | AST_MEMBER(variable_pair, &name) | ||
308 | AST_END(variable_pair) | ||
309 | |||
310 | class DoubleString_t; | ||
311 | class SingleString_t; | ||
312 | |||
313 | AST_NODE(normal_pair, "normal_pair"_id) | ||
314 | ast_sel<true, KeyName_t, Exp_t, DoubleString_t, SingleString_t> key; | ||
315 | ast_sel<true, Exp_t, TableBlock_t> value; | ||
316 | AST_MEMBER(normal_pair, &key, &value) | ||
317 | AST_END(normal_pair) | ||
318 | |||
319 | AST_NODE(simple_table, "simple_table"_id) | ||
320 | ast_ptr<true, Seperator_t> sep; | ||
321 | ast_sel_list<true, variable_pair_t, normal_pair_t> pairs; | ||
322 | AST_MEMBER(simple_table, &sep, &pairs) | ||
323 | AST_END(simple_table) | ||
324 | |||
325 | class String_t; | ||
326 | class const_value_t; | ||
327 | class ClassDecl_t; | ||
328 | class unary_exp_t; | ||
329 | class TableLit_t; | ||
330 | class FunLit_t; | ||
331 | |||
332 | AST_NODE(SimpleValue, "SimpleValue"_id) | ||
333 | ast_sel<true, const_value_t, | ||
334 | If_t, Unless_t, Switch_t, With_t, ClassDecl_t, | ||
335 | ForEach_t, For_t, While_t, Do_t, unary_exp_t, | ||
336 | TblComprehension_t, TableLit_t, Comprehension_t, | ||
337 | FunLit_t, Num_t> value; | ||
338 | AST_MEMBER(SimpleValue, &value) | ||
339 | AST_END(SimpleValue) | ||
340 | |||
341 | AST_LEAF(LuaStringOpen, "LuaStringOpen"_id) | ||
342 | AST_END(LuaStringOpen) | ||
343 | |||
344 | AST_LEAF(LuaStringContent, "LuaStringContent"_id) | ||
345 | AST_END(LuaStringContent) | ||
346 | |||
347 | AST_LEAF(LuaStringClose, "LuaStringClose"_id) | ||
348 | AST_END(LuaStringClose) | ||
349 | |||
350 | AST_NODE(LuaString, "LuaString"_id) | ||
351 | ast_ptr<true, LuaStringOpen_t> open; | ||
352 | ast_ptr<true, LuaStringContent_t> content; | ||
353 | ast_ptr<true, LuaStringClose_t> close; | ||
354 | AST_MEMBER(LuaString, &open, &content, &close) | ||
355 | AST_END(LuaString) | ||
356 | |||
357 | AST_LEAF(SingleString, "SingleString"_id) | ||
358 | AST_END(SingleString) | ||
359 | |||
360 | AST_LEAF(double_string_inner, "double_string_inner"_id) | ||
361 | AST_END(double_string_inner) | ||
362 | |||
363 | AST_NODE(double_string_content, "double_string_content"_id) | ||
364 | ast_sel<true, double_string_inner_t, Exp_t> content; | ||
365 | AST_MEMBER(double_string_content, &content) | ||
366 | AST_END(double_string_content) | ||
367 | |||
368 | AST_NODE(DoubleString, "DoubleString"_id) | ||
369 | ast_ptr<true, Seperator_t> sep; | ||
370 | ast_list<false, double_string_content_t> segments; | ||
371 | AST_MEMBER(DoubleString, &sep, &segments) | ||
372 | AST_END(DoubleString) | ||
373 | |||
374 | AST_NODE(String, "String"_id) | ||
375 | ast_sel<true, DoubleString_t, SingleString_t, LuaString_t> str; | ||
376 | AST_MEMBER(String, &str) | ||
377 | AST_END(String) | ||
378 | |||
379 | AST_NODE(DotChainItem, "DotChainItem"_id) | ||
380 | ast_ptr<true, Name_t> name; | ||
381 | AST_MEMBER(DotChainItem, &name) | ||
382 | AST_END(DotChainItem) | ||
383 | |||
384 | AST_NODE(ColonChainItem, "ColonChainItem"_id) | ||
385 | ast_sel<true, LuaKeyword_t, Name_t> name; | ||
386 | bool switchToDot = false; | ||
387 | AST_MEMBER(ColonChainItem, &name) | ||
388 | AST_END(ColonChainItem) | ||
389 | |||
390 | class default_value_t; | ||
391 | |||
392 | AST_NODE(Slice, "Slice"_id) | ||
393 | ast_sel<true, Exp_t, default_value_t> startValue; | ||
394 | ast_sel<true, Exp_t, default_value_t> stopValue; | ||
395 | ast_sel<true, Exp_t, default_value_t> stepValue; | ||
396 | AST_MEMBER(Slice, &startValue, &stopValue, &stepValue) | ||
397 | AST_END(Slice) | ||
398 | |||
399 | AST_NODE(Parens, "Parens"_id) | ||
400 | ast_ptr<true, Exp_t> expr; | ||
401 | AST_MEMBER(Parens, &expr) | ||
402 | AST_END(Parens) | ||
403 | |||
404 | AST_NODE(Invoke, "Invoke"_id) | ||
405 | ast_ptr<true, Seperator_t> sep; | ||
406 | ast_sel_list<false, Exp_t, SingleString_t, DoubleString_t, LuaString_t> args; | ||
407 | AST_MEMBER(Invoke, &sep, &args) | ||
408 | AST_END(Invoke) | ||
409 | |||
410 | class InvokeArgs_t; | ||
411 | |||
412 | AST_NODE(ChainValue, "ChainValue"_id) | ||
413 | ast_ptr<true, Seperator_t> sep; | ||
414 | ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t> items; | ||
415 | AST_MEMBER(ChainValue, &sep, &items) | ||
416 | AST_END(ChainValue) | ||
417 | |||
418 | AST_NODE(AssignableChain, "AssignableChain"_id) | ||
419 | ast_ptr<true, Seperator_t> sep; | ||
420 | ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Exp_t, String_t> items; | ||
421 | AST_MEMBER(AssignableChain, &sep, &items) | ||
422 | AST_END(AssignableChain) | ||
423 | |||
424 | AST_NODE(Value, "Value"_id) | ||
425 | ast_sel<true, SimpleValue_t, simple_table_t, ChainValue_t, String_t> item; | ||
426 | AST_MEMBER(Value, &item) | ||
427 | AST_END(Value) | ||
428 | |||
429 | AST_LEAF(default_value, "default_value"_id) | ||
430 | AST_END(default_value) | ||
431 | |||
432 | AST_NODE(TableLit, "TableLit"_id) | ||
433 | ast_ptr<true, Seperator_t> sep; | ||
434 | ast_sel_list<false, variable_pair_t, normal_pair_t, Exp_t> values; | ||
435 | AST_MEMBER(TableLit, &sep, &values) | ||
436 | AST_END(TableLit) | ||
437 | |||
438 | AST_NODE(TableBlock, "TableBlock"_id) | ||
439 | ast_ptr<true, Seperator_t> sep; | ||
440 | ast_sel_list<false, variable_pair_t, normal_pair_t> values; | ||
441 | AST_MEMBER(TableBlock, &sep, &values) | ||
442 | AST_END(TableBlock) | ||
443 | |||
444 | AST_NODE(class_member_list, "class_member_list"_id) | ||
445 | ast_ptr<true, Seperator_t> sep; | ||
446 | ast_sel_list<true, variable_pair_t, normal_pair_t> values; | ||
447 | AST_MEMBER(class_member_list, &sep, &values) | ||
448 | AST_END(class_member_list) | ||
449 | |||
450 | AST_NODE(ClassBlock, "ClassBlock"_id) | ||
451 | ast_ptr<true, Seperator_t> sep; | ||
452 | ast_sel_list<true, class_member_list_t, Statement_t> contents; | ||
453 | AST_MEMBER(ClassBlock, &sep, &contents) | ||
454 | AST_END(ClassBlock) | ||
455 | |||
456 | AST_NODE(ClassDecl, "ClassDecl"_id) | ||
457 | ast_ptr<false, Assignable_t> name; | ||
458 | ast_ptr<false, Exp_t> extend; | ||
459 | ast_ptr<false, ClassBlock_t> body; | ||
460 | AST_MEMBER(ClassDecl, &name, &extend, &body) | ||
461 | AST_END(ClassDecl) | ||
462 | |||
463 | AST_NODE(export_values, "export_values"_id) | ||
464 | ast_ptr<true, NameList_t> nameList; | ||
465 | ast_ptr<false, ExpListLow_t> valueList; | ||
466 | AST_MEMBER(export_values, &nameList, &valueList) | ||
467 | AST_END(export_values) | ||
468 | |||
469 | AST_LEAF(export_op, "export_op"_id) | ||
470 | AST_END(export_op) | ||
471 | |||
472 | AST_NODE(Export, "Export"_id) | ||
473 | ast_sel<true, ClassDecl_t, export_op_t, export_values_t> item; | ||
474 | AST_MEMBER(Export, &item) | ||
475 | AST_END(Export) | ||
476 | |||
477 | AST_NODE(FnArgDef, "FnArgDef"_id) | ||
478 | ast_sel<true, Variable_t, SelfName_t> name; | ||
479 | ast_ptr<false, Exp_t> defaultValue; | ||
480 | AST_MEMBER(FnArgDef, &name, &defaultValue) | ||
481 | AST_END(FnArgDef) | ||
482 | |||
483 | AST_NODE(FnArgDefList, "FnArgDefList"_id) | ||
484 | ast_ptr<true, Seperator_t> sep; | ||
485 | ast_list<false, FnArgDef_t> definitions; | ||
486 | ast_ptr<false, VarArg_t> varArg; | ||
487 | AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg) | ||
488 | AST_END(FnArgDefList) | ||
489 | |||
490 | AST_NODE(outer_var_shadow, "outer_var_shadow"_id) | ||
491 | ast_ptr<false, NameList_t> varList; | ||
492 | AST_MEMBER(outer_var_shadow, &varList) | ||
493 | AST_END(outer_var_shadow) | ||
494 | |||
495 | AST_NODE(FnArgsDef, "FnArgsDef"_id) | ||
496 | ast_ptr<false, FnArgDefList_t> defList; | ||
497 | ast_ptr<false, outer_var_shadow_t> shadowOption; | ||
498 | AST_MEMBER(FnArgsDef, &defList, &shadowOption) | ||
499 | AST_END(FnArgsDef) | ||
500 | |||
501 | AST_LEAF(fn_arrow, "fn_arrow"_id) | ||
502 | AST_END(fn_arrow) | ||
503 | |||
504 | AST_NODE(FunLit, "FunLit"_id) | ||
505 | ast_ptr<false, FnArgsDef_t> argsDef; | ||
506 | ast_ptr<true, fn_arrow_t> arrow; | ||
507 | ast_ptr<false, Body_t> body; | ||
508 | AST_MEMBER(FunLit, &argsDef, &arrow, &body) | ||
509 | AST_END(FunLit) | ||
510 | |||
511 | AST_NODE(NameOrDestructure, "NameOrDestructure"_id) | ||
512 | ast_sel<true, Variable_t, TableLit_t> item; | ||
513 | AST_MEMBER(NameOrDestructure, &item) | ||
514 | AST_END(NameOrDestructure) | ||
515 | |||
516 | AST_NODE(AssignableNameList, "AssignableNameList"_id) | ||
517 | ast_ptr<true, Seperator_t> sep; | ||
518 | ast_list<true, NameOrDestructure_t> items; | ||
519 | AST_MEMBER(AssignableNameList, &sep, &items) | ||
520 | AST_END(AssignableNameList) | ||
521 | |||
522 | AST_NODE(InvokeArgs, "InvokeArgs"_id) | ||
523 | ast_ptr<true, Seperator_t> sep; | ||
524 | ast_sel_list<true, Exp_t, TableBlock_t> args; | ||
525 | AST_MEMBER(InvokeArgs, &sep, &args) | ||
526 | AST_END(InvokeArgs) | ||
527 | |||
528 | AST_LEAF(const_value, "const_value"_id) | ||
529 | AST_END(const_value) | ||
530 | |||
531 | AST_NODE(unary_exp, "unary_exp"_id) | ||
532 | ast_ptr<true, Exp_t> item; | ||
533 | AST_MEMBER(unary_exp, &item) | ||
534 | AST_END(unary_exp) | ||
535 | |||
536 | AST_NODE(ExpListAssign, "ExpListAssign"_id) | ||
537 | ast_ptr<true, ExpList_t> expList; | ||
538 | ast_sel<false, Update_t, Assign_t> action; | ||
539 | AST_MEMBER(ExpListAssign, &expList, &action) | ||
540 | AST_END(ExpListAssign) | ||
541 | |||
542 | AST_NODE(if_else_line, "if_else_line"_id) | ||
543 | ast_ptr<true, Exp_t> condition; | ||
544 | ast_sel<false, Exp_t, default_value_t> elseExpr; | ||
545 | AST_MEMBER(if_else_line, &condition, &elseExpr) | ||
546 | AST_END(if_else_line) | ||
547 | |||
548 | AST_NODE(unless_line, "unless_line"_id) | ||
549 | ast_ptr<true, Exp_t> condition; | ||
550 | AST_MEMBER(unless_line, &condition) | ||
551 | AST_END(unless_line) | ||
552 | |||
553 | AST_NODE(statement_appendix, "statement_appendix"_id) | ||
554 | ast_sel<true, if_else_line_t, unless_line_t, CompInner_t> item; | ||
555 | AST_MEMBER(statement_appendix, &item) | ||
556 | AST_END(statement_appendix) | ||
557 | |||
558 | AST_LEAF(BreakLoop, "BreakLoop"_id) | ||
559 | AST_END(BreakLoop) | ||
560 | |||
561 | AST_NODE(Statement, "Statement"_id) | ||
562 | ast_sel<true, Import_t, While_t, For_t, ForEach_t, | ||
563 | Return_t, Local_t, Export_t, BreakLoop_t, | ||
564 | ExpListAssign_t> content; | ||
565 | ast_ptr<false, statement_appendix_t> appendix; | ||
566 | AST_MEMBER(Statement, &content, &appendix) | ||
567 | AST_END(Statement) | ||
568 | |||
569 | class Block_t; | ||
570 | |||
571 | AST_NODE(Body, "Body"_id) | ||
572 | ast_sel<true, Block_t, Statement_t> content; | ||
573 | AST_MEMBER(Body, &content) | ||
574 | AST_END(Body) | ||
575 | |||
576 | AST_NODE(Block, "Block"_id) | ||
577 | ast_ptr<true, Seperator_t> sep; | ||
578 | ast_list<false, Statement_t> statements; | ||
579 | AST_MEMBER(Block, &sep, &statements) | ||
580 | AST_END(Block) | ||
581 | |||
582 | AST_NODE(File, "File"_id) | ||
583 | ast_ptr<true, Block_t> block; | ||
584 | AST_MEMBER(File, &block) | ||
585 | AST_END(File) | ||
586 | |||
587 | } // namespace MoonP | ||
diff --git a/src/MoonP/moon_compiler.cpp b/src/MoonP/moon_compiler.cpp new file mode 100644 index 0000000..f9a86a6 --- /dev/null +++ b/src/MoonP/moon_compiler.cpp | |||
@@ -0,0 +1,3865 @@ | |||
1 | /* Copyright (c) 2020 Jin Li, http://www.luvfight.me | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
4 | |||
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
6 | |||
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ | ||
8 | |||
9 | #include <string> | ||
10 | #include <unordered_set> | ||
11 | #include <unordered_map> | ||
12 | #include <stack> | ||
13 | #include <vector> | ||
14 | #include <numeric> | ||
15 | #include <memory> | ||
16 | #include <sstream> | ||
17 | #include <string_view> | ||
18 | using namespace std::string_view_literals; | ||
19 | #include "MoonP/parser.hpp" | ||
20 | #include "MoonP/moon_ast.h" | ||
21 | #include "MoonP/moon_compiler.h" | ||
22 | |||
23 | namespace MoonP { | ||
24 | |||
25 | #define BLOCK_START do { | ||
26 | #define BLOCK_END } while (false); | ||
27 | #define BREAK_IF(cond) if (cond) break | ||
28 | |||
29 | typedef std::list<std::string> str_list; | ||
30 | |||
31 | inline std::string s(std::string_view sv) { | ||
32 | return std::string(sv); | ||
33 | } | ||
34 | |||
35 | const char* moonScriptVersion() { | ||
36 | return "0.5.0"; | ||
37 | } | ||
38 | |||
39 | class MoonCompliler { | ||
40 | public: | ||
41 | std::pair<std::string,std::string> complile(const std::string& codes, const MoonConfig& config) { | ||
42 | _config = config; | ||
43 | try { | ||
44 | _input = _converter.from_bytes(codes); | ||
45 | } catch (const std::range_error&) { | ||
46 | return {Empty, "Invalid text encoding."}; | ||
47 | } | ||
48 | error_list el; | ||
49 | State st; | ||
50 | ast_ptr<false, File_t> root; | ||
51 | try { | ||
52 | root = parse<File_t>(_input, File, el, &st); | ||
53 | } catch (const std::logic_error& error) { | ||
54 | clear(); | ||
55 | return {Empty, error.what()}; | ||
56 | } | ||
57 | if (root) { | ||
58 | try { | ||
59 | str_list out; | ||
60 | pushScope(); | ||
61 | transformBlock(root->block, out, config.implicitReturnRoot); | ||
62 | popScope(); | ||
63 | return {std::move(out.back()), Empty}; | ||
64 | } catch (const std::logic_error& error) { | ||
65 | clear(); | ||
66 | return {Empty, error.what()}; | ||
67 | } | ||
68 | } else { | ||
69 | clearBuf(); | ||
70 | for (error_list::iterator it = el.begin(); it != el.end(); ++it) { | ||
71 | const error& err = *it; | ||
72 | _buf << debugInfo("Syntax error."sv, &err); | ||
73 | } | ||
74 | std::pair<std::string,std::string> result{Empty, clearBuf()}; | ||
75 | clear(); | ||
76 | return result; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | const std::unordered_map<std::string,std::pair<int,int>>& getGlobals() const { | ||
81 | return _globals; | ||
82 | } | ||
83 | |||
84 | void clear() { | ||
85 | _indentOffset = 0; | ||
86 | _scopes.clear(); | ||
87 | _codeCache.clear(); | ||
88 | std::stack<std::string> emptyWith; | ||
89 | _withVars.swap(emptyWith); | ||
90 | std::stack<std::string> emptyContinue; | ||
91 | _continueVars.swap(emptyContinue); | ||
92 | _buf.str(""); | ||
93 | _buf.clear(); | ||
94 | _joinBuf.str(""); | ||
95 | _joinBuf.clear(); | ||
96 | _globals.clear(); | ||
97 | _input.clear(); | ||
98 | } | ||
99 | private: | ||
100 | MoonConfig _config; | ||
101 | int _indentOffset = 0; | ||
102 | Converter _converter; | ||
103 | input _input; | ||
104 | std::list<input> _codeCache; | ||
105 | std::stack<std::string> _withVars; | ||
106 | std::stack<std::string> _continueVars; | ||
107 | std::unordered_map<std::string,std::pair<int,int>> _globals; | ||
108 | std::ostringstream _buf; | ||
109 | std::ostringstream _joinBuf; | ||
110 | std::string _newLine = "\n"; | ||
111 | enum class LocalMode { | ||
112 | None = 0, | ||
113 | Capital = 1, | ||
114 | Any = 2 | ||
115 | }; | ||
116 | enum class ExportMode { | ||
117 | None = 0, | ||
118 | Capital = 1, | ||
119 | Any = 2 | ||
120 | }; | ||
121 | struct Scope { | ||
122 | ExportMode mode = ExportMode::None; | ||
123 | std::unique_ptr<std::unordered_set<std::string>> vars; | ||
124 | std::unique_ptr<std::unordered_set<std::string>> allows; | ||
125 | std::unique_ptr<std::unordered_set<std::string>> exports; | ||
126 | }; | ||
127 | std::list<Scope> _scopes; | ||
128 | static const std::string Empty; | ||
129 | |||
130 | enum class MemType { | ||
131 | Builtin, | ||
132 | Common, | ||
133 | Property | ||
134 | }; | ||
135 | |||
136 | struct ClassMember { | ||
137 | std::string item; | ||
138 | MemType type; | ||
139 | ast_node* node; | ||
140 | }; | ||
141 | |||
142 | struct DestructItem { | ||
143 | bool isVariable = false; | ||
144 | std::string name; | ||
145 | std::string structure; | ||
146 | }; | ||
147 | |||
148 | struct Destructure { | ||
149 | std::string value; | ||
150 | std::list<DestructItem> items; | ||
151 | }; | ||
152 | |||
153 | enum class ExpUsage { | ||
154 | Return, | ||
155 | Assignment, | ||
156 | Common, | ||
157 | Closure | ||
158 | }; | ||
159 | |||
160 | void pushScope() { | ||
161 | _scopes.emplace_back(); | ||
162 | _scopes.back().vars = std::make_unique<std::unordered_set<std::string>>(); | ||
163 | } | ||
164 | |||
165 | void popScope() { | ||
166 | _scopes.pop_back(); | ||
167 | } | ||
168 | |||
169 | bool isDefined(const std::string& name) { | ||
170 | bool isDefined = false; | ||
171 | int mode = int(std::isupper(name[0]) ? ExportMode::Capital : ExportMode::Any); | ||
172 | const auto& current = _scopes.back(); | ||
173 | if (int(current.mode) >= mode) { | ||
174 | if (current.exports) { | ||
175 | if (current.exports->find(name) != current.exports->end()) { | ||
176 | isDefined = true; | ||
177 | current.vars->insert(name); | ||
178 | } | ||
179 | } else { | ||
180 | isDefined = true; | ||
181 | current.vars->insert(name); | ||
182 | } | ||
183 | } | ||
184 | decltype(_scopes.back().allows.get()) allows = nullptr; | ||
185 | for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { | ||
186 | if (it->allows) allows = it->allows.get(); | ||
187 | } | ||
188 | bool checkShadowScopeOnly = false; | ||
189 | if (allows) { | ||
190 | checkShadowScopeOnly = allows->find(name) == allows->end(); | ||
191 | } | ||
192 | for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { | ||
193 | auto vars = it->vars.get(); | ||
194 | if (vars->find(name) != vars->end()) { | ||
195 | isDefined = true; | ||
196 | break; | ||
197 | } | ||
198 | if (checkShadowScopeOnly && it->allows) break; | ||
199 | } | ||
200 | return isDefined; | ||
201 | } | ||
202 | |||
203 | bool isSolidDefined(const std::string& name) { | ||
204 | bool isDefined = false; | ||
205 | for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { | ||
206 | auto vars = it->vars.get(); | ||
207 | if (vars->find(name) != vars->end()) { | ||
208 | isDefined = true; | ||
209 | break; | ||
210 | } | ||
211 | } | ||
212 | return isDefined; | ||
213 | } | ||
214 | |||
215 | void markVarShadowed() { | ||
216 | auto& scope = _scopes.back(); | ||
217 | scope.allows = std::make_unique<std::unordered_set<std::string>>(); | ||
218 | } | ||
219 | |||
220 | void markVarExported(ExportMode mode, bool specified) { | ||
221 | auto& scope = _scopes.back(); | ||
222 | scope.mode = mode; | ||
223 | if (specified && !scope.exports) { | ||
224 | scope.exports = std::make_unique<std::unordered_set<std::string>>(); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | void addExportedVar(const std::string& name) { | ||
229 | auto& scope = _scopes.back(); | ||
230 | scope.exports->insert(name); | ||
231 | } | ||
232 | |||
233 | void addToAllowList(const std::string& name) { | ||
234 | auto& scope = _scopes.back(); | ||
235 | scope.allows->insert(name); | ||
236 | } | ||
237 | |||
238 | void forceAddToScope(const std::string& name) { | ||
239 | auto& scope = _scopes.back(); | ||
240 | scope.vars->insert(name); | ||
241 | } | ||
242 | |||
243 | Scope& currentScope() { | ||
244 | return _scopes.back(); | ||
245 | } | ||
246 | |||
247 | bool addToScope(const std::string& name) { | ||
248 | bool defined = isDefined(name); | ||
249 | if (!defined) { | ||
250 | auto& scope = currentScope(); | ||
251 | scope.vars->insert(name); | ||
252 | } | ||
253 | return !defined; | ||
254 | } | ||
255 | |||
256 | std::string getUnusedName(std::string_view name) { | ||
257 | int index = 0; | ||
258 | std::string newName; | ||
259 | do { | ||
260 | newName = s(name) + std::to_string(index); | ||
261 | index++; | ||
262 | } while (isSolidDefined(newName)); | ||
263 | return newName; | ||
264 | } | ||
265 | |||
266 | const std::string nll(ast_node* node) { | ||
267 | if (_config.reserveLineNumber) { | ||
268 | return s(" -- "sv) + std::to_string(node->m_begin.m_line) + _newLine; | ||
269 | } else { | ||
270 | return _newLine; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | const std::string nlr(ast_node* node) { | ||
275 | if (_config.reserveLineNumber) { | ||
276 | return s(" -- "sv) + std::to_string(node->m_end.m_line) + _newLine; | ||
277 | } else { | ||
278 | return _newLine; | ||
279 | } | ||
280 | } | ||
281 | |||
282 | void incIndentOffset() { | ||
283 | _indentOffset++; | ||
284 | } | ||
285 | |||
286 | void decIndentOffset() { | ||
287 | _indentOffset--; | ||
288 | } | ||
289 | |||
290 | std::string indent() { | ||
291 | return _config.spaceOverTab ? std::string((_scopes.size() - 1 + _indentOffset) * 2, ' ') : std::string(_scopes.size() - 1 + _indentOffset, '\t'); | ||
292 | } | ||
293 | |||
294 | std::string indent(int offset) { | ||
295 | return _config.spaceOverTab ? std::string((_scopes.size() - 1 + _indentOffset + offset) * 2, ' ') : std::string(_scopes.size() - 1 + _indentOffset + offset, '\t'); | ||
296 | } | ||
297 | |||
298 | std::string clearBuf() { | ||
299 | std::string str = _buf.str(); | ||
300 | _buf.str(""); | ||
301 | _buf.clear(); | ||
302 | return str; | ||
303 | } | ||
304 | |||
305 | std::string join(const str_list& items) { | ||
306 | if (items.empty()) return Empty; | ||
307 | else if (items.size() == 1) return items.front(); | ||
308 | for (const auto& item : items) { | ||
309 | _joinBuf << item; | ||
310 | } | ||
311 | auto result = _joinBuf.str(); | ||
312 | _joinBuf.str(""); | ||
313 | _joinBuf.clear(); | ||
314 | return result; | ||
315 | } | ||
316 | |||
317 | std::string join(const str_list& items, std::string_view sep) { | ||
318 | if (items.empty()) return Empty; | ||
319 | else if (items.size() == 1) return items.front(); | ||
320 | std::string sepStr = s(sep); | ||
321 | auto begin = ++items.begin(); | ||
322 | _joinBuf << items.front(); | ||
323 | for (auto it = begin; it != items.end(); ++it) { | ||
324 | _joinBuf << sepStr << *it; | ||
325 | } | ||
326 | auto result = _joinBuf.str(); | ||
327 | _joinBuf.str(""); | ||
328 | _joinBuf.clear(); | ||
329 | return result; | ||
330 | } | ||
331 | |||
332 | std::string toString(ast_node* node) { | ||
333 | return _converter.to_bytes(std::wstring(node->m_begin.m_it, node->m_end.m_it)); | ||
334 | } | ||
335 | |||
336 | std::string toString(input::iterator begin, input::iterator end) { | ||
337 | return _converter.to_bytes(std::wstring(begin, end)); | ||
338 | } | ||
339 | |||
340 | Value_t* singleValueFrom(ast_node* item) { | ||
341 | Exp_t* exp = nullptr; | ||
342 | switch (item->getId()) { | ||
343 | case "Exp"_id: | ||
344 | exp = static_cast<Exp_t*>(item); | ||
345 | break; | ||
346 | case "ExpList"_id: { | ||
347 | auto expList = static_cast<ExpList_t*>(item); | ||
348 | if (expList->exprs.size() == 1) { | ||
349 | exp = static_cast<Exp_t*>(expList->exprs.front()); | ||
350 | } | ||
351 | break; | ||
352 | } | ||
353 | case "ExpListLow"_id: { | ||
354 | auto expList = static_cast<ExpListLow_t*>(item); | ||
355 | if (expList->exprs.size() == 1) { | ||
356 | exp = static_cast<Exp_t*>(expList->exprs.front()); | ||
357 | } | ||
358 | break; | ||
359 | } | ||
360 | } | ||
361 | if (!exp) return nullptr; | ||
362 | if (exp->opValues.empty()) { | ||
363 | return exp->value.get(); | ||
364 | } | ||
365 | return nullptr; | ||
366 | } | ||
367 | |||
368 | SimpleValue_t* simpleSingleValueFrom(ast_node* expList) { | ||
369 | auto value = singleValueFrom(expList); | ||
370 | if (value && value->item.is<SimpleValue_t>()) { | ||
371 | return static_cast<SimpleValue_t*>(value->item.get()); | ||
372 | } | ||
373 | return nullptr; | ||
374 | } | ||
375 | |||
376 | Value_t* firstValueFrom(ast_node* item) { | ||
377 | Exp_t* exp = nullptr; | ||
378 | if (auto expList = ast_cast<ExpList_t>(item)) { | ||
379 | if (!expList->exprs.empty()) { | ||
380 | exp = static_cast<Exp_t*>(expList->exprs.front()); | ||
381 | } | ||
382 | } else { | ||
383 | exp = ast_cast<Exp_t>(item); | ||
384 | } | ||
385 | return exp->value.get(); | ||
386 | } | ||
387 | |||
388 | Statement_t* lastStatementFrom(Body_t* body) { | ||
389 | if (auto stmt = body->content.as<Statement_t>()) { | ||
390 | return stmt; | ||
391 | } else { | ||
392 | auto node = body->content.to<Block_t>()->statements.objects().back(); | ||
393 | return static_cast<Statement_t*>(node); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | Statement_t* lastStatementFrom(Block_t* block) { | ||
398 | auto node = block->statements.objects().back(); | ||
399 | return static_cast<Statement_t*>(node); | ||
400 | } | ||
401 | |||
402 | template <class T> | ||
403 | ast_ptr<false, T> toAst(std::string_view codes, rule& r, ast_node* parent) { | ||
404 | _codeCache.push_back(_converter.from_bytes(s(codes))); | ||
405 | error_list el; | ||
406 | State st; | ||
407 | auto ptr = parse<T>(_codeCache.back(), r, el, &st); | ||
408 | ptr->traverse([&](ast_node* node) { | ||
409 | node->m_begin.m_line = parent->m_begin.m_line; | ||
410 | node->m_end.m_line = parent->m_begin.m_line; | ||
411 | return traversal::Continue; | ||
412 | }); | ||
413 | return ptr; | ||
414 | } | ||
415 | |||
416 | bool matchAst(rule& r, std::string_view codes) { | ||
417 | error_list el; | ||
418 | State st; | ||
419 | input i = _converter.from_bytes(s(codes)); | ||
420 | auto rEnd = rule(r >> eof()); | ||
421 | ast_ptr<false, ast_node> result(_parse(i, rEnd, el, &st)); | ||
422 | return result; | ||
423 | } | ||
424 | |||
425 | bool isChainValueCall(ChainValue_t* chainValue) { | ||
426 | return ast_is<InvokeArgs_t, Invoke_t>(chainValue->items.back()); | ||
427 | } | ||
428 | |||
429 | std::string singleVariableFrom(ast_node* expList) { | ||
430 | if (!ast_is<Exp_t, ExpList_t>(expList)) return Empty; | ||
431 | BLOCK_START | ||
432 | auto value = singleValueFrom(expList); | ||
433 | BREAK_IF(!value); | ||
434 | auto chainValue = value->getByPath<ChainValue_t>(); | ||
435 | BREAK_IF(!chainValue); | ||
436 | BREAK_IF(chainValue->items.size() != 1); | ||
437 | auto callable = ast_cast<Callable_t>(chainValue->items.front()); | ||
438 | BREAK_IF(!callable || !callable->item.is<Variable_t>()); | ||
439 | str_list tmp; | ||
440 | transformCallable(callable, tmp, false); | ||
441 | return tmp.back(); | ||
442 | BLOCK_END | ||
443 | return Empty; | ||
444 | } | ||
445 | |||
446 | bool isColonChain(ChainValue_t* chainValue) { | ||
447 | return ast_is<ColonChainItem_t>(chainValue->items.back()); | ||
448 | } | ||
449 | |||
450 | bool hasKeywordColonChainItem(ChainValue_t* chainValue) { | ||
451 | const auto& chainList = chainValue->items.objects(); | ||
452 | for (auto it = chainList.begin(); it != chainList.end(); ++it) { | ||
453 | if (auto colonItem = ast_cast<ColonChainItem_t>(*it)) { | ||
454 | if (colonItem->name.is<LuaKeyword_t>()) { | ||
455 | return true; | ||
456 | } | ||
457 | } | ||
458 | } | ||
459 | return false; | ||
460 | } | ||
461 | |||
462 | bool isAssignable(const node_container& chainItems) { | ||
463 | if (chainItems.size() == 1) { | ||
464 | auto firstItem = chainItems.back(); | ||
465 | if (auto callable = ast_cast<Callable_t>(firstItem)) { | ||
466 | switch (callable->item->getId()) { | ||
467 | case "Variable"_id: | ||
468 | case "SelfName"_id: | ||
469 | return true; | ||
470 | } | ||
471 | } else if (firstItem->getId() == "DotChainItem"_id) { | ||
472 | return true; | ||
473 | } | ||
474 | } else { | ||
475 | auto lastItem = chainItems.back(); | ||
476 | switch (lastItem->getId()) { | ||
477 | case "DotChainItem"_id: | ||
478 | case "Exp"_id: | ||
479 | return true; | ||
480 | } | ||
481 | } | ||
482 | return false; | ||
483 | } | ||
484 | |||
485 | bool isAssignable(Exp_t* exp) { | ||
486 | if (auto value = singleValueFrom(exp)) { | ||
487 | auto item = value->item.get(); | ||
488 | switch (item->getId()) { | ||
489 | case "simple_table"_id: | ||
490 | return true; | ||
491 | case "SimpleValue"_id: { | ||
492 | auto simpleValue = static_cast<SimpleValue_t*>(item); | ||
493 | if (simpleValue->value.is<TableLit_t>()) { | ||
494 | return true; | ||
495 | } | ||
496 | return false; | ||
497 | } | ||
498 | case "ChainValue"_id: { | ||
499 | auto chainValue = static_cast<ChainValue_t*>(item); | ||
500 | return isAssignable(chainValue->items.objects()); | ||
501 | } | ||
502 | } | ||
503 | } | ||
504 | return false; | ||
505 | } | ||
506 | |||
507 | bool isAssignable(Assignable_t* assignable) { | ||
508 | if (auto assignableChain = ast_cast<AssignableChain_t>(assignable->item)) { | ||
509 | return isAssignable(assignableChain->items.objects()); | ||
510 | } | ||
511 | return true; | ||
512 | } | ||
513 | |||
514 | void checkAssignable(ExpList_t* expList) { | ||
515 | for (auto exp_ : expList->exprs.objects()) { | ||
516 | Exp_t* exp = static_cast<Exp_t*>(exp_); | ||
517 | if (!isAssignable(exp)) { | ||
518 | throw std::logic_error(debugInfo("Left hand expression is not assignable."sv, exp)); | ||
519 | } | ||
520 | } | ||
521 | } | ||
522 | |||
523 | std::string debugInfo(std::string_view msg, const input_range* loc) { | ||
524 | const int ASCII = 255; | ||
525 | int length = loc->m_begin.m_line; | ||
526 | auto begin = _input.begin(); | ||
527 | auto end = _input.end(); | ||
528 | int count = 0; | ||
529 | for (auto it = _input.begin(); it != _input.end(); ++it) { | ||
530 | if (*it == '\n') { | ||
531 | if (count + 1 == length) { | ||
532 | end = it; | ||
533 | break; | ||
534 | } else { | ||
535 | begin = it + 1; | ||
536 | } | ||
537 | count++; | ||
538 | } | ||
539 | } | ||
540 | auto line = _converter.to_bytes(std::wstring(begin, end)); | ||
541 | int oldCol = loc->m_begin.m_col; | ||
542 | int col = loc->m_begin.m_col - 1; | ||
543 | auto it = begin; | ||
544 | for (int i = 0; i < oldCol; ++i) { | ||
545 | if (*it > ASCII) { | ||
546 | ++col; | ||
547 | } | ||
548 | ++it; | ||
549 | } | ||
550 | replace(line, "\t"sv, " "sv); | ||
551 | std::ostringstream buf; | ||
552 | buf << loc->m_begin.m_line << ": "sv << msg << | ||
553 | '\n' << line << '\n' << std::string(col, ' ') << "^"sv; | ||
554 | return buf.str(); | ||
555 | } | ||
556 | |||
557 | void transformStatement(Statement_t* statement, str_list& out) { | ||
558 | auto x = statement; | ||
559 | if (statement->appendix) { | ||
560 | if (auto assignment = assignmentFrom(statement)) { | ||
561 | auto preDefine = getPredefine(transformAssignDefs(assignment->expList)); | ||
562 | if (!preDefine.empty()) out.push_back(preDefine + nll(statement)); | ||
563 | } | ||
564 | auto appendix = statement->appendix.get(); | ||
565 | switch (appendix->item->getId()) { | ||
566 | case "if_else_line"_id: { | ||
567 | auto if_else_line = appendix->item.to<if_else_line_t>(); | ||
568 | auto ifNode = x->new_ptr<If_t>(); | ||
569 | |||
570 | auto ifCond = x->new_ptr<IfCond_t>(); | ||
571 | ifCond->condition.set(if_else_line->condition); | ||
572 | ifNode->nodes.push_back(ifCond); | ||
573 | |||
574 | auto stmt = x->new_ptr<Statement_t>(); | ||
575 | stmt->content.set(statement->content); | ||
576 | auto body = x->new_ptr<Body_t>(); | ||
577 | body->content.set(stmt); | ||
578 | ifNode->nodes.push_back(body); | ||
579 | |||
580 | if (!ast_is<default_value_t>(if_else_line->elseExpr)) { | ||
581 | auto expList = x->new_ptr<ExpList_t>(); | ||
582 | expList->exprs.push_back(if_else_line->elseExpr); | ||
583 | auto expListAssign = x->new_ptr<ExpListAssign_t>(); | ||
584 | expListAssign->expList.set(expList); | ||
585 | auto stmt = x->new_ptr<Statement_t>(); | ||
586 | stmt->content.set(expListAssign); | ||
587 | auto body = x->new_ptr<Body_t>(); | ||
588 | body->content.set(stmt); | ||
589 | ifNode->nodes.push_back(body); | ||
590 | } | ||
591 | |||
592 | statement->appendix.set(nullptr); | ||
593 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
594 | simpleValue->value.set(ifNode); | ||
595 | auto value = x->new_ptr<Value_t>(); | ||
596 | value->item.set(simpleValue); | ||
597 | auto exp = x->new_ptr<Exp_t>(); | ||
598 | exp->value.set(value); | ||
599 | auto expList = x->new_ptr<ExpList_t>(); | ||
600 | expList->exprs.push_back(exp); | ||
601 | auto expListAssign = x->new_ptr<ExpListAssign_t>(); | ||
602 | expListAssign->expList.set(expList); | ||
603 | statement->content.set(expListAssign); | ||
604 | break; | ||
605 | } | ||
606 | case "unless_line"_id: { | ||
607 | auto unless_line = appendix->item.to<unless_line_t>(); | ||
608 | auto unless = x->new_ptr<Unless_t>(); | ||
609 | |||
610 | auto ifCond = x->new_ptr<IfCond_t>(); | ||
611 | ifCond->condition.set(unless_line->condition); | ||
612 | unless->nodes.push_back(ifCond); | ||
613 | |||
614 | auto stmt = x->new_ptr<Statement_t>(); | ||
615 | stmt->content.set(statement->content); | ||
616 | auto body = x->new_ptr<Body_t>(); | ||
617 | body->content.set(stmt); | ||
618 | unless->nodes.push_back(body); | ||
619 | |||
620 | statement->appendix.set(nullptr); | ||
621 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
622 | simpleValue->value.set(unless); | ||
623 | auto value = x->new_ptr<Value_t>(); | ||
624 | value->item.set(simpleValue); | ||
625 | auto exp = x->new_ptr<Exp_t>(); | ||
626 | exp->value.set(value); | ||
627 | auto exprList = x->new_ptr<ExpList_t>(); | ||
628 | exprList->exprs.push_back(exp); | ||
629 | auto expListAssign = x->new_ptr<ExpListAssign_t>(); | ||
630 | expListAssign->expList.set(exprList); | ||
631 | statement->content.set(expListAssign); | ||
632 | break; | ||
633 | } | ||
634 | case "CompInner"_id: { | ||
635 | auto compInner = appendix->item.to<CompInner_t>(); | ||
636 | auto comp = x->new_ptr<Comprehension_t>(); | ||
637 | comp->forLoop.set(compInner); | ||
638 | auto stmt = x->new_ptr<Statement_t>(); | ||
639 | stmt->content.set(statement->content); | ||
640 | comp->value.set(stmt); | ||
641 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
642 | simpleValue->value.set(comp); | ||
643 | auto value = x->new_ptr<Value_t>(); | ||
644 | value->item.set(simpleValue); | ||
645 | auto exp = x->new_ptr<Exp_t>(); | ||
646 | exp->value.set(value); | ||
647 | auto expList = x->new_ptr<ExpList_t>(); | ||
648 | expList->exprs.push_back(exp); | ||
649 | auto expListAssign = x->new_ptr<ExpListAssign_t>(); | ||
650 | expListAssign->expList.set(expList); | ||
651 | statement->content.set(expListAssign); | ||
652 | statement->appendix.set(nullptr); | ||
653 | break; | ||
654 | } | ||
655 | default: break; | ||
656 | } | ||
657 | } | ||
658 | auto content = statement->content.get(); | ||
659 | if (!content) { | ||
660 | out.push_back(Empty); | ||
661 | return; | ||
662 | } | ||
663 | switch (content->getId()) { | ||
664 | case "Import"_id: transformImport(static_cast<Import_t*>(content), out); break; | ||
665 | case "While"_id: transformWhile(static_cast<While_t*>(content), out); break; | ||
666 | case "For"_id: transformFor(static_cast<For_t*>(content), out); break; | ||
667 | case "ForEach"_id: transformForEach(static_cast<ForEach_t*>(content), out); break; | ||
668 | case "Return"_id: transformReturn(static_cast<Return_t*>(content), out); break; | ||
669 | case "Local"_id: transformLocal(static_cast<Local_t*>(content), out); break; | ||
670 | case "Export"_id: transformExport(static_cast<Export_t*>(content), out); break; | ||
671 | case "BreakLoop"_id: transformBreakLoop(static_cast<BreakLoop_t*>(content), out); break; | ||
672 | case "ExpListAssign"_id: { | ||
673 | auto expListAssign = static_cast<ExpListAssign_t*>(content); | ||
674 | if (expListAssign->action) { | ||
675 | transformAssignment(expListAssign, out); | ||
676 | } else { | ||
677 | auto expList = expListAssign->expList.get(); | ||
678 | if (expList->exprs.objects().empty()) { | ||
679 | out.push_back(Empty); | ||
680 | break; | ||
681 | } | ||
682 | if (auto singleValue = singleValueFrom(expList)) { | ||
683 | if (auto simpleValue = singleValue->item.as<SimpleValue_t>()) { | ||
684 | auto value = simpleValue->value.get(); | ||
685 | bool specialSingleValue = true; | ||
686 | switch (value->getId()) { | ||
687 | case "If"_id: transformIf(static_cast<If_t*>(value), out); break; | ||
688 | case "ClassDecl"_id: transformClassDecl(static_cast<ClassDecl_t*>(value), out); break; | ||
689 | case "Unless"_id: transformUnless(static_cast<Unless_t*>(value), out); break; | ||
690 | case "Switch"_id: transformSwitch(static_cast<Switch_t*>(value), out); break; | ||
691 | case "With"_id: transformWith(static_cast<With_t*>(value), out); break; | ||
692 | case "ForEach"_id: transformForEach(static_cast<ForEach_t*>(value), out); break; | ||
693 | case "For"_id: transformFor(static_cast<For_t*>(value), out); break; | ||
694 | case "While"_id: transformWhile(static_cast<While_t*>(value), out); break; | ||
695 | case "Do"_id: transformDo(static_cast<Do_t*>(value), out); break; | ||
696 | case "Comprehension"_id: transformCompCommon(static_cast<Comprehension_t*>(value), out); break; | ||
697 | default: specialSingleValue = false; break; | ||
698 | } | ||
699 | if (specialSingleValue) { | ||
700 | break; | ||
701 | } | ||
702 | } | ||
703 | if (auto chainValue = singleValue->item.as<ChainValue_t>()) { | ||
704 | if (isChainValueCall(chainValue)) { | ||
705 | transformChainValue(chainValue, out, ExpUsage::Common); | ||
706 | break; | ||
707 | } | ||
708 | } | ||
709 | } | ||
710 | if (_config.allowExprNotInTheEndOfBody) { | ||
711 | auto assign = x->new_ptr<Assign_t>(); | ||
712 | assign->values.dup(expList->exprs); | ||
713 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
714 | assignment->expList.set(toAst<ExpList_t>("_", ExpList, x)); | ||
715 | assignment->action.set(assign); | ||
716 | transformAssignment(assignment, out); | ||
717 | } else { | ||
718 | throw std::logic_error(debugInfo("Expression list must appear at the end of body block."sv, expList)); | ||
719 | } | ||
720 | } | ||
721 | break; | ||
722 | } | ||
723 | default: break; | ||
724 | } | ||
725 | } | ||
726 | |||
727 | str_list getAssignVars(ExpListAssign_t* assignment) { | ||
728 | str_list vars; | ||
729 | if (!assignment->action.is<Assign_t>()) return vars; | ||
730 | for (auto exp : assignment->expList->exprs.objects()) { | ||
731 | auto var = singleVariableFrom(exp); | ||
732 | vars.push_back(var.empty() ? Empty : var); | ||
733 | } | ||
734 | return vars; | ||
735 | } | ||
736 | |||
737 | str_list getAssignVars(With_t* with) { | ||
738 | str_list vars; | ||
739 | for (auto exp : with->valueList->exprs.objects()) { | ||
740 | auto var = singleVariableFrom(exp); | ||
741 | vars.push_back(var.empty() ? Empty : var); | ||
742 | } | ||
743 | return vars; | ||
744 | } | ||
745 | |||
746 | str_list getAssignDefs(ExpList_t* expList) { | ||
747 | str_list preDefs; | ||
748 | for (auto exp_ : expList->exprs.objects()) { | ||
749 | auto exp = static_cast<Exp_t*>(exp_); | ||
750 | if (auto value = singleValueFrom(exp)) { | ||
751 | if (auto chain = value->item.as<ChainValue_t>()) { | ||
752 | BLOCK_START | ||
753 | BREAK_IF(chain->items.size() != 1); | ||
754 | auto callable = ast_cast<Callable_t>(chain->items.front()); | ||
755 | BREAK_IF(!callable); | ||
756 | auto var = callable->item.as<Variable_t>(); | ||
757 | BREAK_IF(!var); | ||
758 | auto name = toString(var); | ||
759 | if (!isDefined(name)) { | ||
760 | preDefs.push_back(name); | ||
761 | } | ||
762 | BLOCK_END | ||
763 | } | ||
764 | } else { | ||
765 | throw std::logic_error(debugInfo("Left hand expression is not assignable."sv, exp)); | ||
766 | } | ||
767 | } | ||
768 | return preDefs; | ||
769 | } | ||
770 | |||
771 | str_list transformAssignDefs(ExpList_t* expList) { | ||
772 | str_list preDefs; | ||
773 | for (auto exp_ : expList->exprs.objects()) { | ||
774 | auto exp = static_cast<Exp_t*>(exp_); | ||
775 | if (auto value = singleValueFrom(exp)) { | ||
776 | if (auto chain = value->item.as<ChainValue_t>()) { | ||
777 | BLOCK_START | ||
778 | BREAK_IF(chain->items.size() != 1); | ||
779 | auto callable = ast_cast<Callable_t>(chain->items.front()); | ||
780 | BREAK_IF(!callable); | ||
781 | auto var = callable->item.as<Variable_t>(); | ||
782 | BREAK_IF(!var); | ||
783 | auto name = toString(var); | ||
784 | if (addToScope(name)) { | ||
785 | preDefs.push_back(name); | ||
786 | } | ||
787 | BLOCK_END | ||
788 | } | ||
789 | } else { | ||
790 | throw std::logic_error(debugInfo("Left hand expression is not assignable."sv, exp)); | ||
791 | } | ||
792 | } | ||
793 | return preDefs; | ||
794 | } | ||
795 | |||
796 | std::string getPredefine(const str_list& defs) { | ||
797 | if (defs.empty()) return Empty; | ||
798 | return indent() + s("local "sv) + join(defs, ", "sv); | ||
799 | } | ||
800 | |||
801 | std::string getDestrucureDefine(ExpListAssign_t* assignment) { | ||
802 | auto info = extractDestructureInfo(assignment); | ||
803 | if (!info.first.empty()) { | ||
804 | for (const auto& destruct : info.first) { | ||
805 | str_list defs; | ||
806 | for (const auto& item : destruct.items) { | ||
807 | if (item.isVariable && addToScope(item.name)) { | ||
808 | defs.push_back(item.name); | ||
809 | } | ||
810 | } | ||
811 | if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv); | ||
812 | } | ||
813 | } | ||
814 | return clearBuf(); | ||
815 | } | ||
816 | |||
817 | std::string getPredefine(ExpListAssign_t* assignment) { | ||
818 | auto preDefine = getDestrucureDefine(assignment); | ||
819 | if (preDefine.empty()) { | ||
820 | preDefine = getPredefine(transformAssignDefs(assignment->expList)); | ||
821 | } | ||
822 | return preDefine.empty() ? preDefine : preDefine + nll(assignment); | ||
823 | } | ||
824 | |||
825 | ExpList_t* expListFrom(Statement_t* statement) { | ||
826 | if (auto expListAssign = statement->content.as<ExpListAssign_t>()) { | ||
827 | if (!expListAssign->action) { | ||
828 | return expListAssign->expList.get(); | ||
829 | } | ||
830 | } | ||
831 | return nullptr; | ||
832 | } | ||
833 | |||
834 | ExpListAssign_t* assignmentFrom(Statement_t* statement) { | ||
835 | if (auto expListAssign = statement->content.as<ExpListAssign_t>()) { | ||
836 | if (expListAssign->action) { | ||
837 | return expListAssign; | ||
838 | } | ||
839 | } | ||
840 | return nullptr; | ||
841 | } | ||
842 | |||
843 | void assignLastExplist(ExpList_t* expList, Body_t* body) { | ||
844 | auto last = lastStatementFrom(body); | ||
845 | if (!last) return; | ||
846 | bool lastAssignable = expListFrom(last) || ast_is<For_t, ForEach_t, While_t>(last->content); | ||
847 | if (lastAssignable) { | ||
848 | auto x = last; | ||
849 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | ||
850 | newAssignment->expList.set(expList); | ||
851 | auto assign = x->new_ptr<Assign_t>(); | ||
852 | if (auto valueList = last->content.as<ExpListAssign_t>()) { | ||
853 | assign->values.dup(valueList->expList->exprs); | ||
854 | } else { | ||
855 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
856 | simpleValue->value.set(last->content); | ||
857 | auto value = x->new_ptr<Value_t>(); | ||
858 | value->item.set(simpleValue); | ||
859 | auto exp = x->new_ptr<Exp_t>(); | ||
860 | exp->value.set(value); | ||
861 | assign->values.push_back(exp); | ||
862 | } | ||
863 | newAssignment->action.set(assign); | ||
864 | last->content.set(newAssignment); | ||
865 | } | ||
866 | } | ||
867 | |||
868 | void transformAssignment(ExpListAssign_t* assignment, str_list& out) { | ||
869 | checkAssignable(assignment->expList); | ||
870 | BLOCK_START | ||
871 | auto assign = ast_cast<Assign_t>(assignment->action); | ||
872 | BREAK_IF(!assign || assign->values.objects().size() != 1); | ||
873 | auto value = assign->values.objects().front(); | ||
874 | if (ast_is<Exp_t>(value)) { | ||
875 | if (auto val = simpleSingleValueFrom(value)) { | ||
876 | value = val->value.get(); | ||
877 | } | ||
878 | } | ||
879 | switch (value->getId()) { | ||
880 | case "If"_id: | ||
881 | case "Unless"_id: { | ||
882 | auto expList = assignment->expList.get(); | ||
883 | str_list temp; | ||
884 | auto defs = transformAssignDefs(expList); | ||
885 | if (!defs.empty()) temp.push_back(getPredefine(defs) + nll(expList)); | ||
886 | value->traverse([&](ast_node* node) { | ||
887 | switch (node->getId()) { | ||
888 | case "IfCond"_id: return traversal::Return; | ||
889 | case "Body"_id: { | ||
890 | auto body = static_cast<Body_t*>(node); | ||
891 | assignLastExplist(expList, body); | ||
892 | return traversal::Return; | ||
893 | } | ||
894 | default: return traversal::Continue; | ||
895 | } | ||
896 | }); | ||
897 | switch (value->getId()) { | ||
898 | case "If"_id: transformIf(static_cast<If_t*>(value), temp); break; | ||
899 | case "Unless"_id: transformUnless(static_cast<Unless_t*>(value), temp); break; | ||
900 | } | ||
901 | out.push_back(join(temp)); | ||
902 | return; | ||
903 | } | ||
904 | case "Switch"_id: { | ||
905 | auto switchNode = static_cast<Switch_t*>(value); | ||
906 | auto expList = assignment->expList.get(); | ||
907 | for (auto branch_ : switchNode->branches.objects()) { | ||
908 | auto branch = static_cast<SwitchCase_t*>(branch_); | ||
909 | assignLastExplist(expList, branch->body); | ||
910 | } | ||
911 | if (switchNode->lastBranch) { | ||
912 | assignLastExplist(expList, switchNode->lastBranch); | ||
913 | } | ||
914 | std::string preDefine = getPredefine(assignment); | ||
915 | transformSwitch(switchNode, out); | ||
916 | out.back() = preDefine + out.back(); | ||
917 | return; | ||
918 | } | ||
919 | case "With"_id: { | ||
920 | auto withNode = static_cast<With_t*>(value); | ||
921 | str_list temp; | ||
922 | auto expList = assignment->expList.get(); | ||
923 | std::string preDefine = getPredefine(assignment); | ||
924 | transformWith(withNode, temp, expList); | ||
925 | out.push_back(preDefine + temp.back()); | ||
926 | return; | ||
927 | } | ||
928 | case "Do"_id: { | ||
929 | auto doNode = static_cast<Do_t*>(value); | ||
930 | auto expList = assignment->expList.get(); | ||
931 | assignLastExplist(expList, doNode->body); | ||
932 | std::string preDefine = getPredefine(assignment); | ||
933 | transformDo(doNode, out); | ||
934 | out.back() = preDefine + out.back(); | ||
935 | return; | ||
936 | } | ||
937 | case "Comprehension"_id: { | ||
938 | auto expList = assignment->expList.get(); | ||
939 | std::string preDefine = getPredefine(assignment); | ||
940 | transformCompInPlace(static_cast<Comprehension_t*>(value), expList, out); | ||
941 | out.back() = preDefine + out.back(); | ||
942 | return; | ||
943 | } | ||
944 | case "TblComprehension"_id: { | ||
945 | auto expList = assignment->expList.get(); | ||
946 | std::string preDefine = getPredefine(assignment); | ||
947 | transformTblCompInPlace(static_cast<TblComprehension_t*>(value), expList, out); | ||
948 | out.back() = preDefine + out.back(); | ||
949 | return; | ||
950 | } | ||
951 | case "For"_id: { | ||
952 | str_list temp; | ||
953 | auto expList = assignment->expList.get(); | ||
954 | std::string preDefine = getPredefine(assignment); | ||
955 | transformForInPlace(static_cast<For_t*>(value), temp, expList); | ||
956 | out.push_back(preDefine + temp.back()); | ||
957 | return; | ||
958 | } | ||
959 | case "ForEach"_id: { | ||
960 | str_list temp; | ||
961 | auto expList = assignment->expList.get(); | ||
962 | std::string preDefine = getPredefine(assignment); | ||
963 | transformForEachInPlace(static_cast<ForEach_t*>(value), temp, expList); | ||
964 | out.push_back(preDefine + temp.back()); | ||
965 | return; | ||
966 | } | ||
967 | case "ClassDecl"_id: { | ||
968 | str_list temp; | ||
969 | auto expList = assignment->expList.get(); | ||
970 | std::string preDefine = getPredefine(assignment); | ||
971 | transformClassDecl(static_cast<ClassDecl_t*>(value), temp, ExpUsage::Assignment, expList); | ||
972 | out.push_back(preDefine + temp.back()); | ||
973 | return; | ||
974 | } | ||
975 | case "While"_id: { | ||
976 | str_list temp; | ||
977 | auto expList = assignment->expList.get(); | ||
978 | std::string preDefine = getPredefine(assignment); | ||
979 | transformWhileInPlace(static_cast<While_t*>(value), temp, expList); | ||
980 | out.push_back(preDefine + temp.back()); | ||
981 | return; | ||
982 | } | ||
983 | } | ||
984 | auto exp = ast_cast<Exp_t>(value); | ||
985 | BREAK_IF(!exp); | ||
986 | if (auto chainValue = exp->value->item.as<ChainValue_t>()) { | ||
987 | if (isColonChain(chainValue)) { | ||
988 | auto assignable = assignment->expList.get(); | ||
989 | std::string preDefine = getPredefine(transformAssignDefs(assignable)); | ||
990 | transformColonChain(chainValue, out, ExpUsage::Assignment, assignable); | ||
991 | auto nl = preDefine.empty() ? Empty : nll(chainValue); | ||
992 | if (!preDefine.empty()) out.back() = preDefine + nl + out.back(); | ||
993 | return; | ||
994 | } else if (hasKeywordColonChainItem(chainValue)) { | ||
995 | transformChainValue(chainValue, out, ExpUsage::Assignment, assignment->expList); | ||
996 | return; | ||
997 | } | ||
998 | } | ||
999 | BLOCK_END | ||
1000 | auto info = extractDestructureInfo(assignment); | ||
1001 | if (info.first.empty()) { | ||
1002 | transformAssignmentCommon(assignment, out); | ||
1003 | } else { | ||
1004 | str_list temp; | ||
1005 | for (const auto& destruct : info.first) { | ||
1006 | if (destruct.items.size() == 1) { | ||
1007 | auto& pair = destruct.items.front(); | ||
1008 | _buf << indent(); | ||
1009 | if (pair.isVariable && !isDefined(pair.name)) { | ||
1010 | _buf << s("local "sv); | ||
1011 | } | ||
1012 | _buf << pair.name << " = "sv << info.first.front().value << pair.structure << nll(assignment); | ||
1013 | addToScope(pair.name); | ||
1014 | temp.push_back(clearBuf()); | ||
1015 | } else if (matchAst(Name, destruct.value)) { | ||
1016 | str_list defs, names, values; | ||
1017 | for (const auto& item : destruct.items) { | ||
1018 | if (item.isVariable && addToScope(item.name)) { | ||
1019 | defs.push_back(item.name); | ||
1020 | } | ||
1021 | names.push_back(item.name); | ||
1022 | values.push_back(item.structure); | ||
1023 | } | ||
1024 | for (auto& v : values) v.insert(0, destruct.value); | ||
1025 | if (defs.empty()) { | ||
1026 | _buf << indent() << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment); | ||
1027 | } else { | ||
1028 | _buf << indent() << "local "sv; | ||
1029 | if (defs.size() != names.size()) { | ||
1030 | _buf << join(defs,", "sv) << nll(assignment) << indent(); | ||
1031 | } | ||
1032 | _buf << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment); | ||
1033 | } | ||
1034 | temp.push_back(clearBuf()); | ||
1035 | } else { | ||
1036 | str_list defs, names, values; | ||
1037 | for (const auto& item : destruct.items) { | ||
1038 | if (item.isVariable && addToScope(item.name)) { | ||
1039 | defs.push_back(item.name); | ||
1040 | } | ||
1041 | names.push_back(item.name); | ||
1042 | values.push_back(item.structure); | ||
1043 | } | ||
1044 | if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv) << nll(assignment); | ||
1045 | _buf << indent() << "do"sv << nll(assignment); | ||
1046 | pushScope(); | ||
1047 | auto objVar = getUnusedName("_obj_"); | ||
1048 | for (auto& v : values) v.insert(0, objVar); | ||
1049 | _buf << indent() << "local "sv << objVar << " = "sv << destruct.value << nll(assignment); | ||
1050 | _buf << indent() << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment); | ||
1051 | popScope(); | ||
1052 | _buf << indent() << "end"sv << nll(assignment); | ||
1053 | temp.push_back(clearBuf()); | ||
1054 | } | ||
1055 | } | ||
1056 | if (info.second) { | ||
1057 | transformAssignmentCommon(info.second, temp); | ||
1058 | } | ||
1059 | out.push_back(join(temp)); | ||
1060 | } | ||
1061 | } | ||
1062 | |||
1063 | void transformAssignItem(ast_node* value, str_list& out) { | ||
1064 | switch (value->getId()) { | ||
1065 | case "With"_id: transformWithClosure(static_cast<With_t*>(value), out); break; | ||
1066 | case "If"_id: transformIf(static_cast<If_t*>(value), out, ExpUsage::Closure); break; | ||
1067 | case "Switch"_id: transformSwitchClosure(static_cast<Switch_t*>(value), out); break; | ||
1068 | case "TableBlock"_id: transformTableBlock(static_cast<TableBlock_t*>(value), out); break; | ||
1069 | case "Exp"_id: transformExp(static_cast<Exp_t*>(value), out); break; | ||
1070 | default: break; | ||
1071 | } | ||
1072 | } | ||
1073 | |||
1074 | std::list<DestructItem> destructFromExp(ast_node* node) { | ||
1075 | const node_container* tableItems = nullptr; | ||
1076 | if (ast_cast<Exp_t>(node)) { | ||
1077 | auto item = singleValueFrom(node)->item.get(); | ||
1078 | if (!item) throw std::logic_error(debugInfo("Invalid destructure value."sv, node)); | ||
1079 | auto tbA = item->getByPath<TableLit_t>(); | ||
1080 | if (tbA) { | ||
1081 | tableItems = &tbA->values.objects(); | ||
1082 | } else { | ||
1083 | auto tbB = ast_cast<simple_table_t>(item); | ||
1084 | if (tbB) tableItems = &tbB->pairs.objects(); | ||
1085 | } | ||
1086 | } else if (auto table = ast_cast<TableBlock_t>(node)) { | ||
1087 | tableItems = &table->values.objects(); | ||
1088 | } | ||
1089 | std::list<DestructItem> pairs; | ||
1090 | int index = 0; | ||
1091 | for (auto pair : *tableItems) { | ||
1092 | switch (pair->getId()) { | ||
1093 | case "Exp"_id: { | ||
1094 | ++index; | ||
1095 | if (!isAssignable(static_cast<Exp_t*>(pair))) { | ||
1096 | throw std::logic_error(debugInfo("Can't destructure value."sv, pair)); | ||
1097 | } | ||
1098 | auto value = singleValueFrom(pair); | ||
1099 | auto item = value->item.get(); | ||
1100 | if (ast_cast<simple_table_t>(item) || | ||
1101 | item->getByPath<TableLit_t>()) { | ||
1102 | auto subPairs = destructFromExp(pair); | ||
1103 | for (auto& p : subPairs) { | ||
1104 | pairs.push_back({p.isVariable, p.name, | ||
1105 | s("["sv) + std::to_string(index) + s("]"sv) + p.structure}); | ||
1106 | } | ||
1107 | } else { | ||
1108 | bool lintGlobal = _config.lintGlobalVariable; | ||
1109 | _config.lintGlobalVariable = false; | ||
1110 | auto exp = static_cast<Exp_t*>(pair); | ||
1111 | auto varName = singleVariableFrom(exp); | ||
1112 | bool isVariable = !varName.empty(); | ||
1113 | if (!isVariable) { | ||
1114 | str_list temp; | ||
1115 | transformExp(exp, temp); | ||
1116 | varName = std::move(temp.back()); | ||
1117 | } | ||
1118 | _config.lintGlobalVariable = lintGlobal; | ||
1119 | pairs.push_back({ | ||
1120 | isVariable, | ||
1121 | varName, | ||
1122 | s("["sv) + std::to_string(index) + s("]"sv) | ||
1123 | }); | ||
1124 | } | ||
1125 | break; | ||
1126 | } | ||
1127 | case "variable_pair"_id: { | ||
1128 | auto vp = static_cast<variable_pair_t*>(pair); | ||
1129 | auto name = toString(vp->name); | ||
1130 | pairs.push_back({true, name, s("."sv) + name}); | ||
1131 | break; | ||
1132 | } | ||
1133 | case "normal_pair"_id: { | ||
1134 | auto np = static_cast<normal_pair_t*>(pair); | ||
1135 | auto key = np->key->getByPath<Name_t>(); | ||
1136 | if (!key) throw std::logic_error(debugInfo("Invalid key for destructure."sv, np)); | ||
1137 | if (auto exp = np->value.as<Exp_t>()) { | ||
1138 | if (!isAssignable(exp)) throw std::logic_error(debugInfo("Can't destructure value."sv, exp)); | ||
1139 | auto item = singleValueFrom(exp)->item.get(); | ||
1140 | if (ast_cast<simple_table_t>(item) || | ||
1141 | item->getByPath<TableLit_t>()) { | ||
1142 | auto subPairs = destructFromExp(exp); | ||
1143 | for (auto& p : subPairs) { | ||
1144 | pairs.push_back({p.isVariable, p.name, | ||
1145 | s("."sv) + toString(key) + p.structure}); | ||
1146 | } | ||
1147 | } else { | ||
1148 | bool lintGlobal = _config.lintGlobalVariable; | ||
1149 | _config.lintGlobalVariable = false; | ||
1150 | auto varName = singleVariableFrom(exp); | ||
1151 | bool isVariable = !varName.empty(); | ||
1152 | if (!isVariable) { | ||
1153 | str_list temp; | ||
1154 | transformExp(exp, temp); | ||
1155 | varName = std::move(temp.back()); | ||
1156 | } | ||
1157 | _config.lintGlobalVariable = lintGlobal; | ||
1158 | pairs.push_back({ | ||
1159 | isVariable, | ||
1160 | varName, | ||
1161 | s("."sv) + toString(key) | ||
1162 | }); | ||
1163 | } | ||
1164 | break; | ||
1165 | } | ||
1166 | if (np->value.as<TableBlock_t>()) { | ||
1167 | auto subPairs = destructFromExp(pair); | ||
1168 | for (auto& p : subPairs) { | ||
1169 | pairs.push_back({p.isVariable, p.name, | ||
1170 | s("."sv) + toString(key) + p.structure}); | ||
1171 | } | ||
1172 | } | ||
1173 | break; | ||
1174 | } | ||
1175 | } | ||
1176 | } | ||
1177 | return pairs; | ||
1178 | } | ||
1179 | |||
1180 | std::pair<std::list<Destructure>, ast_ptr<false, ExpListAssign_t>> | ||
1181 | extractDestructureInfo(ExpListAssign_t* assignment) { | ||
1182 | auto x = assignment; | ||
1183 | std::list<Destructure> destructs; | ||
1184 | if (!assignment->action.is<Assign_t>()) return { destructs, nullptr }; | ||
1185 | auto exprs = assignment->expList->exprs.objects(); | ||
1186 | auto values = assignment->action.to<Assign_t>()->values.objects(); | ||
1187 | size_t size = std::max(exprs.size(),values.size()); | ||
1188 | ast_ptr<false, Exp_t> var; | ||
1189 | if (exprs.size() < size) { | ||
1190 | var = toAst<Exp_t>("_"sv, Exp, x); | ||
1191 | while (exprs.size() < size) exprs.emplace_back(var); | ||
1192 | } | ||
1193 | ast_ptr<false, Exp_t> nullNode; | ||
1194 | if (values.size() < size) { | ||
1195 | nullNode = toAst<Exp_t>("nil"sv, Exp, x); | ||
1196 | while (values.size() < size) values.emplace_back(nullNode); | ||
1197 | } | ||
1198 | using iter = node_container::iterator; | ||
1199 | std::vector<std::pair<iter, iter>> destructPairs; | ||
1200 | str_list temp; | ||
1201 | for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) { | ||
1202 | auto expr = *i; | ||
1203 | ast_node* destructNode = expr->getByPath<Value_t, SimpleValue_t, TableLit_t>(); | ||
1204 | if (destructNode || (destructNode = expr->getByPath<Value_t, simple_table_t>())) { | ||
1205 | destructPairs.push_back({i,j}); | ||
1206 | pushScope(); | ||
1207 | transformAssignItem(*j, temp); | ||
1208 | popScope(); | ||
1209 | auto& destruct = destructs.emplace_back(); | ||
1210 | destruct.value = temp.back(); | ||
1211 | temp.pop_back(); | ||
1212 | auto pairs = destructFromExp(expr); | ||
1213 | destruct.items = std::move(pairs); | ||
1214 | } | ||
1215 | } | ||
1216 | for (const auto& p : destructPairs) { | ||
1217 | exprs.erase(p.first); | ||
1218 | values.erase(p.second); | ||
1219 | } | ||
1220 | ast_ptr<false, ExpListAssign_t> newAssignment; | ||
1221 | if (!destructPairs.empty() && !exprs.empty()) { | ||
1222 | auto x = assignment; | ||
1223 | auto expList = x->new_ptr<ExpList_t>(); | ||
1224 | auto newAssign = x->new_ptr<ExpListAssign_t>(); | ||
1225 | newAssign->expList.set(expList); | ||
1226 | for (auto expr : exprs) expList->exprs.push_back(expr); | ||
1227 | auto assign = x->new_ptr<Assign_t>(); | ||
1228 | for (auto value : values) assign->values.push_back(value); | ||
1229 | newAssign->action.set(assign); | ||
1230 | newAssignment = newAssign; | ||
1231 | } | ||
1232 | return {std::move(destructs), newAssignment}; | ||
1233 | } | ||
1234 | |||
1235 | void transformAssignmentCommon(ExpListAssign_t* assignment, str_list& out) { | ||
1236 | auto x = assignment; | ||
1237 | str_list temp; | ||
1238 | auto expList = assignment->expList.get(); | ||
1239 | auto action = assignment->action.get(); | ||
1240 | switch (action->getId()) { | ||
1241 | case "Update"_id: { | ||
1242 | auto update = static_cast<Update_t*>(action); | ||
1243 | auto leftExp = static_cast<Exp_t*>(expList->exprs.objects().front()); | ||
1244 | auto leftValue = singleValueFrom(leftExp); | ||
1245 | if (!leftValue) throw std::logic_error(debugInfo("Left hand expression is not assignable."sv, leftExp)); | ||
1246 | if (auto chain = leftValue->getByPath<ChainValue_t>()) { | ||
1247 | auto tmpChain = x->new_ptr<ChainValue_t>(); | ||
1248 | for (auto item : chain->items.objects()) { | ||
1249 | bool itemAdded = false; | ||
1250 | BLOCK_START | ||
1251 | auto exp = ast_cast<Exp_t>(item); | ||
1252 | BREAK_IF(!exp); | ||
1253 | auto var = singleVariableFrom(exp); | ||
1254 | BREAK_IF(!var.empty()); | ||
1255 | auto upVar = getUnusedName("_update_"); | ||
1256 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
1257 | assignment->expList.set(toAst<ExpList_t>(upVar, ExpList, x)); | ||
1258 | auto assign = x->new_ptr<Assign_t>(); | ||
1259 | assign->values.push_back(exp); | ||
1260 | assignment->action.set(assign); | ||
1261 | transformAssignment(assignment, temp); | ||
1262 | tmpChain->items.push_back(toAst<Exp_t>(upVar, Exp, x)); | ||
1263 | itemAdded = true; | ||
1264 | BLOCK_END | ||
1265 | if (!itemAdded) tmpChain->items.push_back(item); | ||
1266 | } | ||
1267 | chain->items.clear(); | ||
1268 | chain->items.dup(tmpChain->items); | ||
1269 | } | ||
1270 | transformValue(leftValue, temp); | ||
1271 | auto left = std::move(temp.back()); | ||
1272 | temp.pop_back(); | ||
1273 | transformExp(update->value, temp); | ||
1274 | auto right = std::move(temp.back()); | ||
1275 | temp.pop_back(); | ||
1276 | if (!singleValueFrom(update->value)) { | ||
1277 | right = s("("sv) + right + s(")"sv); | ||
1278 | } | ||
1279 | _buf << join(temp) << indent() << left << " = "sv << left << | ||
1280 | " "sv << toString(update->op) << " "sv << right << nll(assignment); | ||
1281 | out.push_back(clearBuf()); | ||
1282 | break; | ||
1283 | } | ||
1284 | case "Assign"_id: { | ||
1285 | auto defs = getAssignDefs(expList); | ||
1286 | bool oneLined = defs.size() == expList->exprs.objects().size() && | ||
1287 | traversal::Stop != action->traverse([&](ast_node* n) { | ||
1288 | if (n->getId() == "Callable"_id) { | ||
1289 | if (auto name = n->getByPath<Variable_t>()) { | ||
1290 | for (const auto& def : defs) { | ||
1291 | if (def == toString(name)) { | ||
1292 | return traversal::Stop; | ||
1293 | } | ||
1294 | } | ||
1295 | } | ||
1296 | } | ||
1297 | return traversal::Continue; | ||
1298 | }); | ||
1299 | if (oneLined) { | ||
1300 | auto assign = static_cast<Assign_t*>(action); | ||
1301 | for (auto value : assign->values.objects()) { | ||
1302 | transformAssignItem(value, temp); | ||
1303 | } | ||
1304 | std::string preDefine = getPredefine(defs); | ||
1305 | for (const auto& def : defs) { | ||
1306 | addToScope(def); | ||
1307 | } | ||
1308 | if (preDefine.empty()) { | ||
1309 | transformExpList(expList, temp); | ||
1310 | std::string left = std::move(temp.back()); | ||
1311 | temp.pop_back(); | ||
1312 | out.push_back(indent() + left + s(" = "sv) + join(temp, ", "sv) + nll(assignment)); | ||
1313 | } else { | ||
1314 | out.push_back(preDefine + s(" = "sv) + join(temp, ", "sv) + nll(assignment)); | ||
1315 | } | ||
1316 | } | ||
1317 | else { | ||
1318 | std::string preDefine = getPredefine(defs); | ||
1319 | for (const auto& def : defs) { | ||
1320 | addToScope(def); | ||
1321 | } | ||
1322 | transformExpList(expList, temp); | ||
1323 | std::string left = temp.back(); | ||
1324 | temp.pop_back(); | ||
1325 | auto assign = static_cast<Assign_t*>(action); | ||
1326 | for (auto value : assign->values.objects()) { | ||
1327 | transformAssignItem(value, temp); | ||
1328 | } | ||
1329 | out.push_back((preDefine.empty() ? Empty : preDefine + nll(assignment)) + indent() + left + s(" = "sv) + join(temp, ", "sv) + nll(assignment)); | ||
1330 | } | ||
1331 | break; | ||
1332 | } | ||
1333 | default: break; | ||
1334 | } | ||
1335 | } | ||
1336 | |||
1337 | void transformCond(const node_container& nodes, str_list& out, ExpUsage usage = ExpUsage::Common, bool unless = false) { | ||
1338 | std::vector<ast_ptr<false, ast_node>> ns(false); | ||
1339 | for (auto it = nodes.rbegin(); it != nodes.rend(); ++it) { | ||
1340 | ns.push_back(*it); | ||
1341 | if (auto cond = ast_cast<IfCond_t>(*it)) { | ||
1342 | if (*it != nodes.front() && cond->assign) { | ||
1343 | auto x = *it; | ||
1344 | auto newIf = x->new_ptr<If_t>(); | ||
1345 | for (auto j = ns.rbegin(); j != ns.rend(); ++j) { | ||
1346 | newIf->nodes.push_back(*j); | ||
1347 | } | ||
1348 | ns.clear(); | ||
1349 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
1350 | simpleValue->value.set(newIf); | ||
1351 | auto value = x->new_ptr<Value_t>(); | ||
1352 | value->item.set(simpleValue); | ||
1353 | auto exp = x->new_ptr<Exp_t>(); | ||
1354 | exp->value.set(value); | ||
1355 | auto expList = x->new_ptr<ExpList_t>(); | ||
1356 | expList->exprs.push_back(exp); | ||
1357 | auto expListAssign = x->new_ptr<ExpListAssign_t>(); | ||
1358 | expListAssign->expList.set(expList); | ||
1359 | auto stmt = x->new_ptr<Statement_t>(); | ||
1360 | stmt->content.set(expListAssign); | ||
1361 | auto body = x->new_ptr<Body_t>(); | ||
1362 | body->content.set(stmt); | ||
1363 | ns.push_back(body.get()); | ||
1364 | } | ||
1365 | } | ||
1366 | } | ||
1367 | if (nodes.size() != ns.size()) { | ||
1368 | auto x = ns.back(); | ||
1369 | auto newIf = x->new_ptr<If_t>(); | ||
1370 | for (auto j = ns.rbegin(); j != ns.rend(); ++j) { | ||
1371 | newIf->nodes.push_back(*j); | ||
1372 | } | ||
1373 | transformCond(newIf->nodes.objects(), out, usage, unless); | ||
1374 | return; | ||
1375 | } | ||
1376 | str_list temp; | ||
1377 | if (usage == ExpUsage::Closure) { | ||
1378 | temp.push_back(s("(function()"sv) + nll(nodes.front())); | ||
1379 | pushScope(); | ||
1380 | } | ||
1381 | std::list<std::pair<IfCond_t*, Body_t*>> ifCondPairs; | ||
1382 | ifCondPairs.emplace_back(); | ||
1383 | for (auto node : nodes) { | ||
1384 | switch (node->getId()) { | ||
1385 | case "IfCond"_id: | ||
1386 | ifCondPairs.back().first = static_cast<IfCond_t*>(node); | ||
1387 | break; | ||
1388 | case "Body"_id: | ||
1389 | ifCondPairs.back().second = static_cast<Body_t*>(node); | ||
1390 | ifCondPairs.emplace_back(); | ||
1391 | break; | ||
1392 | default: break; | ||
1393 | } | ||
1394 | } | ||
1395 | auto assign = ifCondPairs.front().first->assign.get(); | ||
1396 | bool storingValue = false; | ||
1397 | ast_ptr<false, ExpListAssign_t> extraAssignment; | ||
1398 | if (assign) { | ||
1399 | auto exp = ifCondPairs.front().first->condition.get(); | ||
1400 | auto x = exp; | ||
1401 | auto var = singleVariableFrom(exp); | ||
1402 | if (var.empty()) { | ||
1403 | storingValue = true; | ||
1404 | auto desVar = getUnusedName("_des_"); | ||
1405 | if (assign->values.objects().size() == 1) { | ||
1406 | auto var = singleVariableFrom(assign->values.objects().front()); | ||
1407 | if (!var.empty()) { | ||
1408 | desVar = var; | ||
1409 | storingValue = false; | ||
1410 | } | ||
1411 | } | ||
1412 | if (storingValue) { | ||
1413 | if (usage != ExpUsage::Closure) { | ||
1414 | temp.push_back(indent() + s("do"sv) + nll(assign)); | ||
1415 | pushScope(); | ||
1416 | } | ||
1417 | auto expList = toAst<ExpList_t>(desVar, ExpList, x); | ||
1418 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
1419 | assignment->expList.set(expList); | ||
1420 | assignment->action.set(assign); | ||
1421 | transformAssignment(assignment, temp); | ||
1422 | } | ||
1423 | { | ||
1424 | auto expList = x->new_ptr<ExpList_t>(); | ||
1425 | expList->exprs.push_back(exp); | ||
1426 | auto assignOne = x->new_ptr<Assign_t>(); | ||
1427 | auto valExp = toAst<Exp_t>(desVar, Exp, x); | ||
1428 | assignOne->values.push_back(valExp); | ||
1429 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
1430 | assignment->expList.set(expList); | ||
1431 | assignment->action.set(assignOne); | ||
1432 | extraAssignment.set(assignment); | ||
1433 | ifCondPairs.front().first->condition.set(valExp); | ||
1434 | } | ||
1435 | } else { | ||
1436 | if (!isDefined(var)) { | ||
1437 | storingValue = true; | ||
1438 | if (usage != ExpUsage::Closure) { | ||
1439 | temp.push_back(indent() + s("do"sv) + nll(assign)); | ||
1440 | pushScope(); | ||
1441 | } | ||
1442 | } | ||
1443 | auto expList = x->new_ptr<ExpList_t>(); | ||
1444 | expList->exprs.push_back(exp); | ||
1445 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
1446 | assignment->expList.set(expList); | ||
1447 | assignment->action.set(assign); | ||
1448 | transformAssignment(assignment, temp); | ||
1449 | } | ||
1450 | } | ||
1451 | for (const auto& pair : ifCondPairs) { | ||
1452 | if (pair.first) { | ||
1453 | str_list tmp; | ||
1454 | auto condition = pair.first->condition.get(); | ||
1455 | if (unless) { | ||
1456 | if (auto value = singleValueFrom(condition)) { | ||
1457 | transformValue(value, tmp); | ||
1458 | } else { | ||
1459 | transformExp(condition, tmp); | ||
1460 | tmp.back() = s("("sv) + tmp.back() + s(")"sv); | ||
1461 | } | ||
1462 | tmp.back().insert(0, s("not "sv)); | ||
1463 | unless = false; | ||
1464 | } else { | ||
1465 | transformExp(condition, tmp); | ||
1466 | } | ||
1467 | _buf << indent(); | ||
1468 | if (pair != ifCondPairs.front()) { | ||
1469 | _buf << "else"sv; | ||
1470 | } | ||
1471 | _buf << "if "sv << tmp.back() << " then"sv << nll(condition); | ||
1472 | temp.push_back(clearBuf()); | ||
1473 | } | ||
1474 | if (pair.second) { | ||
1475 | if (!pair.first) { | ||
1476 | temp.push_back(indent() + s("else"sv) + nll(pair.second)); | ||
1477 | } | ||
1478 | pushScope(); | ||
1479 | if (pair == ifCondPairs.front() && extraAssignment) { | ||
1480 | transformAssignment(extraAssignment, temp); | ||
1481 | } | ||
1482 | transformBody(pair.second, temp, usage != ExpUsage::Common); | ||
1483 | popScope(); | ||
1484 | } | ||
1485 | if (!pair.first) { | ||
1486 | temp.push_back(indent() + s("end"sv) + nll(nodes.front())); | ||
1487 | break; | ||
1488 | } | ||
1489 | } | ||
1490 | if (storingValue && usage != ExpUsage::Closure) { | ||
1491 | popScope(); | ||
1492 | temp.push_back(indent() + s("end"sv) + nlr(nodes.front())); | ||
1493 | } | ||
1494 | if (usage == ExpUsage::Closure) { | ||
1495 | popScope(); | ||
1496 | temp.push_back(indent() + s("end)()"sv)); | ||
1497 | } | ||
1498 | out.push_back(join(temp)); | ||
1499 | } | ||
1500 | |||
1501 | void transformIf(If_t* ifNode, str_list& out, ExpUsage usage = ExpUsage::Common) { | ||
1502 | transformCond(ifNode->nodes.objects(), out, usage); | ||
1503 | } | ||
1504 | |||
1505 | void transformUnless(Unless_t* unless, str_list& out, ExpUsage usage = ExpUsage::Common) { | ||
1506 | transformCond(unless->nodes.objects(), out, usage, true); | ||
1507 | } | ||
1508 | |||
1509 | void transformExpList(ExpList_t* expList, str_list& out) { | ||
1510 | str_list temp; | ||
1511 | for (auto exp : expList->exprs.objects()) { | ||
1512 | transformExp(static_cast<Exp_t*>(exp), temp); | ||
1513 | } | ||
1514 | out.push_back(join(temp, ", "sv)); | ||
1515 | } | ||
1516 | |||
1517 | void transformExpListLow(ExpListLow_t* expListLow, str_list& out) { | ||
1518 | str_list temp; | ||
1519 | for (auto exp : expListLow->exprs.objects()) { | ||
1520 | transformExp(static_cast<Exp_t*>(exp), temp); | ||
1521 | } | ||
1522 | out.push_back(join(temp, ", "sv)); | ||
1523 | } | ||
1524 | |||
1525 | void transformExp(Exp_t* exp, str_list& out) { | ||
1526 | str_list temp; | ||
1527 | transformValue(exp->value, temp); | ||
1528 | for (auto _opValue : exp->opValues.objects()) { | ||
1529 | auto opValue = static_cast<exp_op_value_t*>(_opValue); | ||
1530 | transformBinaryOperator(opValue->op, temp); | ||
1531 | transformValue(opValue->value, temp); | ||
1532 | } | ||
1533 | out.push_back(join(temp, " "sv)); | ||
1534 | } | ||
1535 | |||
1536 | void transformValue(Value_t* value, str_list& out) { | ||
1537 | auto item = value->item.get(); | ||
1538 | switch (item->getId()) { | ||
1539 | case "SimpleValue"_id: transformSimpleValue(static_cast<SimpleValue_t*>(item), out); break; | ||
1540 | case "simple_table"_id: transform_simple_table(static_cast<simple_table_t*>(item), out); break; | ||
1541 | case "ChainValue"_id: { | ||
1542 | auto chainValue = static_cast<ChainValue_t*>(item); | ||
1543 | if (isColonChain(chainValue)) { | ||
1544 | transformColonChainClosure(chainValue, out); | ||
1545 | } else { | ||
1546 | transformChainValue(chainValue, out); | ||
1547 | } | ||
1548 | break; | ||
1549 | } | ||
1550 | case "String"_id: transformString(static_cast<String_t*>(item), out); break; | ||
1551 | default: break; | ||
1552 | } | ||
1553 | } | ||
1554 | |||
1555 | void transformCallable(Callable_t* callable, str_list& out, bool invoke) { | ||
1556 | auto item = callable->item.get(); | ||
1557 | switch (item->getId()) { | ||
1558 | case "Variable"_id: { | ||
1559 | transformVariable(static_cast<Variable_t*>(item), out); | ||
1560 | if (_config.lintGlobalVariable && !isDefined(out.back())) { | ||
1561 | if (_globals.find(out.back()) == _globals.end()) { | ||
1562 | _globals[out.back()] = {item->m_begin.m_line, item->m_begin.m_col}; | ||
1563 | } | ||
1564 | } | ||
1565 | break; | ||
1566 | } | ||
1567 | case "SelfName"_id: { transformSelfName(static_cast<SelfName_t*>(item), out, invoke); | ||
1568 | if (_config.lintGlobalVariable) { | ||
1569 | std::string self("self"sv); | ||
1570 | if (!isDefined(self)) { | ||
1571 | if (_globals.find(self) == _globals.end()) { | ||
1572 | _globals[self] = {item->m_begin.m_line, item->m_begin.m_col}; | ||
1573 | } | ||
1574 | } | ||
1575 | } | ||
1576 | break; | ||
1577 | } | ||
1578 | case "VarArg"_id: out.push_back(s("..."sv)); break; | ||
1579 | case "Parens"_id: transformParens(static_cast<Parens_t*>(item), out); break; | ||
1580 | default: break; | ||
1581 | } | ||
1582 | } | ||
1583 | |||
1584 | void transformParens(Parens_t* parans, str_list& out) { | ||
1585 | str_list temp; | ||
1586 | transformExp(parans->expr, temp); | ||
1587 | out.push_back(s("("sv) + temp.front() + s(")"sv)); | ||
1588 | } | ||
1589 | |||
1590 | void transformSimpleValue(SimpleValue_t* simpleValue, str_list& out) { | ||
1591 | auto value = simpleValue->value.get(); | ||
1592 | switch (value->getId()) { | ||
1593 | case "const_value"_id: transform_const_value(static_cast<const_value_t*>(value), out); break; | ||
1594 | case "If"_id: transformIf(static_cast<If_t*>(value), out, ExpUsage::Closure); break; | ||
1595 | case "Unless"_id: transformUnless(static_cast<Unless_t*>(value), out, ExpUsage::Closure); break; | ||
1596 | case "Switch"_id: transformSwitchClosure(static_cast<Switch_t*>(value), out); break; | ||
1597 | case "With"_id: transformWithClosure(static_cast<With_t*>(value), out); break; | ||
1598 | case "ClassDecl"_id: transformClassDeclClosure(static_cast<ClassDecl_t*>(value), out); break; | ||
1599 | case "ForEach"_id: transformForEachClosure(static_cast<ForEach_t*>(value), out); break; | ||
1600 | case "For"_id: transformForClosure(static_cast<For_t*>(value), out); break; | ||
1601 | case "While"_id: transformWhileClosure(static_cast<While_t*>(value), out); break; | ||
1602 | case "Do"_id: transformDoClosure(static_cast<Do_t*>(value), out); break; | ||
1603 | case "unary_exp"_id: transform_unary_exp(static_cast<unary_exp_t*>(value), out); break; | ||
1604 | case "TblComprehension"_id: transformTblCompClosure(static_cast<TblComprehension_t*>(value), out); break; | ||
1605 | case "TableLit"_id: transformTableLit(static_cast<TableLit_t*>(value), out); break; | ||
1606 | case "Comprehension"_id: transformCompClosure(static_cast<Comprehension_t*>(value), out); break; | ||
1607 | case "FunLit"_id: transformFunLit(static_cast<FunLit_t*>(value), out); break; | ||
1608 | case "Num"_id: transformNum(static_cast<Num_t*>(value), out); break; | ||
1609 | default: break; | ||
1610 | } | ||
1611 | } | ||
1612 | |||
1613 | void transformFunLit(FunLit_t* funLit, str_list& out) { | ||
1614 | str_list temp; | ||
1615 | bool isFatArrow = toString(funLit->arrow) == "=>"sv; | ||
1616 | pushScope(); | ||
1617 | if (isFatArrow) { | ||
1618 | forceAddToScope(s("self"sv)); | ||
1619 | } | ||
1620 | if (auto argsDef = funLit->argsDef.get()) { | ||
1621 | transformFnArgsDef(argsDef, temp); | ||
1622 | if (funLit->body) { | ||
1623 | transformBody(funLit->body, temp, true); | ||
1624 | } else { | ||
1625 | temp.push_back(Empty); | ||
1626 | } | ||
1627 | auto it = temp.begin(); | ||
1628 | auto& args = *it; | ||
1629 | auto& initArgs = *(++it); | ||
1630 | auto& bodyCodes = *(++it); | ||
1631 | _buf << "function("sv << | ||
1632 | (isFatArrow ? s("self, "sv) : Empty) << | ||
1633 | args << ')'; | ||
1634 | if (!initArgs.empty() || !bodyCodes.empty()) { | ||
1635 | _buf << nlr(argsDef) << initArgs << bodyCodes; | ||
1636 | popScope(); | ||
1637 | _buf << indent() << "end"sv; | ||
1638 | } else { | ||
1639 | popScope(); | ||
1640 | _buf << " end"sv; | ||
1641 | } | ||
1642 | } else { | ||
1643 | if (funLit->body) { | ||
1644 | transformBody(funLit->body, temp, true); | ||
1645 | } else { | ||
1646 | temp.push_back(Empty); | ||
1647 | } | ||
1648 | auto& bodyCodes = temp.back(); | ||
1649 | _buf << "function("sv << | ||
1650 | (isFatArrow ? s("self"sv) : Empty) << | ||
1651 | ')'; | ||
1652 | if (!bodyCodes.empty()) { | ||
1653 | _buf << nll(funLit) << bodyCodes; | ||
1654 | popScope(); | ||
1655 | _buf << indent() << "end"sv; | ||
1656 | } else { | ||
1657 | popScope(); | ||
1658 | _buf << " end"sv; | ||
1659 | } | ||
1660 | } | ||
1661 | out.push_back(clearBuf()); | ||
1662 | } | ||
1663 | |||
1664 | void transformCodes(const node_container& nodes, str_list& out, bool implicitReturn) { | ||
1665 | LocalMode mode = LocalMode::None; | ||
1666 | Local_t* any = nullptr, *capital = nullptr; | ||
1667 | for (auto node : nodes) { | ||
1668 | auto stmt = static_cast<Statement_t*>(node); | ||
1669 | if (auto local = stmt->content.as<Local_t>()) { | ||
1670 | if (auto flag = local->name.as<local_flag_t>()) { | ||
1671 | LocalMode newMode = toString(flag) == "*"sv ? LocalMode::Any : LocalMode::Capital; | ||
1672 | if (int(newMode) > int(mode)) { | ||
1673 | mode = newMode; | ||
1674 | } | ||
1675 | if (mode == LocalMode::Any) { | ||
1676 | if (!any) any = local; | ||
1677 | if (!capital) capital = local; | ||
1678 | } else { | ||
1679 | if (!capital) capital = local; | ||
1680 | } | ||
1681 | } else { | ||
1682 | auto names = local->name.to<NameList_t>(); | ||
1683 | for (auto name : names->names.objects()) { | ||
1684 | local->forceDecls.push_back(toString(name)); | ||
1685 | } | ||
1686 | } | ||
1687 | } else if (mode != LocalMode::None) { | ||
1688 | ClassDecl_t* classDecl = nullptr; | ||
1689 | if (auto assignment = assignmentFrom(stmt)) { | ||
1690 | auto vars = getAssignVars(assignment); | ||
1691 | for (const auto& var : vars) { | ||
1692 | if (var.empty()) continue; | ||
1693 | if (std::isupper(var[0]) && capital) { | ||
1694 | capital->decls.push_back(var); | ||
1695 | } else if (any) { | ||
1696 | any->decls.push_back(var); | ||
1697 | } | ||
1698 | } | ||
1699 | auto info = extractDestructureInfo(assignment); | ||
1700 | if (!info.first.empty()) { | ||
1701 | for (const auto& destruct : info.first) | ||
1702 | for (const auto& item : destruct.items) | ||
1703 | if (item.isVariable) { | ||
1704 | if (std::isupper(item.name[0]) && capital) { capital->decls.push_back(item.name); | ||
1705 | } else if (any) { | ||
1706 | any->decls.push_back(item.name); | ||
1707 | } | ||
1708 | } | ||
1709 | } | ||
1710 | BLOCK_START | ||
1711 | auto assign = assignment->action.as<Assign_t>(); | ||
1712 | BREAK_IF(!assign); | ||
1713 | BREAK_IF(assign->values.objects().size() != 1); | ||
1714 | auto exp = ast_cast<Exp_t>(assign->values.objects().front()); | ||
1715 | BREAK_IF(!exp); | ||
1716 | auto value = singleValueFrom(exp); | ||
1717 | classDecl = value->getByPath<SimpleValue_t, ClassDecl_t>(); | ||
1718 | BLOCK_END | ||
1719 | } else if (auto expList = expListFrom(stmt)) { | ||
1720 | auto value = singleValueFrom(expList); | ||
1721 | classDecl = value->getByPath<SimpleValue_t, ClassDecl_t>(); | ||
1722 | } | ||
1723 | if (classDecl) { | ||
1724 | if (auto variable = classDecl->name->item.as<Variable_t>()) { | ||
1725 | auto className = toString(variable); | ||
1726 | if (!className.empty()) { | ||
1727 | if (std::isupper(className[0]) && capital) { | ||
1728 | capital->decls.push_back(className); | ||
1729 | } else if (any) { | ||
1730 | any->decls.push_back(className); | ||
1731 | } | ||
1732 | } | ||
1733 | } | ||
1734 | } | ||
1735 | } | ||
1736 | } | ||
1737 | if (implicitReturn) { | ||
1738 | auto last = static_cast<Statement_t*>(nodes.back()); | ||
1739 | auto x = last; | ||
1740 | BLOCK_START | ||
1741 | auto expList = expListFrom(last); | ||
1742 | BREAK_IF(!expList || | ||
1743 | (last->appendix && | ||
1744 | last->appendix->item.is<CompInner_t>())); | ||
1745 | auto expListLow = x->new_ptr<ExpListLow_t>(); | ||
1746 | expListLow->exprs.dup(expList->exprs); | ||
1747 | auto returnNode = x->new_ptr<Return_t>(); | ||
1748 | returnNode->valueList.set(expListLow); | ||
1749 | last->content.set(returnNode); | ||
1750 | BLOCK_END | ||
1751 | } | ||
1752 | str_list temp; | ||
1753 | for (auto node : nodes) { | ||
1754 | transformStatement(static_cast<Statement_t*>(node), temp); | ||
1755 | } | ||
1756 | out.push_back(join(temp)); | ||
1757 | } | ||
1758 | |||
1759 | void transformBody(Body_t* body, str_list& out, bool implicitReturn = false) { | ||
1760 | if (auto stmt = body->content.as<Statement_t>()) { | ||
1761 | transformCodes(node_container{stmt}, out, implicitReturn); | ||
1762 | } else { | ||
1763 | transformCodes(body->content.to<Block_t>()->statements.objects(), out, implicitReturn); | ||
1764 | } | ||
1765 | } | ||
1766 | |||
1767 | void transformBlock(Block_t* block, str_list& out, bool implicitReturn = true) { | ||
1768 | transformCodes(block->statements.objects(), out, implicitReturn); | ||
1769 | } | ||
1770 | |||
1771 | void transformReturn(Return_t* returnNode, str_list& out) { | ||
1772 | if (auto valueList = returnNode->valueList.get()) { | ||
1773 | if (auto singleValue = singleValueFrom(valueList)) { | ||
1774 | if (auto simpleValue = singleValue->item.as<SimpleValue_t>()) { | ||
1775 | auto value = simpleValue->value.get(); | ||
1776 | switch (value->getId()) { | ||
1777 | case "Comprehension"_id: | ||
1778 | transformCompReturn(static_cast<Comprehension_t*>(value), out); | ||
1779 | return; | ||
1780 | case "TblComprehension"_id: | ||
1781 | transformTblCompReturn(static_cast<TblComprehension_t*>(value), out); | ||
1782 | return; | ||
1783 | case "With"_id: | ||
1784 | transformWith(static_cast<With_t*>(value), out, nullptr, true); | ||
1785 | return; | ||
1786 | case "ClassDecl"_id: | ||
1787 | transformClassDecl(static_cast<ClassDecl_t*>(value), out, ExpUsage::Return); | ||
1788 | return; | ||
1789 | case "Do"_id: | ||
1790 | transformDo(static_cast<Do_t*>(value), out, true); | ||
1791 | return; | ||
1792 | case "Switch"_id: | ||
1793 | transformSwitch(static_cast<Switch_t*>(value), out, true); | ||
1794 | return; | ||
1795 | case "While"_id: | ||
1796 | transformWhileInPlace(static_cast<While_t*>(value), out); | ||
1797 | return; | ||
1798 | case "For"_id: | ||
1799 | transformForInPlace(static_cast<For_t*>(value), out); | ||
1800 | return; | ||
1801 | case "ForEach"_id: | ||
1802 | transformForEachInPlace(static_cast<ForEach_t*>(value), out); | ||
1803 | return; | ||
1804 | case "If"_id: | ||
1805 | transformIf(static_cast<If_t*>(value), out, ExpUsage::Return); | ||
1806 | return; | ||
1807 | case "Unless"_id: | ||
1808 | transformUnless(static_cast<Unless_t*>(value), out, ExpUsage::Return); | ||
1809 | return; | ||
1810 | } | ||
1811 | } | ||
1812 | if (auto chainValue = singleValue->item.as<ChainValue_t>()) { | ||
1813 | if (isColonChain(chainValue)) { | ||
1814 | transformColonChain(chainValue, out, ExpUsage::Return); | ||
1815 | } else { | ||
1816 | transformChainValue(chainValue, out, ExpUsage::Return); | ||
1817 | } | ||
1818 | return; | ||
1819 | } | ||
1820 | transformValue(singleValue, out); | ||
1821 | out.back() = indent() + s("return "sv) + out.back() + nlr(returnNode); | ||
1822 | return; | ||
1823 | } else { | ||
1824 | str_list temp; | ||
1825 | transformExpListLow(valueList, temp); | ||
1826 | out.push_back(indent() + s("return "sv) + temp.back() + nlr(returnNode)); | ||
1827 | } | ||
1828 | } else { | ||
1829 | out.push_back(indent() + s("return"sv) + nll(returnNode)); | ||
1830 | } | ||
1831 | } | ||
1832 | |||
1833 | void transformFnArgsDef(FnArgsDef_t* argsDef, str_list& out) { | ||
1834 | if (!argsDef->defList) { | ||
1835 | out.push_back(Empty); | ||
1836 | out.push_back(Empty); | ||
1837 | } else { | ||
1838 | transformFnArgDefList(argsDef->defList, out); | ||
1839 | } | ||
1840 | if (argsDef->shadowOption) { | ||
1841 | transform_outer_var_shadow(argsDef->shadowOption); | ||
1842 | } | ||
1843 | } | ||
1844 | |||
1845 | void transform_outer_var_shadow(outer_var_shadow_t* shadow) { | ||
1846 | markVarShadowed(); | ||
1847 | if (shadow->varList) { | ||
1848 | for (auto name : shadow->varList->names.objects()) { | ||
1849 | addToAllowList(toString(name)); | ||
1850 | } | ||
1851 | } | ||
1852 | } | ||
1853 | |||
1854 | void transformFnArgDefList(FnArgDefList_t* argDefList, str_list& out) { | ||
1855 | auto x = argDefList; | ||
1856 | struct ArgItem { | ||
1857 | std::string name; | ||
1858 | std::string assignSelf; | ||
1859 | }; | ||
1860 | std::list<ArgItem> argItems; | ||
1861 | str_list temp; | ||
1862 | std::string varNames; | ||
1863 | bool assignSelf = false; | ||
1864 | for (auto _def : argDefList->definitions.objects()) { | ||
1865 | auto def = static_cast<FnArgDef_t*>(_def); | ||
1866 | auto& arg = argItems.emplace_back(); | ||
1867 | switch (def->name->getId()) { | ||
1868 | case "Variable"_id: arg.name = toString(def->name); break; | ||
1869 | case "SelfName"_id: { | ||
1870 | assignSelf = true; | ||
1871 | auto selfName = static_cast<SelfName_t*>(def->name.get()); | ||
1872 | switch (selfName->name->getId()) { | ||
1873 | case "self_class_name"_id: { | ||
1874 | auto clsName = static_cast<self_class_name_t*>(selfName->name.get()); | ||
1875 | arg.name = toString(clsName->name); | ||
1876 | arg.assignSelf = s("self.__class."sv) + arg.name; | ||
1877 | break; | ||
1878 | } | ||
1879 | case "self_class"_id: | ||
1880 | arg.name = "self.__class"sv; | ||
1881 | break; | ||
1882 | case "self_name"_id: { | ||
1883 | |||
1884 | auto sfName = static_cast<self_name_t*>(selfName->name.get()); | ||
1885 | arg.name = toString(sfName->name); | ||
1886 | arg.assignSelf = s("self."sv) + arg.name; | ||
1887 | break; | ||
1888 | } | ||
1889 | case "self"_id: | ||
1890 | arg.name = "self"sv; | ||
1891 | break; | ||
1892 | default: break; | ||
1893 | } | ||
1894 | break; | ||
1895 | } | ||
1896 | } | ||
1897 | forceAddToScope(arg.name); | ||
1898 | if (def->defaultValue) { | ||
1899 | pushScope(); | ||
1900 | auto expList = toAst<ExpList_t>(arg.name, ExpList, x); | ||
1901 | auto assign = x->new_ptr<Assign_t>(); | ||
1902 | assign->values.push_back(def->defaultValue.get()); | ||
1903 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
1904 | assignment->expList.set(expList); | ||
1905 | assignment->action.set(assign); | ||
1906 | transformAssignment(assignment, temp); | ||
1907 | popScope(); | ||
1908 | _buf << indent() << "if "sv << arg.name << " == nil then"sv << nll(def); | ||
1909 | _buf << temp.back(); | ||
1910 | _buf << indent() << "end"sv << nll(def); | ||
1911 | temp.back() = clearBuf(); | ||
1912 | } | ||
1913 | if (varNames.empty()) varNames = arg.name; | ||
1914 | else varNames.append(s(", "sv) + arg.name); | ||
1915 | } | ||
1916 | if (argDefList->varArg) { | ||
1917 | auto& arg = argItems.emplace_back(); | ||
1918 | arg.name = "..."sv; | ||
1919 | if (varNames.empty()) varNames = arg.name; | ||
1920 | else varNames.append(s(", "sv) + arg.name); | ||
1921 | } | ||
1922 | std::string initCodes = join(temp); | ||
1923 | if (assignSelf) { | ||
1924 | auto sjoin = [](const decltype(argItems)& items, int index) { | ||
1925 | std::string result; | ||
1926 | for (auto it = items.begin(); it != items.end(); ++it) { | ||
1927 | if (it->assignSelf.empty()) continue; | ||
1928 | if (result.empty()) result = (&it->name)[index]; | ||
1929 | else result.append(s(", "sv) + (&it->name)[index]); | ||
1930 | } | ||
1931 | return result; | ||
1932 | }; | ||
1933 | std::string sleft = sjoin(argItems, 1); | ||
1934 | std::string sright = sjoin(argItems, 0); | ||
1935 | initCodes.append(indent() + sleft + s(" = "sv) + sright + nll(argDefList)); | ||
1936 | } | ||
1937 | out.push_back(varNames); | ||
1938 | out.push_back(initCodes); | ||
1939 | } | ||
1940 | |||
1941 | void transformSelfName(SelfName_t* selfName, str_list& out, bool invoke) { | ||
1942 | auto name = selfName->name.get(); | ||
1943 | switch (name->getId()) { | ||
1944 | case "self_class_name"_id: { | ||
1945 | auto clsName = static_cast<self_class_name_t*>(name); | ||
1946 | out.push_back(s("self.__class"sv) + s(invoke ? ":"sv : "."sv) + toString(clsName->name)); | ||
1947 | break; | ||
1948 | } | ||
1949 | case "self_class"_id: | ||
1950 | out.push_back(s("self.__class"sv)); | ||
1951 | break; | ||
1952 | case "self_name"_id: { | ||
1953 | auto sfName = static_cast<self_class_name_t*>(name); | ||
1954 | out.push_back(s("self"sv) + s(invoke ? ":"sv : "."sv) + toString(sfName->name)); | ||
1955 | break; | ||
1956 | } | ||
1957 | case "self"_id: | ||
1958 | out.push_back(s("self"sv)); | ||
1959 | break; | ||
1960 | } | ||
1961 | } | ||
1962 | |||
1963 | void transformColonChainClosure(ChainValue_t* chainValue, str_list& out) { | ||
1964 | str_list temp; | ||
1965 | temp.push_back(s("(function()"sv) + nll(chainValue)); | ||
1966 | pushScope(); | ||
1967 | transformColonChain(chainValue, temp, ExpUsage::Return); | ||
1968 | popScope(); | ||
1969 | temp.push_back(indent() + s("end)()"sv)); | ||
1970 | out.push_back(join(temp)); | ||
1971 | } | ||
1972 | |||
1973 | void transformColonChain(ChainValue_t* chainValue, str_list& out, ExpUsage usage = ExpUsage::Common, ExpList_t* expList = nullptr) { | ||
1974 | auto x = chainValue; | ||
1975 | const auto& chainList = chainValue->items.objects(); | ||
1976 | auto baseChain = x->new_ptr<ChainValue_t>(); | ||
1977 | switch (chainList.front()->getId()) { | ||
1978 | case "DotChainItem"_id: | ||
1979 | case "ColonChainItem"_id: | ||
1980 | if (_withVars.empty()) { | ||
1981 | throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, chainList.front())); | ||
1982 | } else { | ||
1983 | baseChain->items.push_back(toAst<Callable_t>(_withVars.top(), Callable, x)); | ||
1984 | } | ||
1985 | break; | ||
1986 | } | ||
1987 | auto end = --chainList.end(); | ||
1988 | for (auto it = chainList.begin(); it != end; ++it) { | ||
1989 | baseChain->items.push_back(*it); | ||
1990 | } | ||
1991 | auto colonChainItem = static_cast<ColonChainItem_t*>(chainList.back()); | ||
1992 | auto funcName = toString(colonChainItem->name); | ||
1993 | if (usage != ExpUsage::Return) pushScope(); | ||
1994 | auto baseVar = getUnusedName("_base_"sv); | ||
1995 | auto fnVar = getUnusedName("_fn_"sv); | ||
1996 | str_list temp; | ||
1997 | { | ||
1998 | auto value = x->new_ptr<Value_t>(); | ||
1999 | value->item.set(baseChain); | ||
2000 | auto exp = x->new_ptr<Exp_t>(); | ||
2001 | exp->value.set(value); | ||
2002 | auto assign = x->new_ptr<Assign_t>(); | ||
2003 | assign->values.push_back(exp); | ||
2004 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
2005 | assignment->expList.set(toAst<ExpList_t>(baseVar, ExpList, x)); | ||
2006 | assignment->action.set(assign); | ||
2007 | transformAssignment(assignment, temp); | ||
2008 | } | ||
2009 | { | ||
2010 | auto assign = x->new_ptr<Assign_t>(); | ||
2011 | assign->values.push_back(toAst<Exp_t>(baseVar + "." + funcName, Exp, x)); | ||
2012 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
2013 | assignment->expList.set(toAst<ExpList_t>(fnVar, ExpList, x)); | ||
2014 | assignment->action.set(assign); | ||
2015 | transformAssignment(assignment, temp); | ||
2016 | } | ||
2017 | auto funLit = toAst<Exp_t>(s("(...)-> "sv) + fnVar + s(" "sv) + baseVar + s(", ..."sv), Exp, x); | ||
2018 | switch (usage) { | ||
2019 | case ExpUsage::Return: | ||
2020 | transformExp(funLit, temp); | ||
2021 | _buf << temp.front(); | ||
2022 | _buf << *(++temp.begin()); | ||
2023 | _buf << indent() << "return " << temp.back() << nll(chainValue); | ||
2024 | break; | ||
2025 | case ExpUsage::Assignment: { | ||
2026 | auto assign = x->new_ptr<Assign_t>(); | ||
2027 | assign->values.push_back(funLit); | ||
2028 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
2029 | assignment->expList.set(expList); | ||
2030 | assignment->action.set(assign); | ||
2031 | transformAssignment(assignment, temp); | ||
2032 | _buf << indent(-1) << "do"sv << nll(chainValue); | ||
2033 | _buf << temp.front(); | ||
2034 | _buf << *(++temp.begin()); | ||
2035 | _buf << temp.back(); | ||
2036 | popScope(); | ||
2037 | _buf << indent() << "end"sv << nll(chainValue); | ||
2038 | break; | ||
2039 | } | ||
2040 | case ExpUsage::Common: { | ||
2041 | auto assign = x->new_ptr<Assign_t>(); | ||
2042 | assign->values.push_back(funLit); | ||
2043 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
2044 | assignment->expList.set(toAst<ExpList_t>("_"sv, ExpList, x)); | ||
2045 | assignment->action.set(assign); | ||
2046 | transformAssignment(assignment, temp); | ||
2047 | _buf << indent(-1) << "do"sv << nll(chainValue); | ||
2048 | _buf << temp.front(); | ||
2049 | _buf << *(++temp.begin()); | ||
2050 | _buf << temp.back(); | ||
2051 | popScope(); | ||
2052 | _buf << indent() << "end"sv << nll(chainValue); | ||
2053 | break; | ||
2054 | } | ||
2055 | default: break; | ||
2056 | } | ||
2057 | out.push_back(clearBuf()); | ||
2058 | } | ||
2059 | |||
2060 | void transformChainList(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { | ||
2061 | auto x = chainList.front(); | ||
2062 | str_list temp; | ||
2063 | switch (chainList.front()->getId()) { | ||
2064 | case "DotChainItem"_id: | ||
2065 | case "ColonChainItem"_id: | ||
2066 | if (_withVars.empty()) { | ||
2067 | throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, chainList.front())); | ||
2068 | } else { | ||
2069 | temp.push_back(_withVars.top()); | ||
2070 | } | ||
2071 | break; | ||
2072 | } | ||
2073 | for (auto it = chainList.begin(); it != chainList.end(); ++it) { | ||
2074 | auto item = *it; | ||
2075 | switch (item->getId()) { | ||
2076 | case "Invoke"_id: | ||
2077 | transformInvoke(static_cast<Invoke_t*>(item), temp); | ||
2078 | break; | ||
2079 | case "DotChainItem"_id: | ||
2080 | transformDotChainItem(static_cast<DotChainItem_t*>(item), temp); | ||
2081 | break; | ||
2082 | case "ColonChainItem"_id: { | ||
2083 | auto colonItem = static_cast<ColonChainItem_t*>(item); | ||
2084 | auto next = it; ++next; | ||
2085 | auto followItem = next != chainList.end() ? *next : nullptr; | ||
2086 | if (!ast_is<Invoke_t, InvokeArgs_t>(followItem)) { | ||
2087 | throw std::logic_error(debugInfo("Colon chain item must be followed by invoke arguments."sv, colonItem)); | ||
2088 | } | ||
2089 | if (colonItem->name.is<LuaKeyword_t>()) { | ||
2090 | std::string callVar; | ||
2091 | auto block = x->new_ptr<Block_t>(); | ||
2092 | { | ||
2093 | auto chainValue = x->new_ptr<ChainValue_t>(); | ||
2094 | switch (chainList.front()->getId()) { | ||
2095 | case "DotChainItem"_id: | ||
2096 | case "ColonChainItem"_id: | ||
2097 | chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), Callable, x)); | ||
2098 | break; | ||
2099 | } | ||
2100 | for (auto i = chainList.begin(); i != it; ++i) { | ||
2101 | chainValue->items.push_back(*i); | ||
2102 | } | ||
2103 | auto value = x->new_ptr<Value_t>(); | ||
2104 | value->item.set(chainValue); | ||
2105 | auto exp = x->new_ptr<Exp_t>(); | ||
2106 | exp->value.set(value); | ||
2107 | callVar = singleVariableFrom(exp); | ||
2108 | if (callVar.empty()) { | ||
2109 | callVar = getUnusedName(s("_call_"sv)); | ||
2110 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
2111 | assignment->expList.set(toAst<ExpList_t>(callVar, ExpList, x)); | ||
2112 | auto assign = x->new_ptr<Assign_t>(); | ||
2113 | assign->values.push_back(exp); | ||
2114 | assignment->action.set(assign); | ||
2115 | auto stmt = x->new_ptr<Statement_t>(); | ||
2116 | stmt->content.set(assignment); | ||
2117 | block->statements.push_back(stmt); | ||
2118 | } | ||
2119 | } | ||
2120 | { | ||
2121 | auto name = toString(colonItem->name); | ||
2122 | auto chainValue = x->new_ptr<ChainValue_t>(); | ||
2123 | chainValue->items.push_back(toAst<Callable_t>(callVar, Callable, x)); | ||
2124 | chainValue->items.push_back(toAst<Exp_t>(s("\""sv) + name + s("\""sv), Exp, x)); | ||
2125 | if (auto invoke = ast_cast<Invoke_t>(followItem)) { | ||
2126 | invoke->args.push_front(toAst<Exp_t>(callVar, Exp, x)); | ||
2127 | } else { | ||
2128 | auto invokeArgs = static_cast<InvokeArgs_t*>(followItem); | ||
2129 | invokeArgs->args.push_front(toAst<Exp_t>(callVar, Exp, x)); | ||
2130 | } | ||
2131 | chainValue->items.push_back(followItem); | ||
2132 | for (auto i = ++next; i != chainList.end(); ++i) { | ||
2133 | chainValue->items.push_back(*i); | ||
2134 | } | ||
2135 | auto value = x->new_ptr<Value_t>(); | ||
2136 | value->item.set(chainValue); | ||
2137 | auto exp = x->new_ptr<Exp_t>(); | ||
2138 | exp->value.set(value); | ||
2139 | auto expList = x->new_ptr<ExpList_t>(); | ||
2140 | expList->exprs.push_back(exp); | ||
2141 | auto expListAssign = x->new_ptr<ExpListAssign_t>(); | ||
2142 | expListAssign->expList.set(expList); | ||
2143 | auto stmt = x->new_ptr<Statement_t>(); | ||
2144 | stmt->content.set(expListAssign); | ||
2145 | block->statements.push_back(stmt); | ||
2146 | } | ||
2147 | switch (usage) { | ||
2148 | case ExpUsage::Common: | ||
2149 | transformBlock(block, out, false); | ||
2150 | return; | ||
2151 | case ExpUsage::Return: | ||
2152 | transformBlock(block, out, true); | ||
2153 | return; | ||
2154 | case ExpUsage::Assignment: { | ||
2155 | auto body = x->new_ptr<Body_t>(); | ||
2156 | body->content.set(block); | ||
2157 | assignLastExplist(assignList, body); | ||
2158 | transformBlock(block, out); | ||
2159 | return; | ||
2160 | } | ||
2161 | default: | ||
2162 | break; | ||
2163 | } | ||
2164 | auto body = x->new_ptr<Body_t>(); | ||
2165 | body->content.set(block); | ||
2166 | auto funLit = toAst<FunLit_t>("->"sv, FunLit, x); | ||
2167 | funLit->body.set(body); | ||
2168 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
2169 | simpleValue->value.set(funLit); | ||
2170 | auto value = x->new_ptr<Value_t>(); | ||
2171 | value->item.set(simpleValue); | ||
2172 | auto exp = x->new_ptr<Exp_t>(); | ||
2173 | exp->value.set(value); | ||
2174 | auto paren = x->new_ptr<Parens_t>(); | ||
2175 | paren->expr.set(exp); | ||
2176 | auto callable = x->new_ptr<Callable_t>(); | ||
2177 | callable->item.set(paren); | ||
2178 | auto chainValue = x->new_ptr<ChainValue_t>(); | ||
2179 | chainValue->items.push_back(callable); | ||
2180 | auto invoke = x->new_ptr<Invoke_t>(); | ||
2181 | chainValue->items.push_back(invoke); | ||
2182 | transformChainValue(chainValue, out); | ||
2183 | return; | ||
2184 | } | ||
2185 | transformColonChainItem(colonItem, temp); | ||
2186 | break; | ||
2187 | } | ||
2188 | case "Slice"_id: | ||
2189 | transformSlice(static_cast<Slice_t*>(item), temp); | ||
2190 | break; | ||
2191 | case "Callable"_id: { | ||
2192 | auto next = it; ++next; | ||
2193 | auto followItem = next != chainList.end() ? *next : nullptr; | ||
2194 | transformCallable(static_cast<Callable_t*>(item), temp, | ||
2195 | followItem && ast_is<Invoke_t, InvokeArgs_t>(followItem)); | ||
2196 | break; | ||
2197 | } | ||
2198 | case "String"_id: | ||
2199 | transformString(static_cast<String_t*>(item), temp); | ||
2200 | temp.back() = s("("sv) + temp.back() + s(")"sv); | ||
2201 | break; | ||
2202 | case "Exp"_id: | ||
2203 | transformExp(static_cast<Exp_t*>(item), temp); | ||
2204 | temp.back() = s("["sv) + temp.back() + s("]"sv); | ||
2205 | break; | ||
2206 | case "InvokeArgs"_id: transformInvokeArgs(static_cast<InvokeArgs_t*>(item), temp); break; | ||
2207 | default: break; | ||
2208 | } | ||
2209 | } | ||
2210 | switch (usage) { | ||
2211 | case ExpUsage::Common: | ||
2212 | out.push_back(indent() + join(temp) + nll(chainList.front())); | ||
2213 | break; | ||
2214 | case ExpUsage::Return: | ||
2215 | out.push_back(indent() + s("return "sv) + join(temp) + nll(chainList.front())); | ||
2216 | break; | ||
2217 | default: | ||
2218 | out.push_back(join(temp)); | ||
2219 | break; | ||
2220 | } | ||
2221 | } | ||
2222 | |||
2223 | void transformChainValue(ChainValue_t* chainValue, str_list& out, ExpUsage usage = ExpUsage::Closure, ExpList_t* assignList = nullptr) { | ||
2224 | transformChainList(chainValue->items.objects(), out, usage, assignList); | ||
2225 | } | ||
2226 | |||
2227 | void transformAssignableChain(AssignableChain_t* chain, str_list& out) { | ||
2228 | transformChainList(chain->items.objects(), out, ExpUsage::Closure); | ||
2229 | } | ||
2230 | |||
2231 | void transformDotChainItem(DotChainItem_t* dotChainItem, str_list& out) { | ||
2232 | auto name = toString(dotChainItem->name); | ||
2233 | if (State::keywords.find(name) != State::keywords.end()) { | ||
2234 | out.push_back(s("[\""sv) + name + s("\"]"sv)); | ||
2235 | } else { | ||
2236 | out.push_back(s("."sv) + name); | ||
2237 | } | ||
2238 | } | ||
2239 | |||
2240 | void transformColonChainItem(ColonChainItem_t* colonChainItem, str_list& out) { | ||
2241 | auto name = toString(colonChainItem->name); | ||
2242 | out.push_back(s(colonChainItem->switchToDot ? "."sv : ":"sv) + name); | ||
2243 | } | ||
2244 | |||
2245 | void transformSlice(Slice_t* slice, str_list&) { | ||
2246 | throw std::logic_error(debugInfo("Slice syntax not supported here."sv, slice)); | ||
2247 | } | ||
2248 | |||
2249 | void transformInvoke(Invoke_t* invoke, str_list& out) { | ||
2250 | str_list temp; | ||
2251 | for (auto arg : invoke->args.objects()) { | ||
2252 | switch (arg->getId()) { | ||
2253 | case "Exp"_id: transformExp(static_cast<Exp_t*>(arg), temp); break; | ||
2254 | case "SingleString"_id: transformSingleString(static_cast<SingleString_t*>(arg), temp); break; | ||
2255 | case "DoubleString"_id: transformDoubleString(static_cast<DoubleString_t*>(arg), temp); break; | ||
2256 | case "LuaString"_id: transformLuaString(static_cast<LuaString_t*>(arg), temp); break; | ||
2257 | default: break; | ||
2258 | } | ||
2259 | } | ||
2260 | out.push_back(s("("sv) + join(temp, ", "sv) + s(")"sv)); | ||
2261 | } | ||
2262 | |||
2263 | void transform_unary_exp(unary_exp_t* unary_exp, str_list& out) { | ||
2264 | std::string op = toString(unary_exp->m_begin.m_it, unary_exp->item->m_begin.m_it); | ||
2265 | str_list temp{op + (op == "not"sv ? s(" "sv) : Empty)}; | ||
2266 | transformExp(unary_exp->item, temp); | ||
2267 | out.push_back(join(temp)); | ||
2268 | } | ||
2269 | |||
2270 | void transformVariable(Variable_t* name, str_list& out) { | ||
2271 | out.push_back(toString(name)); | ||
2272 | } | ||
2273 | |||
2274 | void transformNum(Num_t* num, str_list& out) { | ||
2275 | out.push_back(toString(num)); | ||
2276 | } | ||
2277 | |||
2278 | void transformTableLit(TableLit_t* table, str_list& out) { | ||
2279 | transformTable(table, table->values.objects(), out); | ||
2280 | } | ||
2281 | |||
2282 | void transformCompCommon(Comprehension_t* comp, str_list& out) { | ||
2283 | str_list temp; | ||
2284 | auto x = comp; | ||
2285 | auto compInner = comp->forLoop.get(); | ||
2286 | for (auto item : compInner->items.objects()) { | ||
2287 | switch (item->getId()) { | ||
2288 | case "CompForEach"_id: | ||
2289 | transformCompForEach(static_cast<CompForEach_t*>(item), temp); | ||
2290 | break; | ||
2291 | case "CompFor"_id: | ||
2292 | transformCompFor(static_cast<CompFor_t*>(item), temp); | ||
2293 | break; | ||
2294 | case "Exp"_id: | ||
2295 | transformExp(static_cast<Exp_t*>(item), temp); | ||
2296 | temp.back() = indent() + s("if "sv) + temp.back() + s(" then"sv) + nll(item); | ||
2297 | pushScope(); | ||
2298 | break; | ||
2299 | } | ||
2300 | } | ||
2301 | if (auto stmt = comp->value.as<Statement_t>()) { | ||
2302 | transformStatement(stmt, temp); | ||
2303 | } else if (auto exp = comp->value.as<Exp_t>()) { | ||
2304 | auto expList = x->new_ptr<ExpList_t>(); | ||
2305 | expList->exprs.push_back(exp); | ||
2306 | auto expListAssign = x->new_ptr<ExpListAssign_t>(); | ||
2307 | expListAssign->expList.set(expList); | ||
2308 | auto statement = x->new_ptr<Statement_t>(); | ||
2309 | statement->content.set(expListAssign); | ||
2310 | transformStatement(statement, temp); | ||
2311 | } | ||
2312 | auto value = temp.back(); | ||
2313 | temp.pop_back(); | ||
2314 | _buf << join(temp) << value; | ||
2315 | for (size_t i = 0; i < compInner->items.objects().size(); ++i) { | ||
2316 | popScope(); | ||
2317 | _buf << indent() << "end"sv << nll(comp); | ||
2318 | } | ||
2319 | out.push_back(clearBuf()); | ||
2320 | } | ||
2321 | |||
2322 | void transformComprehension(Comprehension_t* comp, str_list& out) { | ||
2323 | str_list temp; | ||
2324 | std::string accum = getUnusedName("_accum_"); | ||
2325 | std::string len = getUnusedName("_len_"); | ||
2326 | addToScope(accum); | ||
2327 | addToScope(len); | ||
2328 | auto compInner = comp->forLoop.get(); | ||
2329 | for (auto item : compInner->items.objects()) { | ||
2330 | switch (item->getId()) { | ||
2331 | case "CompForEach"_id: | ||
2332 | transformCompForEach(static_cast<CompForEach_t*>(item), temp); | ||
2333 | break; | ||
2334 | case "CompFor"_id: | ||
2335 | transformCompFor(static_cast<CompFor_t*>(item), temp); | ||
2336 | break; | ||
2337 | case "Exp"_id: | ||
2338 | transformExp(static_cast<Exp_t*>(item), temp); | ||
2339 | temp.back() = indent() + s("if "sv) + temp.back() + s(" then"sv) + nll(item); | ||
2340 | pushScope(); | ||
2341 | break; | ||
2342 | } | ||
2343 | } | ||
2344 | transformExp(comp->value.to<Exp_t>(), temp); | ||
2345 | auto value = temp.back(); | ||
2346 | temp.pop_back(); | ||
2347 | for (size_t i = 0; i < compInner->items.objects().size(); ++i) { | ||
2348 | popScope(); | ||
2349 | } | ||
2350 | _buf << indent() << "local "sv << accum << " = { }"sv << nll(comp); | ||
2351 | _buf << indent() << "local "sv << len << " = 1"sv << nll(comp); | ||
2352 | _buf << join(temp); | ||
2353 | _buf << indent(int(temp.size())) << accum << "["sv << len << "] = "sv << value << nll(comp); | ||
2354 | _buf << indent(int(temp.size())) << len << " = "sv << len << " + 1"sv << nll(comp); | ||
2355 | for (int ind = int(temp.size()) - 1; ind > -1 ; --ind) { | ||
2356 | _buf << indent(ind) << "end"sv << nll(comp); | ||
2357 | } | ||
2358 | out.push_back(accum); | ||
2359 | out.push_back(clearBuf()); | ||
2360 | } | ||
2361 | |||
2362 | void transformCompInPlace(Comprehension_t* comp, ExpList_t* expList, str_list& out) { | ||
2363 | auto x = comp; | ||
2364 | str_list temp; | ||
2365 | auto ind = indent(); | ||
2366 | pushScope(); | ||
2367 | transformComprehension(comp, temp); | ||
2368 | auto assign = x->new_ptr<Assign_t>(); | ||
2369 | assign->values.push_back(toAst<Exp_t>(temp.front(), Exp, x)); | ||
2370 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
2371 | assignment->expList.set(expList); | ||
2372 | assignment->action.set(assign); | ||
2373 | transformAssignment(assignment, temp); | ||
2374 | out.push_back( | ||
2375 | ind + s("do"sv) + nll(comp) + | ||
2376 | *(++temp.begin()) + | ||
2377 | temp.back()); | ||
2378 | popScope(); | ||
2379 | out.back() = out.back() + indent() + s("end"sv) + nlr(comp); | ||
2380 | } | ||
2381 | |||
2382 | void transformCompReturn(Comprehension_t* comp, str_list& out) { | ||
2383 | str_list temp; | ||
2384 | transformComprehension(comp, temp); | ||
2385 | out.push_back(temp.back() + indent() + s("return "sv) + temp.front() + nlr(comp)); | ||
2386 | } | ||
2387 | |||
2388 | void transformCompClosure(Comprehension_t* comp, str_list& out) { | ||
2389 | str_list temp; | ||
2390 | std::string before = s("(function()"sv) + nll(comp); | ||
2391 | pushScope(); | ||
2392 | transformComprehension(comp, temp); | ||
2393 | out.push_back( | ||
2394 | before + | ||
2395 | temp.back() + | ||
2396 | indent() + s("return "sv) + temp.front() + nlr(comp)); | ||
2397 | popScope(); | ||
2398 | out.back() = out.back() + indent() + s("end)()"sv); | ||
2399 | } | ||
2400 | |||
2401 | void transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out) { | ||
2402 | auto x = nameList; | ||
2403 | str_list temp; | ||
2404 | str_list vars; | ||
2405 | str_list varBefore, varAfter; | ||
2406 | std::list<std::pair<ast_node*, ast_ptr<false, ast_node>>> destructPairs; | ||
2407 | for (auto _item : nameList->items.objects()) { | ||
2408 | auto item = static_cast<NameOrDestructure_t*>(_item)->item.get(); | ||
2409 | switch (item->getId()) { | ||
2410 | case "Variable"_id: | ||
2411 | transformVariable(static_cast<Variable_t*>(item), vars); | ||
2412 | varAfter.push_back(vars.back()); | ||
2413 | break; | ||
2414 | case "TableLit"_id: { | ||
2415 | auto desVar = getUnusedName("_des_"sv); | ||
2416 | destructPairs.emplace_back(item, toAst<Exp_t>(desVar, Exp, x)); | ||
2417 | vars.push_back(desVar); | ||
2418 | varAfter.push_back(desVar); | ||
2419 | break; | ||
2420 | } | ||
2421 | default: break; | ||
2422 | } | ||
2423 | } | ||
2424 | switch (loopTarget->getId()) { | ||
2425 | case "star_exp"_id: { | ||
2426 | auto star_exp = static_cast<star_exp_t*>(loopTarget); | ||
2427 | std::string listVar; | ||
2428 | if (_config.reuseVariable) listVar = singleVariableFrom(star_exp->value); | ||
2429 | auto indexVar = getUnusedName("_index_"); | ||
2430 | varAfter.push_back(indexVar); | ||
2431 | auto value = singleValueFrom(star_exp->value); | ||
2432 | if (!value) throw std::logic_error(debugInfo("Invalid star syntax."sv, star_exp)); | ||
2433 | bool endWithSlice = false; | ||
2434 | BLOCK_START | ||
2435 | auto chainValue = value->item.as<ChainValue_t>(); | ||
2436 | BREAK_IF(!chainValue); | ||
2437 | auto chainList = chainValue->items.objects(); | ||
2438 | auto slice = ast_cast<Slice_t>(chainList.back()); | ||
2439 | BREAK_IF(!slice); | ||
2440 | endWithSlice = true; | ||
2441 | if (listVar.empty() && chainList.size() == 2 && | ||
2442 | ast_is<Callable_t>(chainList.front())) { | ||
2443 | transformCallable(static_cast<Callable_t*>(chainList.front()), temp, false); | ||
2444 | listVar = temp.back(); | ||
2445 | temp.pop_back(); | ||
2446 | } | ||
2447 | chainList.pop_back(); | ||
2448 | auto chain = x->new_ptr<ChainValue_t>(); | ||
2449 | for (auto item : chainList) { | ||
2450 | chain->items.push_back(item); | ||
2451 | } | ||
2452 | std::string startValue("1"sv); | ||
2453 | if (auto exp = slice->startValue.as<Exp_t>()) { | ||
2454 | transformExp(exp, temp); | ||
2455 | startValue = temp.back(); | ||
2456 | temp.pop_back(); | ||
2457 | } | ||
2458 | std::string stopValue; | ||
2459 | if (auto exp = slice->stopValue.as<Exp_t>()) { | ||
2460 | transformExp(exp, temp); | ||
2461 | stopValue = temp.back(); | ||
2462 | temp.pop_back(); | ||
2463 | } | ||
2464 | std::string stepValue; | ||
2465 | if (auto exp = slice->stepValue.as<Exp_t>()) { | ||
2466 | transformExp(exp, temp); | ||
2467 | stepValue = temp.back(); | ||
2468 | temp.pop_back(); | ||
2469 | } | ||
2470 | if (listVar.empty()) { | ||
2471 | listVar = getUnusedName("_list_"); | ||
2472 | varBefore.push_back(listVar); | ||
2473 | transformChainValue(chain, temp); | ||
2474 | _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); | ||
2475 | } | ||
2476 | std::string maxVar; | ||
2477 | if (!stopValue.empty()) { | ||
2478 | maxVar = getUnusedName("_max_"); | ||
2479 | varBefore.push_back(maxVar); | ||
2480 | _buf << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList); | ||
2481 | } | ||
2482 | _buf << indent() << "for "sv << indexVar << " = "sv; | ||
2483 | _buf << startValue << ", "sv; | ||
2484 | if (stopValue.empty()) { | ||
2485 | _buf << "#"sv << listVar; | ||
2486 | } else { | ||
2487 | _buf << maxVar << " < 0 and #"sv << listVar <<" + " << maxVar << " or "sv << maxVar; | ||
2488 | } | ||
2489 | if (!stepValue.empty()) { | ||
2490 | _buf << ", "sv << stepValue; | ||
2491 | } | ||
2492 | _buf << " do"sv << nlr(loopTarget); | ||
2493 | _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList); | ||
2494 | out.push_back(clearBuf()); | ||
2495 | BLOCK_END | ||
2496 | bool newListVal = false; | ||
2497 | if (listVar.empty()) { | ||
2498 | newListVal = true; | ||
2499 | listVar = getUnusedName("_list_"); | ||
2500 | varBefore.push_back(listVar); | ||
2501 | } | ||
2502 | if (!endWithSlice) { | ||
2503 | transformExp(star_exp->value, temp); | ||
2504 | if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); | ||
2505 | _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nlr(loopTarget); | ||
2506 | _buf << indent(1) << "local "sv << join(vars) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList); | ||
2507 | out.push_back(clearBuf()); | ||
2508 | } | ||
2509 | break; | ||
2510 | } | ||
2511 | case "Exp"_id: | ||
2512 | transformExp(static_cast<Exp_t*>(loopTarget), temp); | ||
2513 | _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget); | ||
2514 | out.push_back(clearBuf()); | ||
2515 | break; | ||
2516 | case "ExpList"_id: | ||
2517 | transformExpList(static_cast<ExpList_t*>(loopTarget), temp); | ||
2518 | _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget); | ||
2519 | out.push_back(clearBuf()); | ||
2520 | break; | ||
2521 | default: break; | ||
2522 | } | ||
2523 | for (auto& var : varBefore) addToScope(var); | ||
2524 | pushScope(); | ||
2525 | for (auto& var : varAfter) addToScope(var); | ||
2526 | if (!destructPairs.empty()) { | ||
2527 | temp.clear(); | ||
2528 | for (auto& pair : destructPairs) { | ||
2529 | auto sValue = x->new_ptr<SimpleValue_t>(); | ||
2530 | sValue->value.set(pair.first); | ||
2531 | auto value = x->new_ptr<Value_t>(); | ||
2532 | value->item.set(sValue); | ||
2533 | auto exp = x->new_ptr<Exp_t>(); | ||
2534 | exp->value.set(value); | ||
2535 | auto expList = x->new_ptr<ExpList_t>(); | ||
2536 | expList->exprs.push_back(exp); | ||
2537 | auto assign = x->new_ptr<Assign_t>(); | ||
2538 | assign->values.push_back(pair.second); | ||
2539 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
2540 | assignment->expList.set(expList); | ||
2541 | assignment->action.set(assign); | ||
2542 | transformAssignment(assignment, temp); | ||
2543 | } | ||
2544 | out.back().append(join(temp)); | ||
2545 | } | ||
2546 | } | ||
2547 | |||
2548 | void transformCompForEach(CompForEach_t* comp, str_list& out) { | ||
2549 | transformForEachHead(comp->nameList, comp->loopValue, out); | ||
2550 | } | ||
2551 | |||
2552 | void transformInvokeArgs(InvokeArgs_t* invokeArgs, str_list& out) { | ||
2553 | str_list temp; | ||
2554 | for (auto arg : invokeArgs->args.objects()) { | ||
2555 | switch (arg->getId()) { | ||
2556 | case "Exp"_id: transformExp(static_cast<Exp_t*>(arg), temp); break; | ||
2557 | case "TableBlock"_id: transformTableBlock(static_cast<TableBlock_t*>(arg), temp); break; | ||
2558 | default: break; | ||
2559 | } | ||
2560 | } | ||
2561 | out.push_back(s("("sv) + join(temp, ", "sv) + s(")"sv)); | ||
2562 | } | ||
2563 | |||
2564 | void transformForHead(For_t* forNode, str_list& out) { | ||
2565 | str_list temp; | ||
2566 | std::string varName = toString(forNode->varName); | ||
2567 | transformExp(forNode->startValue, temp); | ||
2568 | transformExp(forNode->stopValue, temp); | ||
2569 | if (forNode->stepValue) { | ||
2570 | transformExp(forNode->stepValue->value, temp); | ||
2571 | } else { | ||
2572 | temp.emplace_back(); | ||
2573 | } | ||
2574 | auto it = temp.begin(); | ||
2575 | const auto& start = *it; | ||
2576 | const auto& stop = *(++it); | ||
2577 | const auto& step = *(++it); | ||
2578 | _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : s(", "sv) + step) << " do"sv << nll(forNode); | ||
2579 | pushScope(); | ||
2580 | addToScope(varName); | ||
2581 | out.push_back(clearBuf()); | ||
2582 | } | ||
2583 | |||
2584 | void transformLoopBody(Body_t* body, str_list& out, const std::string& appendContent) { | ||
2585 | str_list temp; | ||
2586 | bool withContinue = traversal::Stop == body->traverse([&](ast_node* node) { | ||
2587 | switch (node->getId()) { | ||
2588 | case "For"_id: | ||
2589 | case "ForEach"_id: | ||
2590 | return traversal::Return; | ||
2591 | case "BreakLoop"_id: { | ||
2592 | return toString(node) == "continue"sv ? | ||
2593 | traversal::Stop : traversal::Return; | ||
2594 | } | ||
2595 | default: | ||
2596 | return traversal::Continue; | ||
2597 | } | ||
2598 | }); | ||
2599 | if (withContinue) { | ||
2600 | auto continueVar = getUnusedName("_continue_"sv); | ||
2601 | addToScope(continueVar); | ||
2602 | _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); | ||
2603 | _buf << indent() << "repeat"sv << nll(body); | ||
2604 | temp.push_back(clearBuf()); | ||
2605 | _continueVars.push(continueVar); | ||
2606 | pushScope(); | ||
2607 | } | ||
2608 | transformBody(body, temp); | ||
2609 | if (withContinue) { | ||
2610 | if (!appendContent.empty()) { | ||
2611 | _buf << indent() << appendContent; | ||
2612 | } | ||
2613 | _buf << indent() << _continueVars.top() << " = true"sv << nll(body); | ||
2614 | popScope(); | ||
2615 | _buf << indent() << "until true"sv << nlr(body); | ||
2616 | _buf << indent() << "if not "sv << _continueVars.top() << " then"sv << nlr(body); | ||
2617 | _buf << indent(1) << "break"sv << nlr(body); | ||
2618 | _buf << indent() << "end"sv << nlr(body); | ||
2619 | temp.push_back(clearBuf()); | ||
2620 | _continueVars.pop(); | ||
2621 | } else if (!appendContent.empty()) { | ||
2622 | temp.back().append(indent() + appendContent); | ||
2623 | } | ||
2624 | out.push_back(join(temp)); | ||
2625 | } | ||
2626 | |||
2627 | void transformFor(For_t* forNode, str_list& out) { | ||
2628 | str_list temp; | ||
2629 | transformForHead(forNode, temp); | ||
2630 | transformLoopBody(forNode->body, temp, Empty); | ||
2631 | popScope(); | ||
2632 | out.push_back(join(temp) + indent() + s("end"sv) + nlr(forNode)); | ||
2633 | } | ||
2634 | |||
2635 | std::string transformForInner(For_t* forNode, str_list& out) { | ||
2636 | auto x = forNode; | ||
2637 | std::string accum = getUnusedName("_accum_"); | ||
2638 | addToScope(accum); | ||
2639 | std::string len = getUnusedName("_len_"); | ||
2640 | addToScope(len); | ||
2641 | _buf << indent() << "local "sv << accum << " = { }"sv << nll(forNode); | ||
2642 | _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); | ||
2643 | out.push_back(clearBuf()); | ||
2644 | transformForHead(forNode, out); | ||
2645 | auto expList = toAst<ExpList_t>(accum + s("["sv) + len + s("]"sv), ExpList, x); | ||
2646 | assignLastExplist(expList, forNode->body); | ||
2647 | auto lenLine = len + s(" = "sv) + len + s(" + 1"sv) + nlr(forNode->body); | ||
2648 | transformLoopBody(forNode->body, out, lenLine); | ||
2649 | popScope(); | ||
2650 | out.push_back(indent() + s("end"sv) + nlr(forNode)); | ||
2651 | return accum; | ||
2652 | } | ||
2653 | |||
2654 | void transformForClosure(For_t* forNode, str_list& out) { | ||
2655 | str_list temp; | ||
2656 | _buf << "(function()"sv << nll(forNode); | ||
2657 | pushScope(); | ||
2658 | auto accum = transformForInner(forNode, temp); | ||
2659 | temp.push_back(indent() + s("return "sv) + accum + nlr(forNode)); | ||
2660 | popScope(); | ||
2661 | temp.push_back(indent() + s("end)()"sv)); | ||
2662 | out.push_back(join(temp)); | ||
2663 | } | ||
2664 | |||
2665 | void transformForInPlace(For_t* forNode, str_list& out, ExpList_t* assignExpList = nullptr) { | ||
2666 | auto x = forNode; | ||
2667 | str_list temp; | ||
2668 | if (assignExpList) { | ||
2669 | _buf << indent() << "do"sv << nll(forNode); | ||
2670 | pushScope(); | ||
2671 | auto accum = transformForInner(forNode, temp); | ||
2672 | auto assign = x->new_ptr<Assign_t>(); | ||
2673 | assign->values.push_back(toAst<Exp_t>(accum, Exp, x)); | ||
2674 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
2675 | assignment->expList.set(assignExpList); | ||
2676 | assignment->action.set(assign); | ||
2677 | transformAssignment(assignment, temp); | ||
2678 | popScope(); | ||
2679 | temp.push_back(indent() + s("end"sv) + nlr(forNode)); | ||
2680 | } else { | ||
2681 | auto accum = transformForInner(forNode, temp); | ||
2682 | auto returnNode = x->new_ptr<Return_t>(); | ||
2683 | auto expListLow = toAst<ExpListLow_t>(accum, ExpListLow, x); | ||
2684 | returnNode->valueList.set(expListLow); | ||
2685 | transformReturn(returnNode, temp); | ||
2686 | } | ||
2687 | out.push_back(join(temp)); | ||
2688 | } | ||
2689 | |||
2690 | void transformBinaryOperator(BinaryOperator_t* node, str_list& out) { | ||
2691 | auto op = toString(node); | ||
2692 | out.push_back(op == "!="sv ? s("~="sv) : op); | ||
2693 | } | ||
2694 | |||
2695 | void transformForEach(ForEach_t* forEach, str_list& out) { | ||
2696 | str_list temp; | ||
2697 | transformForEachHead(forEach->nameList, forEach->loopValue, temp); | ||
2698 | transformLoopBody(forEach->body, temp, Empty); | ||
2699 | popScope(); | ||
2700 | out.push_back(temp.front() + temp.back() + indent() + s("end"sv) + nlr(forEach)); | ||
2701 | } | ||
2702 | |||
2703 | std::string transformForEachInner(ForEach_t* forEach, str_list& out) { | ||
2704 | auto x = forEach; | ||
2705 | std::string accum = getUnusedName("_accum_"); | ||
2706 | addToScope(accum); | ||
2707 | std::string len = getUnusedName("_len_"); | ||
2708 | addToScope(len); | ||
2709 | _buf << indent() << "local "sv << accum << " = { }"sv << nll(forEach); | ||
2710 | _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); | ||
2711 | out.push_back(clearBuf()); | ||
2712 | transformForEachHead(forEach->nameList, forEach->loopValue, out); | ||
2713 | auto expList = toAst<ExpList_t>(accum + s("["sv) + len + s("]"sv), ExpList, x); | ||
2714 | assignLastExplist(expList, forEach->body); | ||
2715 | auto lenLine = len + s(" = "sv) + len + s(" + 1"sv) + nlr(forEach->body); | ||
2716 | transformLoopBody(forEach->body, out, lenLine); | ||
2717 | popScope(); | ||
2718 | out.push_back(indent() + s("end"sv) + nlr(forEach)); | ||
2719 | return accum; | ||
2720 | } | ||
2721 | |||
2722 | void transformForEachClosure(ForEach_t* forEach, str_list& out) { | ||
2723 | str_list temp; | ||
2724 | _buf << "(function()"sv << nll(forEach); | ||
2725 | pushScope(); | ||
2726 | auto accum = transformForEachInner(forEach, temp); | ||
2727 | temp.push_back(indent() + s("return "sv) + accum + nlr(forEach)); | ||
2728 | popScope(); | ||
2729 | temp.push_back(indent() + s("end)()"sv)); | ||
2730 | out.push_back(join(temp)); | ||
2731 | } | ||
2732 | |||
2733 | void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList = nullptr) { | ||
2734 | auto x = forEach; | ||
2735 | str_list temp; | ||
2736 | if (assignExpList) { | ||
2737 | _buf << indent() << "do"sv << nll(forEach); | ||
2738 | pushScope(); | ||
2739 | auto accum = transformForEachInner(forEach, temp); | ||
2740 | auto assign = x->new_ptr<Assign_t>(); | ||
2741 | assign->values.push_back(toAst<Exp_t>(accum, Exp, x)); | ||
2742 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
2743 | assignment->expList.set(assignExpList); | ||
2744 | assignment->action.set(assign); | ||
2745 | transformAssignment(assignment, temp); | ||
2746 | popScope(); | ||
2747 | temp.push_back(indent() + s("end"sv) + nlr(forEach)); | ||
2748 | } else { | ||
2749 | auto accum = transformForEachInner(forEach, temp); | ||
2750 | auto returnNode = x->new_ptr<Return_t>(); | ||
2751 | auto expListLow = toAst<ExpListLow_t>(accum, ExpListLow, x); | ||
2752 | returnNode->valueList.set(expListLow); | ||
2753 | transformReturn(returnNode, temp); | ||
2754 | } | ||
2755 | out.push_back(join(temp)); | ||
2756 | } | ||
2757 | |||
2758 | void transform_variable_pair(variable_pair_t* pair, str_list& out) { | ||
2759 | auto name = toString(pair->name); | ||
2760 | out.push_back(name + s(" = "sv) + name); | ||
2761 | } | ||
2762 | |||
2763 | void transform_normal_pair(normal_pair_t* pair, str_list& out) { | ||
2764 | auto key = pair->key.get(); | ||
2765 | str_list temp; | ||
2766 | switch (key->getId()) { | ||
2767 | case "KeyName"_id: { | ||
2768 | transformKeyName(static_cast<KeyName_t*>(key), temp); | ||
2769 | if (State::luaKeywords.find(temp.back()) != State::luaKeywords.end()) { | ||
2770 | temp.back() = s("[\""sv) + temp.back() + s("\"]"); | ||
2771 | } | ||
2772 | break; | ||
2773 | } | ||
2774 | case "Exp"_id: | ||
2775 | transformExp(static_cast<Exp_t*>(key), temp); | ||
2776 | temp.back() = s("["sv) + temp.back() + s("]"sv); | ||
2777 | break; | ||
2778 | case "DoubleString"_id: | ||
2779 | transformDoubleString(static_cast<DoubleString_t*>(key), temp); | ||
2780 | temp.back() = s("["sv) + temp.back() + s("]"sv); | ||
2781 | break; | ||
2782 | case "SingleString"_id: transformSingleString(static_cast<SingleString_t*>(key), temp); | ||
2783 | temp.back() = s("["sv) + temp.back() + s("]"sv); | ||
2784 | break; | ||
2785 | default: break; | ||
2786 | } | ||
2787 | auto value = pair->value.get(); | ||
2788 | switch (value->getId()) { | ||
2789 | case "Exp"_id: transformExp(static_cast<Exp_t*>(value), temp); break; | ||
2790 | case "TableBlock"_id: transformTableBlock(static_cast<TableBlock_t*>(value), temp); break; | ||
2791 | default: break; | ||
2792 | } | ||
2793 | out.push_back(temp.front() + s(" = "sv) + temp.back()); | ||
2794 | } | ||
2795 | |||
2796 | void transformKeyName(KeyName_t* keyName, str_list& out) { | ||
2797 | auto name = keyName->name.get(); | ||
2798 | switch (name->getId()) { | ||
2799 | case "SelfName"_id: transformSelfName(static_cast<SelfName_t*>(name), out, false); break; | ||
2800 | case "Name"_id: out.push_back(toString(name)); break; | ||
2801 | default: break; | ||
2802 | } | ||
2803 | } | ||
2804 | |||
2805 | void replace(std::string& str, std::string_view from, std::string_view to) { | ||
2806 | size_t start_pos = 0; | ||
2807 | while((start_pos = str.find(from, start_pos)) != std::string::npos) { | ||
2808 | str.replace(start_pos, from.size(), to); | ||
2809 | start_pos += to.size(); | ||
2810 | } | ||
2811 | } | ||
2812 | |||
2813 | void transformLuaString(LuaString_t* luaString, str_list& out) { | ||
2814 | auto content = toString(luaString->content); | ||
2815 | replace(content, "\r"sv, ""); | ||
2816 | if (content[0] == '\n') content.erase(content.begin()); | ||
2817 | out.push_back(toString(luaString->open) + content + toString(luaString->close)); | ||
2818 | } | ||
2819 | |||
2820 | void transformSingleString(SingleString_t* singleString, str_list& out) { | ||
2821 | auto str = toString(singleString); | ||
2822 | replace(str, "\r"sv, ""); | ||
2823 | replace(str, "\n"sv, "\\n"sv); | ||
2824 | out.push_back(str); | ||
2825 | } | ||
2826 | |||
2827 | void transformDoubleString(DoubleString_t* doubleString, str_list& out) { | ||
2828 | str_list temp; | ||
2829 | for (auto _seg : doubleString->segments.objects()) { | ||
2830 | auto seg = static_cast<double_string_content_t*>(_seg); | ||
2831 | auto content = seg->content.get(); | ||
2832 | switch (content->getId()) { | ||
2833 | case "double_string_inner"_id: { | ||
2834 | auto str = toString(content); | ||
2835 | replace(str, "\r"sv, ""); | ||
2836 | replace(str, "\n"sv, "\\n"sv); | ||
2837 | temp.push_back(s("\""sv) + str + s("\""sv)); | ||
2838 | break; | ||
2839 | } | ||
2840 | case "Exp"_id: | ||
2841 | transformExp(static_cast<Exp_t*>(content), temp); | ||
2842 | temp.back() = s("tostring("sv) + temp.back() + s(")"sv); | ||
2843 | break; | ||
2844 | default: break; | ||
2845 | } | ||
2846 | } | ||
2847 | out.push_back(temp.empty() ? s("\"\""sv) : join(temp, " .. "sv)); | ||
2848 | } | ||
2849 | |||
2850 | void transformString(String_t* string, str_list& out) { | ||
2851 | auto str = string->str.get(); | ||
2852 | switch (str->getId()) { | ||
2853 | case "SingleString"_id: transformSingleString(static_cast<SingleString_t*>(str), out); break; | ||
2854 | case "DoubleString"_id: transformDoubleString(static_cast<DoubleString_t*>(str), out); break; | ||
2855 | case "LuaString"_id: transformLuaString(static_cast<LuaString_t*>(str), out); break; | ||
2856 | default: break; | ||
2857 | } | ||
2858 | } | ||
2859 | |||
2860 | std::pair<std::string,bool> defineClassVariable(Assignable_t* assignable) { | ||
2861 | if (auto variable = assignable->item.as<Variable_t>()) { | ||
2862 | auto name = toString(variable); | ||
2863 | if (addToScope(name)) { | ||
2864 | return {name, true}; | ||
2865 | } else { | ||
2866 | return {name, false}; | ||
2867 | } | ||
2868 | } | ||
2869 | return {Empty, false}; | ||
2870 | } | ||
2871 | |||
2872 | void transformClassDeclClosure(ClassDecl_t* classDecl, str_list& out) { | ||
2873 | str_list temp; | ||
2874 | temp.push_back(s("(function()"sv) + nll(classDecl)); | ||
2875 | pushScope(); | ||
2876 | transformClassDecl(classDecl, temp, ExpUsage::Return); | ||
2877 | popScope(); | ||
2878 | temp.push_back(s("end)()"sv)); | ||
2879 | out.push_back(join(temp)); | ||
2880 | } | ||
2881 | |||
2882 | void transformClassDecl(ClassDecl_t* classDecl, str_list& out, ExpUsage usage = ExpUsage::Common, ExpList_t* expList = nullptr) { | ||
2883 | str_list temp; | ||
2884 | auto x = classDecl; | ||
2885 | auto body = classDecl->body.get(); | ||
2886 | auto assignable = classDecl->name.get(); | ||
2887 | auto extend = classDecl->extend.get(); | ||
2888 | std::string className; | ||
2889 | std::string assignItem; | ||
2890 | if (assignable) { | ||
2891 | if (!isAssignable(assignable)) { | ||
2892 | throw std::logic_error(debugInfo("Left hand expression is not assignable."sv, assignable)); | ||
2893 | } | ||
2894 | bool newDefined = false; | ||
2895 | std::tie(className, newDefined) = defineClassVariable(assignable); | ||
2896 | if (newDefined) { | ||
2897 | temp.push_back(indent() + s("local "sv) + className + nll(classDecl)); | ||
2898 | } | ||
2899 | if (className.empty()) { | ||
2900 | if (auto chain = ast_cast<AssignableChain_t>(assignable->item)) { | ||
2901 | if (auto dotChain = ast_cast<DotChainItem_t>(chain->items.back())) { | ||
2902 | className = s("\""sv) + toString(dotChain->name) + s("\""sv); | ||
2903 | } else if (auto index = ast_cast<Exp_t>(chain->items.back())) { | ||
2904 | if (auto name = index->getByPath<Value_t, String_t>()) { | ||
2905 | transformString(name, temp); | ||
2906 | className = temp.back(); | ||
2907 | temp.pop_back(); | ||
2908 | } | ||
2909 | } | ||
2910 | } | ||
2911 | } else { | ||
2912 | className = s("\""sv) + className + s("\""sv); | ||
2913 | } | ||
2914 | pushScope(); | ||
2915 | transformAssignable(assignable, temp); | ||
2916 | popScope(); | ||
2917 | assignItem = temp.back(); | ||
2918 | temp.pop_back(); | ||
2919 | } else if (expList) { | ||
2920 | auto name = singleVariableFrom(expList); | ||
2921 | if (!name.empty()) { | ||
2922 | className = s("\""sv) + name + s("\""sv); | ||
2923 | } | ||
2924 | } | ||
2925 | temp.push_back(indent() + s("do"sv) + nll(classDecl)); | ||
2926 | pushScope(); | ||
2927 | auto classVar = getUnusedName("_class_"sv); | ||
2928 | addToScope(classVar); | ||
2929 | temp.push_back(indent() + s("local "sv) + classVar + nll(classDecl)); | ||
2930 | if (body) { | ||
2931 | str_list varDefs; | ||
2932 | for (auto item : body->contents.objects()) { | ||
2933 | if (auto statement = ast_cast<Statement_t>(item)) { | ||
2934 | ClassDecl_t* clsDecl = nullptr; | ||
2935 | if (auto assignment = assignmentFrom(statement)) { | ||
2936 | auto names = transformAssignDefs(assignment->expList.get()); | ||
2937 | varDefs.insert(varDefs.end(), names.begin(), names.end()); | ||
2938 | auto info = extractDestructureInfo(assignment); | ||
2939 | if (!info.first.empty()) { | ||
2940 | for (const auto& destruct : info.first) | ||
2941 | for (const auto& item : destruct.items) | ||
2942 | if (item.isVariable && addToScope(item.name)) | ||
2943 | varDefs.push_back(item.name); | ||
2944 | } | ||
2945 | BLOCK_START | ||
2946 | auto assign = assignment->action.as<Assign_t>(); | ||
2947 | BREAK_IF(!assign); | ||
2948 | BREAK_IF(assign->values.objects().size() != 1); | ||
2949 | auto exp = ast_cast<Exp_t>(assign->values.objects().front()); | ||
2950 | BREAK_IF(!exp); | ||
2951 | auto value = singleValueFrom(exp); | ||
2952 | clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>(); | ||
2953 | BLOCK_END | ||
2954 | } else if (auto expList = expListFrom(statement)) { | ||
2955 | auto value = singleValueFrom(expList); | ||
2956 | clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>(); | ||
2957 | } | ||
2958 | if (clsDecl) { | ||
2959 | std::string clsName; | ||
2960 | bool newDefined = false; | ||
2961 | std::tie(clsName,newDefined) = defineClassVariable(clsDecl->name); | ||
2962 | if (newDefined) varDefs.push_back(clsName); | ||
2963 | } | ||
2964 | } | ||
2965 | } | ||
2966 | if (!varDefs.empty()) { | ||
2967 | temp.push_back(indent() + s("local ") + join(varDefs, ", "sv) + nll(body)); | ||
2968 | } | ||
2969 | } | ||
2970 | std::string parent, parentVar; | ||
2971 | if (extend) { | ||
2972 | parentVar = getUnusedName("_parent_"sv); | ||
2973 | addToScope(parentVar); | ||
2974 | transformExp(extend, temp); | ||
2975 | parent = temp.back(); | ||
2976 | temp.pop_back(); | ||
2977 | temp.push_back(indent() + s("local "sv) + parentVar + s(" = "sv) + parent + nll(classDecl)); | ||
2978 | } | ||
2979 | auto baseVar = getUnusedName("_base_"sv); | ||
2980 | addToScope(baseVar); | ||
2981 | temp.push_back(indent() + s("local "sv) + baseVar + s(" = "sv)); | ||
2982 | str_list builtins; | ||
2983 | str_list commons; | ||
2984 | str_list statements; | ||
2985 | if (body) { | ||
2986 | std::list<ClassMember> members; | ||
2987 | for (auto content : classDecl->body->contents.objects()) { | ||
2988 | switch (content->getId()) { | ||
2989 | case "class_member_list"_id: { | ||
2990 | size_t inc = transform_class_member_list(static_cast<class_member_list_t*>(content), members, classVar); | ||
2991 | auto it = members.end(); | ||
2992 | for (size_t i = 0; i < inc; ++i, --it); | ||
2993 | for (; it != members.end(); ++it) { | ||
2994 | auto& member = *it; | ||
2995 | if (member.type == MemType::Property) { | ||
2996 | statements.push_back(indent() + member.item + nll(content)); | ||
2997 | } else { | ||
2998 | member.item = indent(1) + member.item; | ||
2999 | } | ||
3000 | } | ||
3001 | break; | ||
3002 | } | ||
3003 | case "Statement"_id: | ||
3004 | transformStatement(static_cast<Statement_t*>(content), statements); | ||
3005 | break; | ||
3006 | default: break; | ||
3007 | } | ||
3008 | } | ||
3009 | for (auto& member : members) { | ||
3010 | switch (member.type) { | ||
3011 | case MemType::Common: | ||
3012 | commons.push_back((commons.empty() ? Empty : s(","sv) + nll(member.node)) + member.item); | ||
3013 | break; | ||
3014 | case MemType::Builtin: | ||
3015 | builtins.push_back((builtins.empty() ? Empty : s(","sv) + nll(member.node)) + member.item); | ||
3016 | break; | ||
3017 | default: break; | ||
3018 | } | ||
3019 | } | ||
3020 | if (!commons.empty()) { | ||
3021 | temp.back() += s("{"sv) + nll(body); | ||
3022 | temp.push_back(join(commons) + nll(body)); | ||
3023 | temp.push_back(indent() + s("}"sv) + nll(body)); | ||
3024 | } else { | ||
3025 | temp.back() += s("{ }"sv) + nll(body); | ||
3026 | } | ||
3027 | } else { | ||
3028 | temp.back() += s("{ }"sv) + nll(classDecl); | ||
3029 | } | ||
3030 | temp.push_back(indent() + baseVar + s(".__index = "sv) + baseVar + nll(classDecl)); | ||
3031 | str_list tmp; | ||
3032 | if (usage == ExpUsage::Assignment) { | ||
3033 | auto assign = x->new_ptr<Assign_t>(); | ||
3034 | assign->values.push_back(toAst<Exp_t>(classVar, Exp, x)); | ||
3035 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
3036 | assignment->expList.set(expList); | ||
3037 | assignment->action.set(assign); | ||
3038 | transformAssignment(assignment, tmp); | ||
3039 | } | ||
3040 | if (extend) { | ||
3041 | _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nll(classDecl); | ||
3042 | } | ||
3043 | _buf << indent() << classVar << " = setmetatable({" << nll(classDecl); | ||
3044 | if (!builtins.empty()) { | ||
3045 | _buf << join(builtins) << ","sv << nll(classDecl); | ||
3046 | } else { | ||
3047 | if (extend) { | ||
3048 | _buf << indent(1) << "__init = function(self, ...)"sv << nll(classDecl); | ||
3049 | _buf << indent(2) << "return _class_0.__parent.__init(self, ...)"sv << nll(classDecl); | ||
3050 | _buf << indent(1) << "end,"sv << nll(classDecl); | ||
3051 | } else { | ||
3052 | _buf << indent(1) << "__init = function() end,"sv << nll(classDecl); | ||
3053 | } | ||
3054 | } | ||
3055 | _buf << indent(1) << "__base = "sv << baseVar; | ||
3056 | if (!className.empty()) { | ||
3057 | _buf << ","sv << nll(classDecl) << indent(1) << "__name = "sv << className << (extend ? s(","sv) : Empty) << nll(classDecl); | ||
3058 | } else { | ||
3059 | _buf << nll(classDecl); | ||
3060 | } | ||
3061 | if (extend) { | ||
3062 | _buf << indent(1) << "__parent = "sv << parentVar << nll(classDecl); | ||
3063 | } | ||
3064 | _buf << indent() << "}, {"sv << nll(classDecl); | ||
3065 | if (extend) { | ||
3066 | _buf << indent(1) << "__index = function(cls, name)"sv << nll(classDecl); | ||
3067 | _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nll(classDecl); | ||
3068 | _buf << indent(2) << "if val == nil then"sv << nll(classDecl); | ||
3069 | _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nll(classDecl); | ||
3070 | _buf << indent(3) << "if parent then"sv << nll(classDecl); | ||
3071 | _buf << indent(4) << "return parent[name]"sv << nll(classDecl); | ||
3072 | _buf << indent(3) << "end"sv << nll(classDecl); | ||
3073 | _buf << indent(2) << "else"sv << nll(classDecl); | ||
3074 | _buf << indent(3) << "return val"sv << nll(classDecl); | ||
3075 | _buf << indent(2) << "end"sv << nll(classDecl); | ||
3076 | _buf << indent(1) << "end,"sv << nll(classDecl); | ||
3077 | } else { | ||
3078 | _buf << indent(1) << "__index = "sv << baseVar << ","sv << nll(classDecl); | ||
3079 | } | ||
3080 | _buf << indent(1) << "__call = function(cls, ...)"sv << nll(classDecl); | ||
3081 | pushScope(); | ||
3082 | auto selfVar = getUnusedName("_self_"sv); | ||
3083 | addToScope(selfVar); | ||
3084 | _buf << indent(1) << "local " << selfVar << " = setmetatable({}, "sv << baseVar << ")"sv << nll(classDecl); | ||
3085 | _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nll(classDecl); | ||
3086 | _buf << indent(1) << "return "sv << selfVar << nll(classDecl); | ||
3087 | popScope(); | ||
3088 | _buf << indent(1) << "end"sv << nll(classDecl); | ||
3089 | _buf << indent() << "})"sv << nll(classDecl); | ||
3090 | _buf << indent() << baseVar << ".__class = "sv << classVar << nll(classDecl); | ||
3091 | if (!statements.empty()) _buf << indent() << "local self = "sv << classVar << nll(classDecl); | ||
3092 | _buf << join(statements); | ||
3093 | if (extend) { | ||
3094 | _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nll(classDecl); | ||
3095 | _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nll(classDecl); | ||
3096 | _buf << indent() << "end"sv << nll(classDecl); | ||
3097 | } | ||
3098 | if (!assignItem.empty()) { | ||
3099 | _buf << indent() << assignItem << " = "sv << classVar << nll(classDecl); | ||
3100 | } | ||
3101 | switch (usage) { | ||
3102 | case ExpUsage::Return: { | ||
3103 | _buf << indent() << "return "sv << classVar << nlr(classDecl); | ||
3104 | break; | ||
3105 | } | ||
3106 | case ExpUsage::Assignment: { | ||
3107 | _buf << tmp.back(); | ||
3108 | break; | ||
3109 | } | ||
3110 | default: break; | ||
3111 | } | ||
3112 | temp.push_back(clearBuf()); | ||
3113 | popScope(); | ||
3114 | temp.push_back(indent() + s("end"sv) + nlr(classDecl)); | ||
3115 | out.push_back(join(temp)); | ||
3116 | } | ||
3117 | |||
3118 | size_t transform_class_member_list(class_member_list_t* class_member_list, std::list<ClassMember>& out, const std::string& classVar) { | ||
3119 | str_list temp; | ||
3120 | size_t count = 0; | ||
3121 | for (auto keyValue : class_member_list->values.objects()) { | ||
3122 | MemType type = MemType::Common; | ||
3123 | BLOCK_START | ||
3124 | auto normal_pair = ast_cast<normal_pair_t>(keyValue); | ||
3125 | BREAK_IF(!normal_pair); | ||
3126 | auto keyName = normal_pair->key.as<KeyName_t>(); | ||
3127 | BREAK_IF(!keyName); | ||
3128 | std::string newSuperCall; | ||
3129 | auto selfName = keyName->name.as<SelfName_t>(); | ||
3130 | if (selfName) { | ||
3131 | type = MemType::Property; | ||
3132 | auto name = ast_cast<self_name_t>(selfName->name); | ||
3133 | if (!name) throw std::logic_error(debugInfo("Invalid class poperty name."sv, selfName->name)); | ||
3134 | newSuperCall = classVar + s(".__parent."sv) + toString(name->name); | ||
3135 | } else { | ||
3136 | auto x = keyName; | ||
3137 | auto nameNode = keyName->name.as<Name_t>(); | ||
3138 | if (!nameNode) break; | ||
3139 | auto name = toString(nameNode); | ||
3140 | if (name == "new"sv) { | ||
3141 | type = MemType::Builtin; | ||
3142 | keyName->name.set(toAst<Name_t>("__init"sv, Name, x)); | ||
3143 | newSuperCall = classVar + s(".__parent.__init"sv); | ||
3144 | } else { | ||
3145 | newSuperCall = classVar + s(".__parent.__base."sv) + name; | ||
3146 | } | ||
3147 | } | ||
3148 | normal_pair->value->traverse([&](ast_node* node) { | ||
3149 | if (node->getId() == "ClassDecl"_id) return traversal::Return; | ||
3150 | if (auto chainValue = ast_cast<ChainValue_t>(node)) { | ||
3151 | if (auto callable = ast_cast<Callable_t>(chainValue->items.front())) { | ||
3152 | auto var = callable->item.get(); | ||
3153 | if (toString(var) == "super"sv) { | ||
3154 | auto insertSelfToArguments = [&](ast_node* item) { | ||
3155 | auto x = item; | ||
3156 | switch (item->getId()) { | ||
3157 | case "InvokeArgs"_id: { | ||
3158 | auto invoke = static_cast<InvokeArgs_t*>(item); | ||
3159 | invoke->args.push_front(toAst<Exp_t>("self"sv, Exp, x)); | ||
3160 | return true; | ||
3161 | } | ||
3162 | case "Invoke"_id: { | ||
3163 | auto invoke = static_cast<Invoke_t*>(item); | ||
3164 | invoke->args.push_front(toAst<Exp_t>("self"sv, Exp, x)); | ||
3165 | return true; | ||
3166 | } | ||
3167 | default: | ||
3168 | return false; | ||
3169 | } | ||
3170 | }; | ||
3171 | const auto& chainList = chainValue->items.objects(); | ||
3172 | if (chainList.size() >= 2) { | ||
3173 | auto it = chainList.begin(); | ||
3174 | auto secondItem = *(++it); | ||
3175 | if (!insertSelfToArguments(secondItem)) { | ||
3176 | if (auto colonChainItem = ast_cast<ColonChainItem_t>(secondItem)) { | ||
3177 | if (chainList.size() > 2 && insertSelfToArguments(*(++it))) { | ||
3178 | colonChainItem->switchToDot = true; | ||
3179 | } | ||
3180 | } | ||
3181 | newSuperCall = classVar + s(".__parent"sv); | ||
3182 | } | ||
3183 | } else { | ||
3184 | newSuperCall = classVar + s(".__parent"sv); | ||
3185 | } | ||
3186 | auto newChain = toAst<ChainValue_t>(newSuperCall, ChainValue, chainValue); | ||
3187 | chainValue->items.pop_front(); | ||
3188 | const auto& items = newChain->items.objects(); | ||
3189 | for (auto it = items.rbegin(); it != items.rend(); ++it) { | ||
3190 | chainValue->items.push_front(*it); | ||
3191 | } | ||
3192 | } | ||
3193 | } | ||
3194 | } | ||
3195 | return traversal::Continue; | ||
3196 | }); | ||
3197 | BLOCK_END | ||
3198 | pushScope(); | ||
3199 | if (type == MemType::Property) { | ||
3200 | decIndentOffset(); | ||
3201 | } | ||
3202 | switch (keyValue->getId()) { | ||
3203 | case "variable_pair"_id: | ||
3204 | transform_variable_pair(static_cast<variable_pair_t*>(keyValue), temp); | ||
3205 | break; | ||
3206 | case "normal_pair"_id: | ||
3207 | transform_normal_pair(static_cast<normal_pair_t*>(keyValue), temp); | ||
3208 | break; | ||
3209 | } | ||
3210 | if (type == MemType::Property) { | ||
3211 | incIndentOffset(); | ||
3212 | } | ||
3213 | popScope(); | ||
3214 | out.push_back({temp.back(), type, keyValue}); | ||
3215 | temp.clear(); | ||
3216 | ++count; | ||
3217 | } | ||
3218 | return count; | ||
3219 | } | ||
3220 | |||
3221 | void transformAssignable(Assignable_t* assignable, str_list& out) { | ||
3222 | auto item = assignable->item.get(); | ||
3223 | switch (item->getId()) { | ||
3224 | case "AssignableChain"_id: transformAssignableChain(static_cast<AssignableChain_t*>(item), out); break; | ||
3225 | case "Variable"_id: transformVariable(static_cast<Variable_t*>(item), out); break; | ||
3226 | case "SelfName"_id: transformSelfName(static_cast<SelfName_t*>(item), out, false); break; | ||
3227 | default: break; | ||
3228 | } | ||
3229 | } | ||
3230 | |||
3231 | void transformWithClosure(With_t* with, str_list& out) { | ||
3232 | str_list temp; | ||
3233 | temp.push_back(s("(function()"sv) + nll(with)); | ||
3234 | pushScope(); | ||
3235 | transformWith(with, temp, nullptr, true); | ||
3236 | popScope(); | ||
3237 | temp.push_back(indent() + s("end)()"sv)); | ||
3238 | out.push_back(join(temp)); | ||
3239 | } | ||
3240 | |||
3241 | void transformWith(With_t* with, str_list& out, ExpList_t* assignList = nullptr, bool returnValue = false) { | ||
3242 | auto x = with; | ||
3243 | str_list temp; | ||
3244 | std::string withVar; | ||
3245 | bool scoped = false; | ||
3246 | if (with->assigns) { | ||
3247 | checkAssignable(with->valueList); | ||
3248 | auto vars = getAssignVars(with); | ||
3249 | if (vars.front().empty()) { | ||
3250 | if (_config.reuseVariable && with->assigns->values.objects().size() == 1) { | ||
3251 | auto var = singleVariableFrom(with->assigns->values.objects().front()); | ||
3252 | if (!var.empty()) { | ||
3253 | withVar = var; | ||
3254 | } | ||
3255 | } | ||
3256 | if (withVar.empty()) { | ||
3257 | withVar = getUnusedName("_with_"); | ||
3258 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
3259 | assignment->expList.set(toAst<ExpList_t>(withVar, ExpList, x)); | ||
3260 | auto assign = x->new_ptr<Assign_t>(); | ||
3261 | assign->values.push_back(with->assigns->values.objects().front()); | ||
3262 | assignment->action.set(assign); | ||
3263 | if (!returnValue) { | ||
3264 | scoped = true; | ||
3265 | temp.push_back(indent() + s("do"sv) + nll(with)); | ||
3266 | pushScope(); | ||
3267 | } | ||
3268 | transformAssignment(assignment, temp); | ||
3269 | } | ||
3270 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
3271 | assignment->expList.set(with->valueList); | ||
3272 | auto assign = x->new_ptr<Assign_t>(); | ||
3273 | assign->values.push_back(toAst<Exp_t>(withVar, Exp, x)); | ||
3274 | bool skipFirst = true; | ||
3275 | for (auto value : with->assigns->values.objects()) { | ||
3276 | if (skipFirst) { | ||
3277 | skipFirst = false; | ||
3278 | continue; | ||
3279 | } | ||
3280 | assign->values.push_back(value); | ||
3281 | } | ||
3282 | assignment->action.set(assign); | ||
3283 | transformAssignment(assignment, temp); | ||
3284 | } else { | ||
3285 | withVar = vars.front(); | ||
3286 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
3287 | assignment->expList.set(with->valueList); | ||
3288 | assignment->action.set(with->assigns); | ||
3289 | if (!returnValue) { | ||
3290 | scoped = true; | ||
3291 | temp.push_back(indent() + s("do"sv) + nll(with)); | ||
3292 | pushScope(); | ||
3293 | } | ||
3294 | transformAssignment(assignment, temp); | ||
3295 | } | ||
3296 | } else { | ||
3297 | if (_config.reuseVariable) withVar = singleVariableFrom(with->valueList); | ||
3298 | if (withVar.empty()) { | ||
3299 | withVar = getUnusedName("_with_"); | ||
3300 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
3301 | assignment->expList.set(toAst<ExpList_t>(withVar, ExpList, x)); | ||
3302 | auto assign = x->new_ptr<Assign_t>(); | ||
3303 | assign->values.dup(with->valueList->exprs); | ||
3304 | assignment->action.set(assign); | ||
3305 | if (!returnValue) { | ||
3306 | scoped = true; | ||
3307 | temp.push_back(indent() + s("do"sv) + nll(with)); | ||
3308 | pushScope(); | ||
3309 | } | ||
3310 | transformAssignment(assignment, temp); | ||
3311 | } | ||
3312 | } | ||
3313 | if (!scoped && !returnValue) { | ||
3314 | pushScope(); | ||
3315 | scoped = traversal::Stop == with->body->traverse([&](ast_node* node) { | ||
3316 | if (auto statement = ast_cast<Statement_t>(node)) { | ||
3317 | ClassDecl_t* clsDecl = nullptr; | ||
3318 | if (auto assignment = assignmentFrom(statement)) { | ||
3319 | auto names = getAssignDefs(assignment->expList.get()); | ||
3320 | if (!names.empty()) { | ||
3321 | return traversal::Stop; | ||
3322 | } | ||
3323 | auto info = extractDestructureInfo(assignment); | ||
3324 | if (!info.first.empty()) { | ||
3325 | for (const auto& destruct : info.first) | ||
3326 | for (const auto& item : destruct.items) | ||
3327 | if (item.isVariable && !isDefined(item.name)) | ||
3328 | return traversal::Stop; | ||
3329 | } | ||
3330 | BLOCK_START | ||
3331 | auto assign = assignment->action.as<Assign_t>(); | ||
3332 | BREAK_IF(!assign); | ||
3333 | BREAK_IF(assign->values.objects().size() != 1); | ||
3334 | auto exp = ast_cast<Exp_t>(assign->values.objects().front()); | ||
3335 | BREAK_IF(!exp); | ||
3336 | if (auto value = singleValueFrom(exp)) { | ||
3337 | clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>(); | ||
3338 | } | ||
3339 | BLOCK_END | ||
3340 | } else if (auto expList = expListFrom(statement)) { | ||
3341 | auto value = singleValueFrom(expList); | ||
3342 | clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>(); | ||
3343 | } | ||
3344 | if (clsDecl) { | ||
3345 | auto variable = clsDecl->name.as<Variable_t>(); | ||
3346 | if (!isDefined(toString(variable))) return traversal::Stop; | ||
3347 | } | ||
3348 | return traversal::Return; | ||
3349 | } | ||
3350 | return traversal::Continue; | ||
3351 | }); | ||
3352 | popScope(); | ||
3353 | if (scoped) { | ||
3354 | temp.push_back(indent() + s("do"sv) + nll(with)); | ||
3355 | pushScope(); | ||
3356 | } | ||
3357 | } | ||
3358 | _withVars.push(withVar); | ||
3359 | transformBody(with->body, temp); | ||
3360 | _withVars.pop(); | ||
3361 | if (assignList) { | ||
3362 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
3363 | assignment->expList.set(assignList); | ||
3364 | auto assign = x->new_ptr<Assign_t>(); | ||
3365 | assign->values.push_back(toAst<Exp_t>(withVar, Exp, x)); | ||
3366 | assignment->action.set(assign); | ||
3367 | transformAssignment(assignment, temp); | ||
3368 | } | ||
3369 | if (returnValue) { | ||
3370 | auto stmt = lastStatementFrom(with->body); | ||
3371 | if (!stmt->content.is<Return_t>()) { | ||
3372 | temp.push_back(indent() + s("return "sv) + withVar + nll(with)); | ||
3373 | } | ||
3374 | } | ||
3375 | if (scoped) { | ||
3376 | popScope(); | ||
3377 | temp.push_back(indent() + s("end"sv) + nll(with)); | ||
3378 | } | ||
3379 | out.push_back(join(temp)); | ||
3380 | } | ||
3381 | |||
3382 | void transform_const_value(const_value_t* const_value, str_list& out) { | ||
3383 | out.push_back(toString(const_value)); | ||
3384 | } | ||
3385 | |||
3386 | void transformExport(Export_t* exportNode, str_list& out) { | ||
3387 | auto x = exportNode; | ||
3388 | auto item = exportNode->item.get(); | ||
3389 | switch (item->getId()) { | ||
3390 | case "ClassDecl"_id: { | ||
3391 | auto classDecl = static_cast<ClassDecl_t*>(item); | ||
3392 | if (classDecl->name && classDecl->name->item->getId() == "Variable"_id) { | ||
3393 | markVarExported(ExportMode::Any, true); | ||
3394 | addExportedVar(toString(classDecl->name->item)); | ||
3395 | } | ||
3396 | transformClassDecl(classDecl, out); | ||
3397 | break; | ||
3398 | } | ||
3399 | case "export_op"_id: | ||
3400 | if (toString(item) == "*"sv) { | ||
3401 | markVarExported(ExportMode::Any, false); | ||
3402 | } else { | ||
3403 | markVarExported(ExportMode::Capital, false); | ||
3404 | } | ||
3405 | break; | ||
3406 | case "export_values"_id: { | ||
3407 | markVarExported(ExportMode::Any, true); | ||
3408 | auto values = exportNode->item.to<export_values_t>(); | ||
3409 | if (values->valueList) { | ||
3410 | auto expList = x->new_ptr<ExpList_t>(); | ||
3411 | for (auto name : values->nameList->names.objects()) { | ||
3412 | addExportedVar(toString(name)); | ||
3413 | auto callable = x->new_ptr<Callable_t>(); | ||
3414 | callable->item.set(name); | ||
3415 | auto chainValue = x->new_ptr<ChainValue_t>(); | ||
3416 | chainValue->items.push_back(callable); | ||
3417 | auto value = x->new_ptr<Value_t>(); | ||
3418 | value->item.set(chainValue); | ||
3419 | auto exp = x->new_ptr<Exp_t>(); | ||
3420 | exp->value.set(value); | ||
3421 | expList->exprs.push_back(exp); | ||
3422 | } | ||
3423 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
3424 | assignment->expList.set(expList); | ||
3425 | auto assign = x->new_ptr<Assign_t>(); | ||
3426 | assign->values.dup(values->valueList->exprs); | ||
3427 | assignment->action.set(assign); | ||
3428 | transformAssignment(assignment, out); | ||
3429 | } else { | ||
3430 | for (auto name : values->nameList->names.objects()) { | ||
3431 | addExportedVar(toString(name)); | ||
3432 | } | ||
3433 | } | ||
3434 | break; | ||
3435 | } | ||
3436 | default: | ||
3437 | break; | ||
3438 | } | ||
3439 | } | ||
3440 | |||
3441 | void transformTable(ast_node* table, const node_container& pairs, str_list& out) { | ||
3442 | if (pairs.empty()) { | ||
3443 | out.push_back(s("{ }"sv)); | ||
3444 | return; | ||
3445 | } | ||
3446 | str_list temp; | ||
3447 | pushScope(); | ||
3448 | for (auto pair : pairs) { | ||
3449 | switch (pair->getId()) { | ||
3450 | case "Exp"_id: transformExp(static_cast<Exp_t*>(pair), temp); break; | ||
3451 | case "variable_pair"_id: transform_variable_pair(static_cast<variable_pair_t*>(pair), temp); break; | ||
3452 | case "normal_pair"_id: transform_normal_pair(static_cast<normal_pair_t*>(pair), temp); break; | ||
3453 | } | ||
3454 | temp.back() = indent() + temp.back() + (pair == pairs.back() ? Empty : s(","sv)) + nll(pair); | ||
3455 | } | ||
3456 | out.push_back(s("{"sv) + nll(table) + join(temp)); | ||
3457 | popScope(); | ||
3458 | out.back() += (indent() + s("}"sv)); | ||
3459 | } | ||
3460 | |||
3461 | void transform_simple_table(simple_table_t* table, str_list& out) { | ||
3462 | transformTable(table, table->pairs.objects(), out); | ||
3463 | } | ||
3464 | |||
3465 | void transformTblComprehension(TblComprehension_t* comp, str_list& out) { | ||
3466 | str_list kv; | ||
3467 | std::string tbl = getUnusedName("_tbl_"); | ||
3468 | addToScope(tbl); | ||
3469 | str_list temp; | ||
3470 | auto compInner = comp->forLoop.get(); | ||
3471 | for (auto item : compInner->items.objects()) { | ||
3472 | switch (item->getId()) { | ||
3473 | case "CompForEach"_id: | ||
3474 | transformCompForEach(static_cast<CompForEach_t*>(item), temp); | ||
3475 | break; | ||
3476 | case "CompFor"_id: | ||
3477 | transformCompFor(static_cast<CompFor_t*>(item), temp); | ||
3478 | break; | ||
3479 | case "Exp"_id: | ||
3480 | transformExp(static_cast<Exp_t*>(item), temp); | ||
3481 | temp.back() = indent() + s("if "sv) + temp.back() + s(" then"sv) + nll(item); | ||
3482 | pushScope(); | ||
3483 | break; | ||
3484 | } | ||
3485 | } | ||
3486 | transformExp(comp->key, kv); | ||
3487 | if (comp->value) { | ||
3488 | transformExp(comp->value->value, kv); | ||
3489 | } | ||
3490 | for (size_t i = 0; i < compInner->items.objects().size(); ++i) { | ||
3491 | popScope(); | ||
3492 | } | ||
3493 | _buf << indent() << "local "sv << tbl << " = { }"sv << nll(comp); | ||
3494 | _buf << join(temp); | ||
3495 | pushScope(); | ||
3496 | if (!comp->value) { | ||
3497 | auto keyVar = getUnusedName("_key_"); | ||
3498 | auto valVar = getUnusedName("_val_"); | ||
3499 | _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nll(comp); | ||
3500 | kv.front() = keyVar; | ||
3501 | kv.push_back(valVar); | ||
3502 | } | ||
3503 | _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nll(comp); | ||
3504 | for (int ind = int(temp.size()) - 2; ind > -1 ; --ind) { | ||
3505 | _buf << indent(ind) << "end"sv << nll(comp); | ||
3506 | } | ||
3507 | popScope(); | ||
3508 | _buf << indent() << "end"sv << nll(comp); | ||
3509 | out.push_back(tbl); | ||
3510 | out.push_back(clearBuf()); | ||
3511 | } | ||
3512 | |||
3513 | void transformTblCompInPlace(TblComprehension_t* comp, ExpList_t* expList, str_list& out) { | ||
3514 | auto x = comp; | ||
3515 | str_list temp; | ||
3516 | auto ind = indent(); | ||
3517 | pushScope(); | ||
3518 | transformTblComprehension(comp, temp); | ||
3519 | auto assign = x->new_ptr<Assign_t>(); | ||
3520 | assign->values.push_back(toAst<Exp_t>(temp.front(), Exp, x)); | ||
3521 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
3522 | assignment->expList.set(expList); | ||
3523 | assignment->action.set(assign); | ||
3524 | transformAssignment(assignment, temp); | ||
3525 | out.push_back( | ||
3526 | ind + s("do"sv) + nll(comp) + | ||
3527 | *(++temp.begin()) + | ||
3528 | temp.back()); | ||
3529 | popScope(); | ||
3530 | out.back() = out.back() + indent() + s("end"sv) + nlr(comp); | ||
3531 | } | ||
3532 | |||
3533 | void transformTblCompReturn(TblComprehension_t* comp, str_list& out) { | ||
3534 | str_list temp; | ||
3535 | transformTblComprehension(comp, temp); | ||
3536 | out.push_back(temp.back() + indent() + s("return "sv) + temp.front() + nlr(comp)); | ||
3537 | } | ||
3538 | |||
3539 | void transformTblCompClosure(TblComprehension_t* comp, str_list& out) { | ||
3540 | str_list temp; | ||
3541 | std::string before = s("(function()"sv) + nll(comp); | ||
3542 | pushScope(); | ||
3543 | transformTblComprehension(comp, temp); | ||
3544 | const auto& tbVar = temp.front(); | ||
3545 | const auto& compBody = temp.back(); | ||
3546 | out.push_back( | ||
3547 | before + | ||
3548 | compBody + | ||
3549 | indent() + s("return "sv) + tbVar + nlr(comp)); | ||
3550 | popScope(); | ||
3551 | out.back() = out.back() + indent() + s("end)()"sv); | ||
3552 | } | ||
3553 | |||
3554 | void transformCompFor(CompFor_t* comp, str_list& out) { | ||
3555 | str_list temp; | ||
3556 | std::string varName = toString(comp->varName); | ||
3557 | transformExp(comp->startValue, temp); | ||
3558 | transformExp(comp->stopValue, temp); | ||
3559 | if (comp->stepValue) { | ||
3560 | transformExp(comp->stepValue->value, temp); | ||
3561 | } else { | ||
3562 | temp.emplace_back(); | ||
3563 | } | ||
3564 | auto it = temp.begin(); | ||
3565 | const auto& start = *it; | ||
3566 | const auto& stop = *(++it); | ||
3567 | const auto& step = *(++it); | ||
3568 | _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : s(", "sv) + step) << " do"sv << nll(comp); | ||
3569 | out.push_back(clearBuf()); | ||
3570 | pushScope(); | ||
3571 | addToScope(varName); | ||
3572 | } | ||
3573 | |||
3574 | void transformTableBlock(TableBlock_t* table, str_list& out) { | ||
3575 | transformTable(table, table->values.objects(), out); | ||
3576 | } | ||
3577 | |||
3578 | void transformDo(Do_t* doNode, str_list& out, bool implicitReturn = false) { | ||
3579 | str_list temp; | ||
3580 | temp.push_back(indent() + s("do"sv) + nll(doNode)); | ||
3581 | pushScope(); | ||
3582 | transformBody(doNode->body, temp, implicitReturn); | ||
3583 | popScope(); | ||
3584 | temp.push_back(indent() + s("end"sv) + nlr(doNode)); | ||
3585 | out.push_back(join(temp)); | ||
3586 | } | ||
3587 | |||
3588 | void transformDoClosure(Do_t* doNode, str_list& out) { | ||
3589 | str_list temp; | ||
3590 | temp.push_back(s("(function()"sv) + nll(doNode)); | ||
3591 | pushScope(); | ||
3592 | transformBody(doNode->body, temp, true); | ||
3593 | popScope(); | ||
3594 | temp.push_back(indent() + s("end)()"sv)); | ||
3595 | out.push_back(join(temp)); | ||
3596 | } | ||
3597 | |||
3598 | void transformImport(Import_t* import, str_list& out) { | ||
3599 | str_list temp; | ||
3600 | auto x = import; | ||
3601 | auto objVar = singleVariableFrom(import->exp); | ||
3602 | ast_ptr<false, ExpListAssign_t> objAssign; | ||
3603 | if (objVar.empty()) { | ||
3604 | objVar = getUnusedName("_obj_"sv); | ||
3605 | auto expList = toAst<ExpList_t>(objVar, ExpList, x); | ||
3606 | auto assign = x->new_ptr<Assign_t>(); | ||
3607 | assign->values.push_back(import->exp); | ||
3608 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
3609 | assignment->expList.set(expList); | ||
3610 | assignment->action.set(assign); | ||
3611 | objAssign.set(assignment); | ||
3612 | } | ||
3613 | auto expList = x->new_ptr<ExpList_t>(); | ||
3614 | auto assign = x->new_ptr<Assign_t>(); | ||
3615 | for (auto name : import->names.objects()) { | ||
3616 | switch (name->getId()) { | ||
3617 | case "Variable"_id: { | ||
3618 | auto var = ast_to<Variable_t>(name); | ||
3619 | { | ||
3620 | auto callable = toAst<Callable_t>(objVar, Callable, x); | ||
3621 | auto dotChainItem = x->new_ptr<DotChainItem_t>(); | ||
3622 | dotChainItem->name.set(var->name); | ||
3623 | auto chainValue = x->new_ptr<ChainValue_t>(); | ||
3624 | chainValue->items.push_back(callable); | ||
3625 | chainValue->items.push_back(dotChainItem); | ||
3626 | auto value = x->new_ptr<Value_t>(); | ||
3627 | value->item.set(chainValue); | ||
3628 | auto exp = x->new_ptr<Exp_t>(); | ||
3629 | exp->value.set(value); | ||
3630 | assign->values.push_back(exp); | ||
3631 | } | ||
3632 | auto callable = x->new_ptr<Callable_t>(); | ||
3633 | callable->item.set(var); | ||
3634 | auto chainValue = x->new_ptr<ChainValue_t>(); | ||
3635 | chainValue->items.push_back(callable); | ||
3636 | auto value = x->new_ptr<Value_t>(); | ||
3637 | value->item.set(chainValue); | ||
3638 | auto exp = x->new_ptr<Exp_t>(); | ||
3639 | exp->value.set(value); | ||
3640 | expList->exprs.push_back(exp); | ||
3641 | break; | ||
3642 | } | ||
3643 | case "colon_import_name"_id: { | ||
3644 | auto var = static_cast<colon_import_name_t*>(name)->name.get(); | ||
3645 | { | ||
3646 | auto nameNode = var->name.get(); | ||
3647 | auto callable = toAst<Callable_t>(objVar, Callable, x); | ||
3648 | auto colonChain = x->new_ptr<ColonChainItem_t>(); | ||
3649 | colonChain->name.set(nameNode); | ||
3650 | auto chainValue = x->new_ptr<ChainValue_t>(); | ||
3651 | chainValue->items.push_back(callable); | ||
3652 | chainValue->items.push_back(colonChain); | ||
3653 | auto value = x->new_ptr<Value_t>(); | ||
3654 | value->item.set(chainValue); | ||
3655 | auto exp = x->new_ptr<Exp_t>(); | ||
3656 | exp->value.set(value); | ||
3657 | assign->values.push_back(exp); | ||
3658 | } | ||
3659 | auto callable = x->new_ptr<Callable_t>(); | ||
3660 | callable->item.set(var); | ||
3661 | auto chainValue = x->new_ptr<ChainValue_t>(); | ||
3662 | chainValue->items.push_back(callable); | ||
3663 | auto value = x->new_ptr<Value_t>(); | ||
3664 | value->item.set(chainValue); | ||
3665 | auto exp = x->new_ptr<Exp_t>(); | ||
3666 | exp->value.set(value); | ||
3667 | expList->exprs.push_back(exp); | ||
3668 | break; | ||
3669 | } | ||
3670 | } | ||
3671 | } | ||
3672 | if (objAssign) { | ||
3673 | auto preDef = getPredefine(transformAssignDefs(expList)); | ||
3674 | if (!preDef.empty()) { | ||
3675 | temp.push_back(preDef + nll(import)); | ||
3676 | } | ||
3677 | temp.push_back(indent() + s("do"sv) + nll(import)); | ||
3678 | pushScope(); | ||
3679 | transformAssignment(objAssign, temp); | ||
3680 | } | ||
3681 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
3682 | assignment->expList.set(expList); | ||
3683 | assignment->action.set(assign); | ||
3684 | transformAssignment(assignment, temp); | ||
3685 | if (objAssign) { | ||
3686 | popScope(); | ||
3687 | temp.push_back(indent() + s("end"sv) + nlr(import)); | ||
3688 | } | ||
3689 | out.push_back(join(temp)); | ||
3690 | } | ||
3691 | |||
3692 | void transformWhileInPlace(While_t* whileNode, str_list& out, ExpList_t* expList = nullptr) { | ||
3693 | auto x = whileNode; | ||
3694 | str_list temp; | ||
3695 | if (expList) { | ||
3696 | temp.push_back(indent() + s("do"sv) + nll(whileNode)); | ||
3697 | } | ||
3698 | pushScope(); | ||
3699 | auto accumVar = getUnusedName("_accum_"sv); | ||
3700 | addToScope(accumVar); | ||
3701 | auto lenVar = getUnusedName("_len_"sv); | ||
3702 | addToScope(lenVar); | ||
3703 | temp.push_back(indent() + s("local "sv) + accumVar + s(" = { }"sv) + nll(whileNode)); | ||
3704 | temp.push_back(indent() + s("local "sv) + lenVar + s(" = 1"sv) + nll(whileNode)); | ||
3705 | transformExp(whileNode->condition, temp); | ||
3706 | temp.back() = indent() + s("while "sv) + temp.back() + s(" do"sv) + nll(whileNode); | ||
3707 | pushScope(); | ||
3708 | auto assignLeft = toAst<ExpList_t>(accumVar + s("["sv) + lenVar + s("]"sv), ExpList, x); | ||
3709 | assignLastExplist(assignLeft, whileNode->body); | ||
3710 | auto lenLine = lenVar + s(" = "sv) + lenVar + s(" + 1"sv) + nlr(whileNode); | ||
3711 | transformLoopBody(whileNode->body, temp, lenLine); | ||
3712 | popScope(); | ||
3713 | temp.push_back(indent() + s("end"sv) + nlr(whileNode)); | ||
3714 | if (expList) { | ||
3715 | auto assign = x->new_ptr<Assign_t>(); | ||
3716 | assign->values.push_back(toAst<Exp_t>(accumVar, Exp, x)); | ||
3717 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
3718 | assignment->expList.set(expList); | ||
3719 | assignment->action.set(assign); | ||
3720 | transformAssignment(assignment, temp); | ||
3721 | } else { | ||
3722 | temp.push_back(indent() + s("return "sv) + accumVar + nlr(whileNode)); | ||
3723 | } | ||
3724 | popScope(); | ||
3725 | if (expList) { | ||
3726 | temp.push_back(indent() + s("end"sv) + nlr(whileNode)); | ||
3727 | } | ||
3728 | out.push_back(join(temp)); | ||
3729 | } | ||
3730 | |||
3731 | void transformWhileClosure(While_t* whileNode, str_list& out) { | ||
3732 | auto x = whileNode; | ||
3733 | str_list temp; | ||
3734 | temp.push_back(s("(function() "sv) + nll(whileNode)); | ||
3735 | pushScope(); | ||
3736 | auto accumVar = getUnusedName("_accum_"sv); | ||
3737 | addToScope(accumVar); | ||
3738 | auto lenVar = getUnusedName("_len_"sv); | ||
3739 | addToScope(lenVar); | ||
3740 | temp.push_back(indent() + s("local "sv) + accumVar + s(" = { }"sv) + nll(whileNode)); | ||
3741 | temp.push_back(indent() + s("local "sv) + lenVar + s(" = 1"sv) + nll(whileNode)); | ||
3742 | transformExp(whileNode->condition, temp); | ||
3743 | temp.back() = indent() + s("while "sv) + temp.back() + s(" do"sv) + nll(whileNode); | ||
3744 | pushScope(); | ||
3745 | auto assignLeft = toAst<ExpList_t>(accumVar + s("["sv) + lenVar + s("]"sv), ExpList, x); | ||
3746 | assignLastExplist(assignLeft, whileNode->body); | ||
3747 | auto lenLine = lenVar + s(" = "sv) + lenVar + s(" + 1"sv) + nlr(whileNode); | ||
3748 | transformLoopBody(whileNode->body, temp, lenLine); | ||
3749 | popScope(); | ||
3750 | temp.push_back(indent() + s("end"sv) + nlr(whileNode)); | ||
3751 | temp.push_back(indent() + s("return "sv) + accumVar + nlr(whileNode)); | ||
3752 | popScope(); | ||
3753 | temp.push_back(indent() + s("end)()"sv)); | ||
3754 | out.push_back(join(temp)); | ||
3755 | } | ||
3756 | |||
3757 | void transformWhile(While_t* whileNode, str_list& out) { | ||
3758 | str_list temp; | ||
3759 | pushScope(); | ||
3760 | transformExp(whileNode->condition, temp); | ||
3761 | transformLoopBody(whileNode->body, temp, Empty); | ||
3762 | popScope(); | ||
3763 | _buf << indent() << "while "sv << temp.front() << " do"sv << nll(whileNode); | ||
3764 | _buf << temp.back(); | ||
3765 | _buf << indent() << "end"sv << nlr(whileNode); | ||
3766 | out.push_back(clearBuf()); | ||
3767 | } | ||
3768 | |||
3769 | void transformSwitchClosure(Switch_t* switchNode, str_list& out) { | ||
3770 | str_list temp; | ||
3771 | temp.push_back(s("(function()"sv) + nll(switchNode)); | ||
3772 | pushScope(); | ||
3773 | transformSwitch(switchNode, temp, true); | ||
3774 | popScope(); | ||
3775 | temp.push_back(indent() + s("end)()"sv)); | ||
3776 | out.push_back(join(temp)); | ||
3777 | } | ||
3778 | |||
3779 | void transformSwitch(Switch_t* switchNode, str_list& out, bool implicitReturn = false) { | ||
3780 | str_list temp; | ||
3781 | auto objVar = singleVariableFrom(switchNode->target); | ||
3782 | if (objVar.empty()) { | ||
3783 | objVar = getUnusedName("_exp_"sv); | ||
3784 | addToScope(objVar); | ||
3785 | transformExp(switchNode->target, temp); | ||
3786 | _buf << indent() << "local "sv << objVar << " = "sv << temp.back() << nll(switchNode); | ||
3787 | temp.back() = clearBuf(); | ||
3788 | } | ||
3789 | const auto& branches = switchNode->branches.objects(); | ||
3790 | for (auto branch_ : branches) { | ||
3791 | auto branch = static_cast<SwitchCase_t*>(branch_); | ||
3792 | temp.push_back(indent() + s(branches.front() == branch ? "if"sv : "elseif"sv)); | ||
3793 | str_list tmp; | ||
3794 | const auto& exprs = branch->valueList->exprs.objects(); | ||
3795 | for (auto exp_ : exprs) { | ||
3796 | auto exp = static_cast<Exp_t*>(exp_); | ||
3797 | transformExp(exp, tmp); | ||
3798 | if (!singleValueFrom(exp)) { | ||
3799 | tmp.back() = s("("sv) + tmp.back() + s(")"sv); | ||
3800 | } | ||
3801 | temp.back().append(s(" "sv) + tmp.back() + s(" == "sv) + objVar + | ||
3802 | s(exp == exprs.back() ? ""sv : " or"sv)); | ||
3803 | } | ||
3804 | temp.back().append(s(" then"sv) + nll(branch)); | ||
3805 | pushScope(); | ||
3806 | transformBody(branch->body, temp, implicitReturn); | ||
3807 | popScope(); | ||
3808 | } | ||
3809 | if (switchNode->lastBranch) { | ||
3810 | temp.push_back(indent() + s("else"sv) + nll(switchNode->lastBranch)); | ||
3811 | pushScope(); | ||
3812 | transformBody(switchNode->lastBranch, temp, implicitReturn); | ||
3813 | popScope(); | ||
3814 | } | ||
3815 | temp.push_back(indent() + s("end"sv) + nlr(switchNode)); | ||
3816 | out.push_back(join(temp)); | ||
3817 | } | ||
3818 | |||
3819 | void transformLocal(Local_t* local, str_list& out) { | ||
3820 | if (!local->forceDecls.empty() || !local->decls.empty()) { | ||
3821 | str_list defs; | ||
3822 | for (const auto& decl : local->forceDecls) { | ||
3823 | forceAddToScope(decl); | ||
3824 | defs.push_back(decl); | ||
3825 | } | ||
3826 | for (const auto& decl : local->decls) { | ||
3827 | if (addToScope(decl)) { | ||
3828 | defs.push_back(decl); | ||
3829 | } | ||
3830 | } | ||
3831 | auto preDefine = getPredefine(defs); | ||
3832 | if (!preDefine.empty()) { | ||
3833 | out.push_back(preDefine + nll(local)); | ||
3834 | } | ||
3835 | } | ||
3836 | } | ||
3837 | |||
3838 | void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { | ||
3839 | auto keyword = toString(breakLoop); | ||
3840 | if (keyword == "break"sv) { | ||
3841 | out.push_back(indent() + keyword + nll(breakLoop)); | ||
3842 | return; | ||
3843 | } | ||
3844 | if (_continueVars.empty()) throw std::logic_error(debugInfo("Continue is not inside a loop."sv, breakLoop)); | ||
3845 | _buf << indent() << _continueVars.top() << " = true"sv << nll(breakLoop); | ||
3846 | _buf << indent() << "break"sv << nll(breakLoop); | ||
3847 | out.push_back(clearBuf()); | ||
3848 | } | ||
3849 | }; | ||
3850 | |||
3851 | const std::string MoonCompliler::Empty; | ||
3852 | |||
3853 | std::tuple<std::string,std::string,GlobalVars> moonCompile(const std::string& codes, const MoonConfig& config) { | ||
3854 | auto compiler = MoonCompliler{}; | ||
3855 | auto result = compiler.complile(codes, config); | ||
3856 | auto globals = std::make_unique<std::list<GlobalVar>>(); | ||
3857 | for (const auto& var : compiler.getGlobals()) { | ||
3858 | int line,col; | ||
3859 | std::tie(line,col) = var.second; | ||
3860 | globals->push_back({var.first, line, col}); | ||
3861 | } | ||
3862 | return std::make_tuple(std::move(result.first),std::move(result.second),std::move(globals)); | ||
3863 | } | ||
3864 | |||
3865 | } // namespace MoonP | ||
diff --git a/src/MoonP/moon_compiler.h b/src/MoonP/moon_compiler.h new file mode 100644 index 0000000..cb1990c --- /dev/null +++ b/src/MoonP/moon_compiler.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* Copyright (c) 2020 Jin Li, http://www.luvfight.me | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
4 | |||
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
6 | |||
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ | ||
8 | |||
9 | #pragma once | ||
10 | |||
11 | #include <string> | ||
12 | #include <tuple> | ||
13 | #include <list> | ||
14 | #include <memory> | ||
15 | |||
16 | namespace MoonP { | ||
17 | |||
18 | const char* moonScriptVersion(); | ||
19 | |||
20 | struct MoonConfig { | ||
21 | bool lintGlobalVariable = false; | ||
22 | bool implicitReturnRoot = true; | ||
23 | bool reserveLineNumber = false; | ||
24 | bool spaceOverTab = false; | ||
25 | bool reuseVariable = false; | ||
26 | bool allowExprNotInTheEndOfBody = false; | ||
27 | }; | ||
28 | |||
29 | struct GlobalVar { | ||
30 | std::string name; | ||
31 | int line; | ||
32 | int col; | ||
33 | }; | ||
34 | |||
35 | using GlobalVars = std::unique_ptr<std::list<GlobalVar>>; | ||
36 | |||
37 | std::tuple<std::string,std::string,GlobalVars> moonCompile(const std::string& codes, const MoonConfig& config = {}); | ||
38 | |||
39 | } // namespace MoonP | ||
diff --git a/src/MoonP/moon_parser.cpp b/src/MoonP/moon_parser.cpp new file mode 100644 index 0000000..7b5183e --- /dev/null +++ b/src/MoonP/moon_parser.cpp | |||
@@ -0,0 +1,526 @@ | |||
1 | /* Copyright (c) 2020 Jin Li, http://www.luvfight.me | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
4 | |||
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
6 | |||
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ | ||
8 | |||
9 | #include "MoonP/moon_parser.h" | ||
10 | |||
11 | namespace pl = parserlib; | ||
12 | |||
13 | namespace MoonP { | ||
14 | |||
15 | std::unordered_set<std::string> State::luaKeywords = { | ||
16 | "and", "break", "do", "else", "elseif", | ||
17 | "end", "false", "for", "function", "if", | ||
18 | "in", "local", "nil", "not", "or", | ||
19 | "repeat", "return", "then", "true", "until", | ||
20 | "while" | ||
21 | }; | ||
22 | |||
23 | std::unordered_set<std::string> State::keywords = { | ||
24 | "and", "break", "do", "else", "elseif", | ||
25 | "end", "false", "for", "function", "if", | ||
26 | "in", "local", "nil", "not", "or", | ||
27 | "repeat", "return", "then", "true", "until", | ||
28 | "while", // Lua keywords | ||
29 | "class", "continue", "export", "extends", "from", | ||
30 | "import", "switch", "unless", "using", "when", | ||
31 | "with" // Moon keywords | ||
32 | }; | ||
33 | |||
34 | rule plain_space = *set(" \t"); | ||
35 | rule Break = nl(-expr('\r') >> '\n'); | ||
36 | rule Any = Break | any(); | ||
37 | rule White = *(set(" \t") | Break); | ||
38 | rule Stop = Break | eof(); | ||
39 | rule Comment = "--" >> *(not_(set("\r\n")) >> Any) >> and_(Stop); | ||
40 | rule Indent = *set(" \t"); | ||
41 | rule Space = plain_space >> -Comment; | ||
42 | rule SomeSpace = +set(" \t") >> -Comment; | ||
43 | rule SpaceBreak = Space >> Break; | ||
44 | rule EmptyLine = SpaceBreak; | ||
45 | rule AlphaNum = range('a', 'z') | range('A', 'Z') | range('0', '9') | '_'; | ||
46 | rule Name = (range('a', 'z') | range('A', 'Z') | '_') >> *AlphaNum; | ||
47 | rule Num = | ||
48 | ( | ||
49 | "0x" >> | ||
50 | +(range('0', '9') | range('a', 'f') | range('A', 'F')) >> | ||
51 | -(-set("uU") >> set("lL") >> set("lL")) | ||
52 | ) | ( | ||
53 | +range('0', '9') >> -set("uU") >> set("lL") >> set("lL") | ||
54 | ) | ( | ||
55 | ( | ||
56 | (+range('0', '9') >> -('.' >> +range('0', '9'))) | | ||
57 | ('.' >> +range('0', '9')) | ||
58 | ) >> -(set("eE") >> -expr('-') >> +range('0', '9')) | ||
59 | ); | ||
60 | rule Cut = false_(); | ||
61 | rule Seperator = true_(); | ||
62 | |||
63 | #define sym(str) (Space >> str) | ||
64 | #define symx(str) expr(str) | ||
65 | #define ensure(patt, finally) (((patt) >> (finally)) | ((finally) >> (Cut))) | ||
66 | #define key(str) (Space >> str >> not_(AlphaNum)) | ||
67 | |||
68 | rule Variable = pl::user(Name, [](const item_t& item) { | ||
69 | State* st = reinterpret_cast<State*>(item.user_data); | ||
70 | for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it); | ||
71 | auto it = State::keywords.find(st->buffer); | ||
72 | st->buffer.clear(); | ||
73 | return it == State::keywords.end(); | ||
74 | }); | ||
75 | |||
76 | rule LuaKeyword = pl::user(Name, [](const item_t& item) { | ||
77 | State* st = reinterpret_cast<State*>(item.user_data); | ||
78 | for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it); | ||
79 | auto it = State::luaKeywords.find(st->buffer); | ||
80 | st->buffer.clear(); | ||
81 | return it != State::luaKeywords.end(); | ||
82 | }); | ||
83 | |||
84 | rule self = expr('@'); | ||
85 | rule self_name = '@' >> Name; | ||
86 | rule self_class = expr("@@"); | ||
87 | rule self_class_name = "@@" >> Name; | ||
88 | |||
89 | rule SelfName = Space >> (self_class_name | self_class | self_name | self); | ||
90 | rule KeyName = SelfName | Space >> Name; | ||
91 | rule VarArg = Space >> "..."; | ||
92 | |||
93 | rule check_indent = pl::user(Indent, [](const item_t& item) { | ||
94 | int indent = 0; | ||
95 | for (input_it i = item.begin; i != item.end; ++i) { | ||
96 | switch (*i) { | ||
97 | case ' ': indent++; break; | ||
98 | case '\t': indent += 4; break; | ||
99 | } | ||
100 | } | ||
101 | State* st = reinterpret_cast<State*>(item.user_data); | ||
102 | return st->indents.top() == indent; | ||
103 | }); | ||
104 | rule CheckIndent = and_(check_indent); | ||
105 | |||
106 | rule advance = pl::user(Indent, [](const item_t& item) { | ||
107 | int indent = 0; | ||
108 | for (input_it i = item.begin; i != item.end; ++i) { | ||
109 | switch (*i) { | ||
110 | case ' ': indent++; break; | ||
111 | case '\t': indent += 4; break; | ||
112 | } | ||
113 | } | ||
114 | State* st = reinterpret_cast<State*>(item.user_data); | ||
115 | int top = st->indents.top(); | ||
116 | if (top != -1 && indent > top) { | ||
117 | st->indents.push(indent); | ||
118 | return true; | ||
119 | } | ||
120 | return false; | ||
121 | }); | ||
122 | rule Advance = and_(advance); | ||
123 | |||
124 | rule push_indent = pl::user(Indent, [](const item_t& item) { | ||
125 | int indent = 0; | ||
126 | for (input_it i = item.begin; i != item.end; ++i) { | ||
127 | switch (*i) { | ||
128 | case ' ': indent++; break; | ||
129 | case '\t': indent += 4; break; | ||
130 | } | ||
131 | } | ||
132 | State* st = reinterpret_cast<State*>(item.user_data); | ||
133 | st->indents.push(indent); | ||
134 | return true; | ||
135 | }); | ||
136 | rule PushIndent = and_(push_indent); | ||
137 | |||
138 | rule PreventIndent = pl::user(true_(), [](const item_t& item) { | ||
139 | State* st = reinterpret_cast<State*>(item.user_data); | ||
140 | st->indents.push(-1); | ||
141 | return true; | ||
142 | }); | ||
143 | |||
144 | rule PopIndent = pl::user(true_(), [](const item_t& item) { | ||
145 | State* st = reinterpret_cast<State*>(item.user_data); | ||
146 | st->indents.pop(); | ||
147 | return true; | ||
148 | }); | ||
149 | |||
150 | extern rule Block; | ||
151 | |||
152 | rule InBlock = Advance >> Block >> PopIndent; | ||
153 | |||
154 | extern rule NameList; | ||
155 | |||
156 | rule local_flag = expr('*') | expr('^'); | ||
157 | rule Local = key("local") >> ((Space >> local_flag) | NameList); | ||
158 | |||
159 | rule colon_import_name = sym('\\') >> Space >> Variable; | ||
160 | rule ImportName = colon_import_name | Space >> Variable; | ||
161 | rule ImportNameList = Seperator >> *SpaceBreak >> ImportName >> *((+SpaceBreak | sym(',') >> *SpaceBreak) >> ImportName); | ||
162 | |||
163 | extern rule Exp; | ||
164 | |||
165 | rule Import = key("import") >> ImportNameList >> *SpaceBreak >> key("from") >> Exp; | ||
166 | rule BreakLoop = (expr("break") | expr("continue")) >> not_(AlphaNum); | ||
167 | |||
168 | extern rule ExpListLow, ExpList, Assign; | ||
169 | |||
170 | rule Return = key("return") >> -ExpListLow; | ||
171 | rule WithExp = ExpList >> -Assign; | ||
172 | |||
173 | extern rule DisableDo, PopDo, Body; | ||
174 | |||
175 | rule With = key("with") >> DisableDo >> ensure(WithExp, PopDo) >> -key("do") >> Body; | ||
176 | rule SwitchCase = key("when") >> ExpList >> -key("then") >> Body; | ||
177 | rule SwitchElse = key("else") >> Body; | ||
178 | |||
179 | rule SwitchBlock = *EmptyLine >> | ||
180 | Advance >> Seperator >> | ||
181 | SwitchCase >> | ||
182 | *(+SpaceBreak >> SwitchCase) >> | ||
183 | -(+SpaceBreak >> SwitchElse) >> | ||
184 | PopIndent; | ||
185 | |||
186 | rule Switch = key("switch") >> | ||
187 | DisableDo >> ensure(Exp, PopDo) >> | ||
188 | -key("do") >> -Space >> Break >> SwitchBlock; | ||
189 | |||
190 | rule IfCond = Exp >> -Assign; | ||
191 | rule IfElseIf = -(Break >> *EmptyLine >> CheckIndent) >> key("elseif") >> IfCond >> -key("then") >> Body; | ||
192 | rule IfElse = -(Break >> *EmptyLine >> CheckIndent) >> key("else") >> Body; | ||
193 | rule If = key("if") >> Seperator >> IfCond >> -key("then") >> Body >> *IfElseIf >> -IfElse; | ||
194 | rule Unless = key("unless") >> Seperator >> IfCond >> -key("then") >> Body >> *IfElseIf >> -IfElse; | ||
195 | |||
196 | rule While = key("while") >> DisableDo >> ensure(Exp, PopDo) >> -key("do") >> Body; | ||
197 | |||
198 | rule for_step_value = sym(',') >> Exp; | ||
199 | rule for_args = Space >> Variable >> sym('=') >> Exp >> sym(',') >> Exp >> -for_step_value; | ||
200 | |||
201 | rule For = key("for") >> DisableDo >> | ||
202 | ensure(for_args, PopDo) >> | ||
203 | -key("do") >> Body; | ||
204 | |||
205 | extern rule AssignableNameList; | ||
206 | |||
207 | extern rule star_exp; | ||
208 | |||
209 | rule for_in = star_exp | ExpList; | ||
210 | |||
211 | rule ForEach = key("for") >> AssignableNameList >> key("in") >> | ||
212 | DisableDo >> ensure(for_in, PopDo) >> | ||
213 | -key("do") >> Body; | ||
214 | |||
215 | rule Do = pl::user(key("do") >> Body, [](const item_t& item) | ||
216 | { | ||
217 | State* st = reinterpret_cast<State*>(item.user_data); | ||
218 | return st->doStack.empty() || st->doStack.top(); | ||
219 | }); | ||
220 | |||
221 | rule DisableDo = pl::user(true_(), [](const item_t& item) | ||
222 | { | ||
223 | State* st = reinterpret_cast<State*>(item.user_data); | ||
224 | st->doStack.push(false); | ||
225 | return true; | ||
226 | }); | ||
227 | |||
228 | rule PopDo = pl::user(true_(), [](const item_t& item) | ||
229 | { | ||
230 | State* st = reinterpret_cast<State*>(item.user_data); | ||
231 | st->doStack.pop(); | ||
232 | return true; | ||
233 | }); | ||
234 | |||
235 | extern rule CompInner; | ||
236 | |||
237 | rule Comprehension = sym('[') >> Exp >> CompInner >> sym(']'); | ||
238 | rule comp_value = sym(',') >> Exp; | ||
239 | rule TblComprehension = sym('{') >> (Exp >> -comp_value) >> CompInner >> sym('}'); | ||
240 | |||
241 | extern rule CompForEach, CompFor, CompClause; | ||
242 | |||
243 | rule CompInner = Seperator >> (CompForEach | CompFor) >> *CompClause; | ||
244 | rule star_exp = sym('*') >> Exp; | ||
245 | rule CompForEach = key("for") >> AssignableNameList >> key("in") >> (star_exp | Exp); | ||
246 | rule CompFor = key("for") >> Space >> Variable >> sym('=') >> Exp >> sym(',') >> Exp >> -for_step_value; | ||
247 | rule CompClause = CompFor | CompForEach | key("when") >> Exp; | ||
248 | |||
249 | extern rule TableBlock; | ||
250 | |||
251 | rule Assign = sym('=') >> Seperator >> (With | If | Switch | TableBlock | Exp >> *((sym(',') | sym(';')) >> Exp)); | ||
252 | |||
253 | rule update_op = | ||
254 | expr("..") | | ||
255 | expr("+") | | ||
256 | expr("-") | | ||
257 | expr("*") | | ||
258 | expr("/") | | ||
259 | expr("%") | | ||
260 | expr("or") | | ||
261 | expr("and") | | ||
262 | expr("&") | | ||
263 | expr("|") | | ||
264 | expr(">>") | | ||
265 | expr("<<"); | ||
266 | |||
267 | rule Update = Space >> update_op >> expr("=") >> Exp; | ||
268 | |||
269 | rule BinaryOperator = | ||
270 | (expr("or") >> not_(AlphaNum)) | | ||
271 | (expr("and") >> not_(AlphaNum)) | | ||
272 | expr("<=") | | ||
273 | expr(">=") | | ||
274 | expr("~=") | | ||
275 | expr("!=") | | ||
276 | expr("==") | | ||
277 | expr("..") | | ||
278 | expr("<<") | | ||
279 | expr(">>") | | ||
280 | expr("//") | | ||
281 | set("+-*/%^><|&"); | ||
282 | |||
283 | extern rule AssignableChain; | ||
284 | |||
285 | rule Assignable = AssignableChain | Space >> Variable | SelfName; | ||
286 | |||
287 | extern rule Value; | ||
288 | |||
289 | rule exp_op_value = Space >> BinaryOperator >> *SpaceBreak >> Value; | ||
290 | rule Exp = Value >> *exp_op_value; | ||
291 | |||
292 | extern rule Chain, Callable, InvokeArgs; | ||
293 | |||
294 | rule ChainValue = Seperator >> (Chain | Callable) >> -InvokeArgs; | ||
295 | |||
296 | extern rule KeyValue, String, SimpleValue; | ||
297 | |||
298 | rule simple_table = Seperator >> KeyValue >> *(sym(',') >> KeyValue); | ||
299 | rule Value = SimpleValue | simple_table | ChainValue | String; | ||
300 | |||
301 | extern rule LuaString; | ||
302 | |||
303 | rule single_string_inner = expr("\\'") | "\\\\" | not_(expr('\'')) >> Any; | ||
304 | rule SingleString = symx('\'') >> *single_string_inner >> sym('\''); | ||
305 | rule interp = symx("#{") >> Exp >> sym('}'); | ||
306 | rule double_string_plain = expr("\\\"") | "\\\\" | not_(expr('"')) >> Any; | ||
307 | rule double_string_inner = +(not_(interp) >> double_string_plain); | ||
308 | rule double_string_content = double_string_inner | interp; | ||
309 | rule DoubleString = symx('"') >> Seperator >> *double_string_content >> sym('"'); | ||
310 | rule String = Space >> (DoubleString | SingleString | LuaString); | ||
311 | |||
312 | rule lua_string_open = '[' >> *expr('=') >> '['; | ||
313 | rule lua_string_close = ']' >> *expr('=') >> ']'; | ||
314 | |||
315 | rule LuaStringOpen = pl::user(lua_string_open, [](const item_t& item) | ||
316 | { | ||
317 | size_t count = std::distance(item.begin, item.end); | ||
318 | State* st = reinterpret_cast<State*>(item.user_data); | ||
319 | st->stringOpen = count; | ||
320 | return true; | ||
321 | }); | ||
322 | |||
323 | rule LuaStringClose = pl::user(lua_string_close, [](const item_t& item) | ||
324 | { | ||
325 | size_t count = std::distance(item.begin, item.end); | ||
326 | State* st = reinterpret_cast<State*>(item.user_data); | ||
327 | return st->stringOpen == count; | ||
328 | }); | ||
329 | |||
330 | rule LuaStringContent = *(not_(LuaStringClose) >> (Break | Any)); | ||
331 | |||
332 | rule LuaString = pl::user(LuaStringOpen >> -Break >> LuaStringContent >> LuaStringClose, [](const item_t& item) | ||
333 | { | ||
334 | State* st = reinterpret_cast<State*>(item.user_data); | ||
335 | st->stringOpen = -1; | ||
336 | return true; | ||
337 | }); | ||
338 | |||
339 | rule Parens = sym('(') >> *SpaceBreak >> Exp >> *SpaceBreak >> sym(')'); | ||
340 | rule Callable = Space >> Variable | SelfName | VarArg | Parens; | ||
341 | rule FnArgsExpList = Exp >> *((Break | sym(',')) >> White >> Exp); | ||
342 | |||
343 | rule FnArgs = (symx('(') >> *SpaceBreak >> -FnArgsExpList >> *SpaceBreak >> sym(')')) | | ||
344 | (sym('!') >> not_(expr('='))); | ||
345 | |||
346 | extern rule ChainItems, DotChainItem, ColonChain; | ||
347 | |||
348 | rule chain_call = (Callable | String) >> ChainItems; | ||
349 | rule chain_item = and_(set(".\\")) >> ChainItems; | ||
350 | rule chain_dot_chain = DotChainItem >> -ChainItems; | ||
351 | |||
352 | rule Chain = chain_call | chain_item | | ||
353 | Space >> (chain_dot_chain | ColonChain); | ||
354 | |||
355 | rule AssignableChain = Seperator >> Chain; | ||
356 | |||
357 | extern rule ChainItem; | ||
358 | |||
359 | rule chain_with_colon = +ChainItem >> -ColonChain; | ||
360 | rule ChainItems = chain_with_colon | ColonChain; | ||
361 | |||
362 | extern rule Invoke, Slice; | ||
363 | |||
364 | rule Index = symx('[') >> Exp >> sym(']'); | ||
365 | rule ChainItem = Invoke | DotChainItem | Slice | Index; | ||
366 | rule DotChainItem = symx('.') >> Name; | ||
367 | rule ColonChainItem = symx('\\') >> (LuaKeyword | Name); | ||
368 | rule invoke_chain = Invoke >> -ChainItems; | ||
369 | rule ColonChain = ColonChainItem >> -invoke_chain; | ||
370 | |||
371 | rule default_value = true_(); | ||
372 | rule Slice = | ||
373 | symx('[') >> | ||
374 | (Exp | default_value) >> | ||
375 | sym(',') >> | ||
376 | (Exp | default_value) >> | ||
377 | (sym(',') >> Exp | default_value) >> | ||
378 | sym(']'); | ||
379 | |||
380 | rule Invoke = Seperator >> ( | ||
381 | FnArgs | | ||
382 | SingleString | | ||
383 | DoubleString | | ||
384 | and_(expr('[')) >> LuaString); | ||
385 | |||
386 | extern rule TableValueList, TableLitLine; | ||
387 | |||
388 | rule TableValue = KeyValue | Exp; | ||
389 | |||
390 | rule table_lit_lines = SpaceBreak >> TableLitLine >> *(-sym(',') >> SpaceBreak >> TableLitLine) >> -sym(','); | ||
391 | |||
392 | rule TableLit = | ||
393 | sym('{') >> Seperator >> | ||
394 | -TableValueList >> | ||
395 | -sym(',') >> | ||
396 | -table_lit_lines >> | ||
397 | White >> sym('}'); | ||
398 | |||
399 | rule TableValueList = TableValue >> *(sym(',') >> TableValue); | ||
400 | |||
401 | rule TableLitLine = | ||
402 | ( | ||
403 | PushIndent >> (TableValueList >> PopIndent | PopIndent) | ||
404 | ) | ( | ||
405 | Space | ||
406 | ); | ||
407 | |||
408 | extern rule KeyValueLine; | ||
409 | |||
410 | rule TableBlockInner = Seperator >> KeyValueLine >> *(+(SpaceBreak) >> KeyValueLine); | ||
411 | rule TableBlock = +(SpaceBreak) >> Advance >> ensure(TableBlockInner, PopIndent); | ||
412 | |||
413 | extern rule Statement; | ||
414 | |||
415 | rule class_member_list = Seperator >> KeyValue >> *(sym(',') >> KeyValue); | ||
416 | rule ClassLine = CheckIndent >> (class_member_list | Statement) >> -sym(','); | ||
417 | rule ClassBlock = +(SpaceBreak) >> Advance >>Seperator >> ClassLine >> *(+(SpaceBreak) >> ClassLine) >> PopIndent; | ||
418 | |||
419 | rule ClassDecl = | ||
420 | key("class") >> not_(expr(':')) >> | ||
421 | -Assignable >> | ||
422 | -(key("extends") >> PreventIndent >> ensure(Exp, PopIndent)) >> | ||
423 | -ClassBlock; | ||
424 | |||
425 | rule export_values = NameList >> -(sym('=') >> ExpListLow); | ||
426 | rule export_op = expr('*') | expr('^'); | ||
427 | rule Export = key("export") >> (ClassDecl | (Space >> export_op) | export_values); | ||
428 | |||
429 | rule variable_pair = sym(':') >> not_(SomeSpace) >> Space >> Variable; | ||
430 | |||
431 | rule normal_pair = | ||
432 | ( | ||
433 | KeyName | | ||
434 | sym('[') >> Exp >> sym(']') | | ||
435 | Space >> DoubleString | | ||
436 | Space >> SingleString | ||
437 | ) >> | ||
438 | symx(':') >> | ||
439 | (Exp | TableBlock | +(SpaceBreak) >> Exp); | ||
440 | |||
441 | rule KeyValue = variable_pair | normal_pair; | ||
442 | |||
443 | rule KeyValueList = KeyValue >> *(sym(',') >> KeyValue); | ||
444 | rule KeyValueLine = CheckIndent >> KeyValueList >> -sym(','); | ||
445 | |||
446 | rule FnArgDef = (Space >> Variable | SelfName) >> -(sym('=') >> Exp); | ||
447 | |||
448 | rule FnArgDefList = Seperator >> | ||
449 | ( | ||
450 | ( | ||
451 | FnArgDef >> | ||
452 | *((sym(',') | Break) >> White >> FnArgDef) >> | ||
453 | -((sym(',') | Break) >> White >> VarArg) | ||
454 | ) | ( | ||
455 | VarArg | ||
456 | ) | ||
457 | ); | ||
458 | |||
459 | rule outer_var_shadow = key("using") >> (NameList | Space >> expr("nil")); | ||
460 | |||
461 | rule FnArgsDef = sym('(') >> White >> -FnArgDefList >> -outer_var_shadow >> White >> sym(')'); | ||
462 | rule fn_arrow = expr("->") | expr("=>"); | ||
463 | rule FunLit = -FnArgsDef >> Space >> fn_arrow >> -Body; | ||
464 | |||
465 | rule NameList = Seperator >> Space >> Variable >> *(sym(',') >> Space >> Variable); | ||
466 | rule NameOrDestructure = Space >> Variable | TableLit; | ||
467 | rule AssignableNameList = Seperator >> NameOrDestructure >> *(sym(',') >> NameOrDestructure); | ||
468 | |||
469 | rule ExpList = Seperator >> Exp >> *(sym(',') >> Exp); | ||
470 | rule ExpListLow = Seperator >> Exp >> *((sym(',') | sym(';')) >> Exp); | ||
471 | |||
472 | rule ArgLine = CheckIndent >> Exp >> *(sym(',') >> Exp); | ||
473 | rule ArgBlock = ArgLine >> *(sym(',') >> SpaceBreak >> ArgLine) >> PopIndent; | ||
474 | |||
475 | rule invoke_args_with_table = | ||
476 | sym(',') >> | ||
477 | ( | ||
478 | TableBlock | | ||
479 | SpaceBreak >> Advance >> ArgBlock >> -TableBlock | ||
480 | ); | ||
481 | |||
482 | rule InvokeArgs = | ||
483 | not_(expr('-')) >> Seperator >> | ||
484 | ( | ||
485 | Exp >> *(sym(',') >> Exp) >> -(invoke_args_with_table | TableBlock) | | ||
486 | TableBlock | ||
487 | ); | ||
488 | |||
489 | rule const_value = (expr("nil") | expr("true") | expr("false")) >> not_(AlphaNum); | ||
490 | rule minus_exp = expr('-') >> not_(SomeSpace) >> Exp; | ||
491 | rule sharp_exp = expr('#') >> Exp; | ||
492 | rule tilde_exp = expr('~') >> Exp; | ||
493 | rule not_exp = expr("not") >> not_(AlphaNum) >> Exp; | ||
494 | rule unary_exp = minus_exp | sharp_exp | tilde_exp | not_exp; | ||
495 | |||
496 | rule SimpleValue = | ||
497 | (Space >> const_value) | | ||
498 | If | Unless | Switch | With | ClassDecl | ForEach | For | While | Do | | ||
499 | (Space >> unary_exp) | | ||
500 | TblComprehension | TableLit | Comprehension | FunLit | | ||
501 | (Space >> Num); | ||
502 | |||
503 | rule ExpListAssign = ExpList >> -(Update | Assign); | ||
504 | |||
505 | rule if_else_line = key("if") >> Exp >> (key("else") >> Exp | default_value); | ||
506 | rule unless_line = key("unless") >> Exp; | ||
507 | |||
508 | rule statement_appendix = (if_else_line | unless_line | CompInner) >> Space; | ||
509 | rule Statement = | ||
510 | ( | ||
511 | Import | While | For | ForEach | | ||
512 | Return | Local | Export | Space >> BreakLoop | | ||
513 | ExpListAssign | ||
514 | ) >> Space >> | ||
515 | -statement_appendix; | ||
516 | |||
517 | rule Body = -Space >> Break >> *EmptyLine >> InBlock | Statement; | ||
518 | |||
519 | rule empty_line_stop = Space >> and_(Stop); | ||
520 | rule Line = CheckIndent >> Statement | empty_line_stop; | ||
521 | rule Block = Seperator >> Line >> *(+Break >> Line); | ||
522 | |||
523 | rule Shebang = expr("#!") >> *(not_(Stop) >> Any); | ||
524 | rule File = White >> -Shebang >> Block >> eof(); | ||
525 | |||
526 | } // namespace MoonP | ||
diff --git a/src/MoonP/moon_parser.h b/src/MoonP/moon_parser.h new file mode 100644 index 0000000..fc4ee55 --- /dev/null +++ b/src/MoonP/moon_parser.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* Copyright (c) 2020 Jin Li, http://www.luvfight.me | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
4 | |||
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
6 | |||
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ | ||
8 | |||
9 | #pragma once | ||
10 | |||
11 | #include <string> | ||
12 | #include <codecvt> | ||
13 | #include <unordered_set> | ||
14 | #include <stack> | ||
15 | #include <algorithm> | ||
16 | #include <vector> | ||
17 | #include "MoonP/ast.hpp" | ||
18 | using namespace parserlib; | ||
19 | |||
20 | namespace MoonP { | ||
21 | |||
22 | struct State { | ||
23 | State() { | ||
24 | indents.push(0); | ||
25 | stringOpen = -1; | ||
26 | } | ||
27 | std::string buffer; | ||
28 | size_t stringOpen; | ||
29 | std::stack<int> indents; | ||
30 | std::stack<bool> doStack; | ||
31 | static std::unordered_set<std::string> luaKeywords; | ||
32 | static std::unordered_set<std::string> keywords; | ||
33 | }; | ||
34 | |||
35 | } // namespace MoonP | ||
diff --git a/src/MoonP/parser.cpp b/src/MoonP/parser.cpp new file mode 100644 index 0000000..19c0068 --- /dev/null +++ b/src/MoonP/parser.cpp | |||
@@ -0,0 +1,1439 @@ | |||
1 | /* Copyright (c) 2012, Achilleas Margaritis, modified by Jin Li | ||
2 | All rights reserved. | ||
3 | |||
4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | ||
5 | |||
6 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | ||
7 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | ||
8 | |||
9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | ||
10 | |||
11 | #include <cstdlib> | ||
12 | #include <cstring> | ||
13 | #include <cassert> | ||
14 | #include <stdexcept> | ||
15 | #include <unordered_map> | ||
16 | #include <unordered_set> | ||
17 | |||
18 | #include "MoonP/parser.hpp" | ||
19 | |||
20 | |||
21 | namespace parserlib { | ||
22 | |||
23 | |||
24 | //internal map from rules to parse procs | ||
25 | typedef std::unordered_map<rule *, parse_proc> _parse_proc_map_t; | ||
26 | |||
27 | //on exit, it deletes the parse proc map | ||
28 | static _parse_proc_map_t& _get_parse_proc_map() { | ||
29 | static _parse_proc_map_t _parse_proc_map; | ||
30 | return _parse_proc_map; | ||
31 | } | ||
32 | |||
33 | |||
34 | //get the parse proc from the map | ||
35 | static parse_proc _get_parse_proc(rule *r) { | ||
36 | _parse_proc_map_t& _parse_proc_map = _get_parse_proc_map(); | ||
37 | _parse_proc_map_t::iterator it = _parse_proc_map.find(r); | ||
38 | if (it == _parse_proc_map.end()) return 0; | ||
39 | return it->second; | ||
40 | } | ||
41 | |||
42 | |||
43 | //internal private class that manages access to the public classes' internals. | ||
44 | class _private { | ||
45 | public: | ||
46 | //get the internal expression object from the expression. | ||
47 | static _expr *get_expr(const expr &e) { | ||
48 | return e.m_expr; | ||
49 | } | ||
50 | |||
51 | //create new expression from given expression | ||
52 | static expr construct_expr(_expr *e) { | ||
53 | return e; | ||
54 | } | ||
55 | |||
56 | //get the internal expression object from the rule. | ||
57 | static _expr *get_expr(rule &r) { | ||
58 | return r.m_expr; | ||
59 | } | ||
60 | |||
61 | //get the internal parse proc from the rule. | ||
62 | static parse_proc get_parse_proc(rule &r) { | ||
63 | return r.m_parse_proc; | ||
64 | } | ||
65 | }; | ||
66 | |||
67 | |||
68 | class _context; | ||
69 | |||
70 | |||
71 | //parser state | ||
72 | class _state { | ||
73 | public: | ||
74 | //position | ||
75 | pos m_pos; | ||
76 | |||
77 | //size of match vector | ||
78 | size_t m_matches; | ||
79 | |||
80 | //constructor | ||
81 | _state(_context &con); | ||
82 | }; | ||
83 | |||
84 | |||
85 | //match | ||
86 | class _match { | ||
87 | public: | ||
88 | //rule matched | ||
89 | rule *m_rule; | ||
90 | |||
91 | //begin position | ||
92 | pos m_begin; | ||
93 | |||
94 | //end position | ||
95 | pos m_end; | ||
96 | |||
97 | //null constructor | ||
98 | _match() {} | ||
99 | |||
100 | //constructor from parameters | ||
101 | _match(rule *r, const pos &b, const pos &e) : | ||
102 | m_rule(r), | ||
103 | m_begin(b), | ||
104 | m_end(e) | ||
105 | { | ||
106 | } | ||
107 | }; | ||
108 | |||
109 | |||
110 | //match vector | ||
111 | typedef std::vector<_match> _match_vector; | ||
112 | |||
113 | |||
114 | //parsing context | ||
115 | class _context { | ||
116 | public: | ||
117 | //user data | ||
118 | void* m_user_data; | ||
119 | |||
120 | //current position | ||
121 | pos m_pos; | ||
122 | |||
123 | //error position | ||
124 | pos m_error_pos; | ||
125 | |||
126 | //input begin | ||
127 | input::iterator m_begin; | ||
128 | |||
129 | //input end | ||
130 | input::iterator m_end; | ||
131 | |||
132 | //matches | ||
133 | _match_vector m_matches; | ||
134 | |||
135 | //constructor | ||
136 | _context(input &i, void* ud) : | ||
137 | m_user_data(ud), | ||
138 | m_pos(i), | ||
139 | m_error_pos(i), | ||
140 | m_begin(i.begin()), | ||
141 | m_end(i.end()) | ||
142 | { | ||
143 | } | ||
144 | |||
145 | //check if the end is reached | ||
146 | bool end() const { | ||
147 | return m_pos.m_it == m_end; | ||
148 | } | ||
149 | |||
150 | //get the current symbol | ||
151 | input::value_type symbol() const { | ||
152 | assert(!end()); | ||
153 | return *m_pos.m_it; | ||
154 | } | ||
155 | |||
156 | //set the longest possible error | ||
157 | void set_error_pos() { | ||
158 | if (m_pos.m_it > m_error_pos.m_it) { | ||
159 | m_error_pos = m_pos; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | //next column | ||
164 | void next_col() { | ||
165 | ++m_pos.m_it; | ||
166 | ++m_pos.m_col; | ||
167 | } | ||
168 | |||
169 | //next line | ||
170 | void next_line() { | ||
171 | ++m_pos.m_line; | ||
172 | m_pos.m_col = 1; | ||
173 | } | ||
174 | |||
175 | //restore the state | ||
176 | void restore(const _state &st) { | ||
177 | m_pos = st.m_pos; | ||
178 | m_matches.resize(st.m_matches); | ||
179 | } | ||
180 | |||
181 | //parse non-term rule. | ||
182 | bool parse_non_term(rule &r); | ||
183 | |||
184 | //parse term rule. | ||
185 | bool parse_term(rule &r); | ||
186 | |||
187 | //execute all the parse procs | ||
188 | void do_parse_procs(void *d) const { | ||
189 | for(_match_vector::const_iterator it = m_matches.begin(); | ||
190 | it != m_matches.end(); | ||
191 | ++it) | ||
192 | { | ||
193 | const _match &m = *it; | ||
194 | parse_proc p = _private::get_parse_proc(*m.m_rule); | ||
195 | p(m.m_begin, m.m_end, d); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | private: | ||
200 | //parse non-term rule. | ||
201 | bool _parse_non_term(rule &r); | ||
202 | |||
203 | //parse term rule. | ||
204 | bool _parse_term(rule &r); | ||
205 | }; | ||
206 | |||
207 | |||
208 | //base class for expressions | ||
209 | class _expr { | ||
210 | public: | ||
211 | //destructor. | ||
212 | virtual ~_expr() { | ||
213 | } | ||
214 | |||
215 | //parse with whitespace | ||
216 | virtual bool parse_non_term(_context &con) const = 0; | ||
217 | |||
218 | //parse terminal | ||
219 | virtual bool parse_term(_context &con) const = 0; | ||
220 | }; | ||
221 | |||
222 | |||
223 | //single character expression. | ||
224 | class _char : public _expr { | ||
225 | public: | ||
226 | //constructor. | ||
227 | _char(char c) : | ||
228 | m_char(c) | ||
229 | { | ||
230 | } | ||
231 | |||
232 | //parse with whitespace | ||
233 | virtual bool parse_non_term(_context &con) const { | ||
234 | return _parse(con); | ||
235 | } | ||
236 | |||
237 | //parse terminal | ||
238 | virtual bool parse_term(_context &con) const { | ||
239 | return _parse(con); | ||
240 | } | ||
241 | |||
242 | private: | ||
243 | //character | ||
244 | input::value_type m_char; | ||
245 | |||
246 | //internal parse | ||
247 | bool _parse(_context &con) const { | ||
248 | if (!con.end()) { | ||
249 | input::value_type ch = con.symbol(); | ||
250 | if (ch == m_char) { | ||
251 | con.next_col(); | ||
252 | return true; | ||
253 | } | ||
254 | } | ||
255 | con.set_error_pos(); | ||
256 | return false; | ||
257 | } | ||
258 | }; | ||
259 | |||
260 | |||
261 | //string expression. | ||
262 | class _string : public _expr { | ||
263 | public: | ||
264 | //constructor from ansi string. | ||
265 | _string(const char *s) : | ||
266 | m_string(Converter{}.from_bytes(s)) | ||
267 | { | ||
268 | } | ||
269 | |||
270 | //parse with whitespace | ||
271 | virtual bool parse_non_term(_context &con) const { | ||
272 | return _parse(con); | ||
273 | } | ||
274 | |||
275 | //parse terminal | ||
276 | virtual bool parse_term(_context &con) const { | ||
277 | return _parse(con); | ||
278 | } | ||
279 | |||
280 | private: | ||
281 | //string | ||
282 | input m_string; | ||
283 | |||
284 | //parse the string | ||
285 | bool _parse(_context &con) const { | ||
286 | for(input::const_iterator it = m_string.begin(), | ||
287 | end = m_string.end();;) | ||
288 | { | ||
289 | if (it == end) return true; | ||
290 | if (con.end()) break; | ||
291 | if (con.symbol() != *it) break; | ||
292 | ++it; | ||
293 | con.next_col(); | ||
294 | } | ||
295 | con.set_error_pos(); | ||
296 | return false; | ||
297 | } | ||
298 | }; | ||
299 | |||
300 | |||
301 | //set expression. | ||
302 | class _set : public _expr { | ||
303 | public: | ||
304 | //constructor from ansi string. | ||
305 | _set(const char *s) { | ||
306 | auto str = Converter{}.from_bytes(s); | ||
307 | for (auto ch : str) { | ||
308 | _add(ch); | ||
309 | } | ||
310 | } | ||
311 | |||
312 | //constructor from range. | ||
313 | _set(int min, int max) { | ||
314 | assert(min >= 0); | ||
315 | assert(min <= max); | ||
316 | m_quick_set.resize((size_t)max + 1U); | ||
317 | for(; min <= max; ++min) { | ||
318 | m_quick_set[(size_t)min] = true; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | //parse with whitespace | ||
323 | virtual bool parse_non_term(_context &con) const { | ||
324 | return _parse(con); | ||
325 | } | ||
326 | |||
327 | //parse terminal | ||
328 | virtual bool parse_term(_context &con) const { | ||
329 | return _parse(con); | ||
330 | } | ||
331 | |||
332 | private: | ||
333 | //set is kept as an array of flags, for quick access | ||
334 | std::vector<bool> m_quick_set; | ||
335 | std::unordered_set<size_t> m_large_set; | ||
336 | |||
337 | //add character | ||
338 | void _add(size_t i) { | ||
339 | if (i <= m_quick_set.size() || i <= 255) { | ||
340 | if (i >= m_quick_set.size()) { | ||
341 | m_quick_set.resize(i + 1); | ||
342 | } | ||
343 | m_quick_set[i] = true; | ||
344 | } else { | ||
345 | m_large_set.insert(i); | ||
346 | } | ||
347 | } | ||
348 | |||
349 | //internal parse | ||
350 | bool _parse(_context &con) const { | ||
351 | if (!con.end()) { | ||
352 | size_t ch = con.symbol(); | ||
353 | if (ch < m_quick_set.size()) { | ||
354 | if (m_quick_set[ch]) { | ||
355 | con.next_col(); | ||
356 | return true; | ||
357 | } | ||
358 | } else if (m_large_set.find(ch) != m_large_set.end()) { | ||
359 | con.next_col(); | ||
360 | return true; | ||
361 | } | ||
362 | } | ||
363 | con.set_error_pos(); | ||
364 | return false; | ||
365 | } | ||
366 | }; | ||
367 | |||
368 | |||
369 | //base class for unary expressions | ||
370 | class _unary : public _expr { | ||
371 | public: | ||
372 | //constructor. | ||
373 | _unary(_expr *e) : | ||
374 | m_expr(e) | ||
375 | { | ||
376 | } | ||
377 | |||
378 | //destructor. | ||
379 | virtual ~_unary() { | ||
380 | delete m_expr; | ||
381 | } | ||
382 | |||
383 | protected: | ||
384 | //expression | ||
385 | _expr *m_expr; | ||
386 | }; | ||
387 | |||
388 | |||
389 | //terminal | ||
390 | class _term : public _unary { | ||
391 | public: | ||
392 | //constructor. | ||
393 | _term(_expr *e) : | ||
394 | _unary(e) | ||
395 | { | ||
396 | } | ||
397 | |||
398 | //parse with whitespace | ||
399 | virtual bool parse_non_term(_context &con) const { | ||
400 | return m_expr->parse_term(con); | ||
401 | } | ||
402 | |||
403 | //parse terminal | ||
404 | virtual bool parse_term(_context &con) const { | ||
405 | return m_expr->parse_term(con); | ||
406 | } | ||
407 | }; | ||
408 | |||
409 | |||
410 | //user | ||
411 | class _user : public _unary { | ||
412 | public: | ||
413 | //constructor. | ||
414 | _user(_expr *e, const user_handler &callback) : | ||
415 | _unary(e), | ||
416 | m_handler(callback) | ||
417 | { | ||
418 | } | ||
419 | |||
420 | //parse with whitespace | ||
421 | virtual bool parse_non_term(_context &con) const { | ||
422 | pos pos = con.m_pos; | ||
423 | if (m_expr->parse_non_term(con)) { | ||
424 | item_t item = {pos.m_it, con.m_pos.m_it, con.m_user_data}; | ||
425 | return m_handler(item); | ||
426 | } | ||
427 | return false; | ||
428 | } | ||
429 | |||
430 | //parse terminal | ||
431 | virtual bool parse_term(_context &con) const { | ||
432 | pos pos = con.m_pos; | ||
433 | if (m_expr->parse_term(con)) { | ||
434 | item_t item = {pos.m_it, con.m_pos.m_it, con.m_user_data}; | ||
435 | return m_handler(item); | ||
436 | } | ||
437 | return false; | ||
438 | } | ||
439 | private: | ||
440 | user_handler m_handler; | ||
441 | }; | ||
442 | |||
443 | |||
444 | //loop 0 | ||
445 | class _loop0 : public _unary { | ||
446 | public: | ||
447 | //constructor. | ||
448 | _loop0(_expr *e) : | ||
449 | _unary(e) | ||
450 | { | ||
451 | } | ||
452 | |||
453 | //parse with whitespace | ||
454 | virtual bool parse_non_term(_context &con) const { | ||
455 | //if parsing of the first fails, restore the context and stop | ||
456 | _state st(con); | ||
457 | if (!m_expr->parse_non_term(con)) { | ||
458 | con.restore(st); | ||
459 | return true; | ||
460 | } | ||
461 | |||
462 | //parse the rest | ||
463 | for(;;) { | ||
464 | _state st(con); | ||
465 | if (!m_expr->parse_non_term(con)) { | ||
466 | con.restore(st); | ||
467 | break; | ||
468 | } | ||
469 | } | ||
470 | |||
471 | return true; | ||
472 | } | ||
473 | |||
474 | //parse terminal | ||
475 | virtual bool parse_term(_context &con) const { | ||
476 | //if parsing of the first fails, restore the context and stop | ||
477 | _state st(con); | ||
478 | if (!m_expr->parse_term(con)) { | ||
479 | con.restore(st); | ||
480 | return true; | ||
481 | } | ||
482 | |||
483 | //parse the rest until no more parsing is possible | ||
484 | for(;;) { | ||
485 | _state st(con); | ||
486 | if (!m_expr->parse_term(con)) { | ||
487 | con.restore(st); | ||
488 | break; | ||
489 | } | ||
490 | } | ||
491 | |||
492 | return true; | ||
493 | } | ||
494 | }; | ||
495 | |||
496 | |||
497 | //loop 1 | ||
498 | class _loop1 : public _unary { | ||
499 | public: | ||
500 | //constructor. | ||
501 | _loop1(_expr *e) : | ||
502 | _unary(e) | ||
503 | { | ||
504 | } | ||
505 | |||
506 | //parse with whitespace | ||
507 | virtual bool parse_non_term(_context &con) const { | ||
508 | //parse the first; if the first fails, stop | ||
509 | if (!m_expr->parse_non_term(con)) return false; | ||
510 | |||
511 | //parse the rest until no more parsing is possible | ||
512 | for(;;) { | ||
513 | _state st(con); | ||
514 | if (!m_expr->parse_non_term(con)) { | ||
515 | con.restore(st); | ||
516 | break; | ||
517 | } | ||
518 | } | ||
519 | |||
520 | return true; | ||
521 | } | ||
522 | |||
523 | //parse terminal | ||
524 | virtual bool parse_term(_context &con) const { | ||
525 | //parse the first; if the first fails, stop | ||
526 | if (!m_expr->parse_term(con)) return false; | ||
527 | |||
528 | //parse the rest until no more parsing is possible | ||
529 | for(;;) { | ||
530 | _state st(con); | ||
531 | if (!m_expr->parse_term(con)) { | ||
532 | con.restore(st); | ||
533 | break; | ||
534 | } | ||
535 | } | ||
536 | |||
537 | return true; | ||
538 | } | ||
539 | }; | ||
540 | |||
541 | |||
542 | //optional | ||
543 | class _optional : public _unary { | ||
544 | public: | ||
545 | //constructor. | ||
546 | _optional(_expr *e) : | ||
547 | _unary(e) | ||
548 | { | ||
549 | } | ||
550 | |||
551 | //parse with whitespace | ||
552 | virtual bool parse_non_term(_context &con) const { | ||
553 | _state st(con); | ||
554 | if (!m_expr->parse_non_term(con)) con.restore(st); | ||
555 | return true; | ||
556 | } | ||
557 | |||
558 | //parse terminal | ||
559 | virtual bool parse_term(_context &con) const { | ||
560 | _state st(con); | ||
561 | if (!m_expr->parse_term(con)) con.restore(st); | ||
562 | return true; | ||
563 | } | ||
564 | }; | ||
565 | |||
566 | |||
567 | //and | ||
568 | class _and : public _unary { | ||
569 | public: | ||
570 | //constructor. | ||
571 | _and(_expr *e) : | ||
572 | _unary(e) | ||
573 | { | ||
574 | } | ||
575 | |||
576 | //parse with whitespace | ||
577 | virtual bool parse_non_term(_context &con) const { | ||
578 | _state st(con); | ||
579 | bool ok = m_expr->parse_non_term(con); | ||
580 | con.restore(st); | ||
581 | return ok; | ||
582 | } | ||
583 | |||
584 | //parse terminal | ||
585 | virtual bool parse_term(_context &con) const { | ||
586 | _state st(con); | ||
587 | bool ok = m_expr->parse_term(con); | ||
588 | con.restore(st); | ||
589 | return ok; | ||
590 | } | ||
591 | }; | ||
592 | |||
593 | |||
594 | //not | ||
595 | class _not : public _unary { | ||
596 | public: | ||
597 | //constructor. | ||
598 | _not(_expr *e) : | ||
599 | _unary(e) | ||
600 | { | ||
601 | } | ||
602 | |||
603 | //parse with whitespace | ||
604 | virtual bool parse_non_term(_context &con) const { | ||
605 | _state st(con); | ||
606 | bool ok = !m_expr->parse_non_term(con); | ||
607 | con.restore(st); | ||
608 | return ok; | ||
609 | } | ||
610 | |||
611 | //parse terminal | ||
612 | virtual bool parse_term(_context &con) const { | ||
613 | _state st(con); | ||
614 | bool ok = !m_expr->parse_term(con); | ||
615 | con.restore(st); | ||
616 | return ok; | ||
617 | } | ||
618 | }; | ||
619 | |||
620 | |||
621 | //newline | ||
622 | class _nl : public _unary { | ||
623 | public: | ||
624 | //constructor. | ||
625 | _nl(_expr *e) : | ||
626 | _unary(e) | ||
627 | { | ||
628 | } | ||
629 | |||
630 | //parse with whitespace | ||
631 | virtual bool parse_non_term(_context &con) const { | ||
632 | if (!m_expr->parse_non_term(con)) return false; | ||
633 | con.next_line(); | ||
634 | return true; | ||
635 | } | ||
636 | |||
637 | //parse terminal | ||
638 | virtual bool parse_term(_context &con) const { | ||
639 | if (!m_expr->parse_term(con)) return false; | ||
640 | con.next_line(); | ||
641 | return true; | ||
642 | } | ||
643 | }; | ||
644 | |||
645 | |||
646 | //base class for binary expressions | ||
647 | class _binary : public _expr { | ||
648 | public: | ||
649 | //constructor. | ||
650 | _binary(_expr *left, _expr *right) : | ||
651 | m_left(left), m_right(right) | ||
652 | { | ||
653 | } | ||
654 | |||
655 | //destructor. | ||
656 | virtual ~_binary() { | ||
657 | delete m_left; | ||
658 | delete m_right; | ||
659 | } | ||
660 | |||
661 | protected: | ||
662 | //left and right expressions | ||
663 | _expr *m_left, *m_right; | ||
664 | }; | ||
665 | |||
666 | |||
667 | //sequence | ||
668 | class _seq : public _binary { | ||
669 | public: | ||
670 | //constructor. | ||
671 | _seq(_expr *left, _expr *right) : | ||
672 | _binary(left, right) | ||
673 | { | ||
674 | } | ||
675 | |||
676 | //parse with whitespace | ||
677 | virtual bool parse_non_term(_context &con) const { | ||
678 | if (!m_left->parse_non_term(con)) return false; | ||
679 | return m_right->parse_non_term(con); | ||
680 | } | ||
681 | |||
682 | //parse terminal | ||
683 | virtual bool parse_term(_context &con) const { | ||
684 | if (!m_left->parse_term(con)) return false; | ||
685 | return m_right->parse_term(con); | ||
686 | } | ||
687 | }; | ||
688 | |||
689 | |||
690 | //choice | ||
691 | class _choice : public _binary { | ||
692 | public: | ||
693 | //constructor. | ||
694 | _choice(_expr *left, _expr *right) : | ||
695 | _binary(left, right) | ||
696 | { | ||
697 | } | ||
698 | |||
699 | //parse with whitespace | ||
700 | virtual bool parse_non_term(_context &con) const { | ||
701 | _state st(con); | ||
702 | if (m_left->parse_non_term(con)) return true; | ||
703 | con.restore(st); | ||
704 | return m_right->parse_non_term(con); | ||
705 | } | ||
706 | |||
707 | //parse terminal | ||
708 | virtual bool parse_term(_context &con) const { | ||
709 | _state st(con); | ||
710 | if (m_left->parse_term(con)) return true; | ||
711 | con.restore(st); | ||
712 | return m_right->parse_term(con); | ||
713 | } | ||
714 | }; | ||
715 | |||
716 | |||
717 | //reference to rule | ||
718 | class _ref : public _expr { | ||
719 | public: | ||
720 | //constructor. | ||
721 | _ref(rule &r) : | ||
722 | m_rule(r) | ||
723 | { | ||
724 | } | ||
725 | |||
726 | //parse with whitespace | ||
727 | virtual bool parse_non_term(_context &con) const { | ||
728 | return con.parse_non_term(m_rule); | ||
729 | } | ||
730 | |||
731 | //parse terminal | ||
732 | virtual bool parse_term(_context &con) const { | ||
733 | return con.parse_term(m_rule); | ||
734 | } | ||
735 | |||
736 | private: | ||
737 | //reference | ||
738 | rule &m_rule; | ||
739 | }; | ||
740 | |||
741 | |||
742 | //eof | ||
743 | class _eof : public _expr { | ||
744 | public: | ||
745 | //parse with whitespace | ||
746 | virtual bool parse_non_term(_context &con) const { | ||
747 | return parse_term(con); | ||
748 | } | ||
749 | |||
750 | //parse terminal | ||
751 | virtual bool parse_term(_context &con) const { | ||
752 | return con.end(); | ||
753 | } | ||
754 | }; | ||
755 | |||
756 | |||
757 | //any | ||
758 | class _any : public _expr { | ||
759 | public: | ||
760 | //parse with whitespace | ||
761 | virtual bool parse_non_term(_context &con) const { | ||
762 | return parse_term(con); | ||
763 | } | ||
764 | |||
765 | //parse terminal | ||
766 | virtual bool parse_term(_context &con) const { | ||
767 | if (!con.end()) { | ||
768 | con.next_col(); | ||
769 | return true; | ||
770 | } | ||
771 | con.set_error_pos(); | ||
772 | return false; | ||
773 | } | ||
774 | }; | ||
775 | |||
776 | |||
777 | //true | ||
778 | class _true : public _expr { | ||
779 | public: | ||
780 | //parse with whitespace | ||
781 | virtual bool parse_non_term(_context &) const { | ||
782 | return true; | ||
783 | } | ||
784 | |||
785 | //parse terminal | ||
786 | virtual bool parse_term(_context &) const { | ||
787 | return true; | ||
788 | } | ||
789 | }; | ||
790 | |||
791 | |||
792 | //false | ||
793 | class _false: public _expr { | ||
794 | public: | ||
795 | //parse with whitespace | ||
796 | virtual bool parse_non_term(_context &) const { | ||
797 | return false; | ||
798 | } | ||
799 | |||
800 | //parse terminal | ||
801 | virtual bool parse_term(_context &) const { | ||
802 | return false; | ||
803 | } | ||
804 | }; | ||
805 | |||
806 | //exception thrown when left recursion terminates successfully | ||
807 | struct _lr_ok { | ||
808 | rule *m_rule; | ||
809 | _lr_ok(rule *r) : m_rule(r) {} | ||
810 | }; | ||
811 | |||
812 | |||
813 | //constructor | ||
814 | _state::_state(_context &con) : | ||
815 | m_pos(con.m_pos), | ||
816 | m_matches(con.m_matches.size()) | ||
817 | { | ||
818 | } | ||
819 | |||
820 | |||
821 | //parse non-term rule. | ||
822 | bool _context::parse_non_term(rule &r) { | ||
823 | //save the state of the rule | ||
824 | rule::_state old_state = r.m_state; | ||
825 | |||
826 | //success/failure result | ||
827 | bool ok; | ||
828 | |||
829 | //compute the new position | ||
830 | size_t new_pos = m_pos.m_it - m_begin; | ||
831 | |||
832 | //check if we have left recursion | ||
833 | bool lr = new_pos == r.m_state.m_pos; | ||
834 | |||
835 | //update the rule's state | ||
836 | r.m_state.m_pos = new_pos; | ||
837 | |||
838 | //handle the mode of the rule | ||
839 | switch (r.m_state.m_mode) { | ||
840 | //normal parse | ||
841 | case rule::_PARSE: | ||
842 | if (lr) { | ||
843 | //first try to parse the rule by rejecting it, so alternative branches are examined | ||
844 | r.m_state.m_mode = rule::_REJECT; | ||
845 | ok = _parse_non_term(r); | ||
846 | |||
847 | //if the first try is successful, try accepting the rule, | ||
848 | //so other elements of the sequence are parsed | ||
849 | if (ok) { | ||
850 | r.m_state.m_mode = rule::_ACCEPT; | ||
851 | |||
852 | //loop until no more parsing can be done | ||
853 | for(;;) { | ||
854 | //store the correct state, in order to backtrack if the call fails | ||
855 | _state st(*this); | ||
856 | |||
857 | //update the rule position to the current position, | ||
858 | //because at this state the rule is resolving the left recursion | ||
859 | r.m_state.m_pos = m_pos.m_it - m_begin; | ||
860 | |||
861 | //if parsing fails, restore the last good state and stop | ||
862 | if (!_parse_non_term(r)) { | ||
863 | restore(st); | ||
864 | break; | ||
865 | } | ||
866 | } | ||
867 | |||
868 | //since the left recursion was resolved successfully, | ||
869 | //return via a non-local exit | ||
870 | r.m_state = old_state; | ||
871 | throw _lr_ok(r.this_ptr()); | ||
872 | } | ||
873 | } | ||
874 | else { | ||
875 | try { | ||
876 | ok = _parse_non_term(r); | ||
877 | } | ||
878 | catch (const _lr_ok &ex) { | ||
879 | //since left recursions may be mutual, we must test which rule's left recursion | ||
880 | //was ended successfully | ||
881 | if (ex.m_rule == r.this_ptr()) { | ||
882 | ok = true; | ||
883 | } | ||
884 | else { | ||
885 | r.m_state = old_state; | ||
886 | throw; | ||
887 | } | ||
888 | } | ||
889 | } | ||
890 | break; | ||
891 | |||
892 | //reject the left recursive rule | ||
893 | case rule::_REJECT: | ||
894 | if (lr) { | ||
895 | ok = false; | ||
896 | } | ||
897 | else { | ||
898 | r.m_state.m_mode = rule::_PARSE; | ||
899 | ok = _parse_non_term(r); | ||
900 | r.m_state.m_mode = rule::_REJECT; | ||
901 | } | ||
902 | break; | ||
903 | |||
904 | //accept the left recursive rule | ||
905 | case rule::_ACCEPT: | ||
906 | if (lr) { | ||
907 | ok = true; | ||
908 | } | ||
909 | else { | ||
910 | r.m_state.m_mode = rule::_PARSE; | ||
911 | ok = _parse_non_term(r); | ||
912 | r.m_state.m_mode = rule::_ACCEPT; | ||
913 | } | ||
914 | break; | ||
915 | } | ||
916 | |||
917 | //restore the rule's state | ||
918 | r.m_state = old_state; | ||
919 | |||
920 | return ok; | ||
921 | } | ||
922 | |||
923 | |||
924 | //parse term rule. | ||
925 | bool _context::parse_term(rule &r) { | ||
926 | //save the state of the rule | ||
927 | rule::_state old_state = r.m_state; | ||
928 | |||
929 | //success/failure result | ||
930 | bool ok; | ||
931 | |||
932 | //compute the new position | ||
933 | size_t new_pos = m_pos.m_it - m_begin; | ||
934 | |||
935 | //check if we have left recursion | ||
936 | bool lr = new_pos == r.m_state.m_pos; | ||
937 | |||
938 | //update the rule's state | ||
939 | r.m_state.m_pos = new_pos; | ||
940 | |||
941 | //handle the mode of the rule | ||
942 | switch (r.m_state.m_mode) { | ||
943 | //normal parse | ||
944 | case rule::_PARSE: | ||
945 | if (lr) { | ||
946 | //first try to parse the rule by rejecting it, so alternative branches are examined | ||
947 | r.m_state.m_mode = rule::_REJECT; | ||
948 | ok = _parse_term(r); | ||
949 | |||
950 | //if the first try is successful, try accepting the rule, | ||
951 | //so other elements of the sequence are parsed | ||
952 | if (ok) { | ||
953 | r.m_state.m_mode = rule::_ACCEPT; | ||
954 | |||
955 | //loop until no more parsing can be done | ||
956 | for(;;) { | ||
957 | //store the correct state, in order to backtrack if the call fails | ||
958 | _state st(*this); | ||
959 | |||
960 | //update the rule position to the current position, | ||
961 | //because at this state the rule is resolving the left recursion | ||
962 | r.m_state.m_pos = m_pos.m_it - m_begin; | ||
963 | |||
964 | //if parsing fails, restore the last good state and stop | ||
965 | if (!_parse_term(r)) { | ||
966 | restore(st); | ||
967 | break; | ||
968 | } | ||
969 | } | ||
970 | |||
971 | //since the left recursion was resolved successfully, | ||
972 | //return via a non-local exit | ||
973 | r.m_state = old_state; | ||
974 | throw _lr_ok(r.this_ptr()); | ||
975 | } | ||
976 | } | ||
977 | else { | ||
978 | try { | ||
979 | ok = _parse_term(r); | ||
980 | } | ||
981 | catch (const _lr_ok &ex) { | ||
982 | //since left recursions may be mutual, we must test which rule's left recursion | ||
983 | //was ended successfully | ||
984 | if (ex.m_rule == r.this_ptr()) { | ||
985 | ok = true; | ||
986 | } | ||
987 | else { | ||
988 | r.m_state = old_state; | ||
989 | throw; | ||
990 | } | ||
991 | } | ||
992 | } | ||
993 | break; | ||
994 | |||
995 | //reject the left recursive rule | ||
996 | case rule::_REJECT: | ||
997 | if (lr) { | ||
998 | ok = false; | ||
999 | } | ||
1000 | else { | ||
1001 | r.m_state.m_mode = rule::_PARSE; | ||
1002 | ok = _parse_term(r); | ||
1003 | r.m_state.m_mode = rule::_REJECT; | ||
1004 | } | ||
1005 | break; | ||
1006 | |||
1007 | //accept the left recursive rule | ||
1008 | case rule::_ACCEPT: | ||
1009 | if (lr) { | ||
1010 | ok = true; | ||
1011 | } | ||
1012 | else { | ||
1013 | r.m_state.m_mode = rule::_PARSE; | ||
1014 | ok = _parse_term(r); | ||
1015 | r.m_state.m_mode = rule::_ACCEPT; | ||
1016 | } | ||
1017 | break; | ||
1018 | } | ||
1019 | |||
1020 | //restore the rule's state | ||
1021 | r.m_state = old_state; | ||
1022 | |||
1023 | return ok; | ||
1024 | } | ||
1025 | |||
1026 | |||
1027 | //parse non-term rule internal. | ||
1028 | bool _context::_parse_non_term(rule &r) { | ||
1029 | bool ok; | ||
1030 | if (_private::get_parse_proc(r)) { | ||
1031 | pos b = m_pos; | ||
1032 | ok = _private::get_expr(r)->parse_non_term(*this); | ||
1033 | if (ok) { | ||
1034 | m_matches.push_back(_match(r.this_ptr(), b, m_pos)); | ||
1035 | } | ||
1036 | } | ||
1037 | else { | ||
1038 | ok = _private::get_expr(r)->parse_non_term(*this); | ||
1039 | } | ||
1040 | return ok; | ||
1041 | } | ||
1042 | |||
1043 | |||
1044 | //parse term rule internal. | ||
1045 | bool _context::_parse_term(rule &r) { | ||
1046 | bool ok; | ||
1047 | if (_private::get_parse_proc(r)) { | ||
1048 | pos b = m_pos; | ||
1049 | ok = _private::get_expr(r)->parse_term(*this); | ||
1050 | if (ok) { | ||
1051 | m_matches.push_back(_match(r.this_ptr(), b, m_pos)); | ||
1052 | } | ||
1053 | } | ||
1054 | else { | ||
1055 | ok = _private::get_expr(r)->parse_term(*this); | ||
1056 | } | ||
1057 | return ok; | ||
1058 | } | ||
1059 | |||
1060 | |||
1061 | //get syntax error | ||
1062 | static error _syntax_error(_context &con) { | ||
1063 | return error(con.m_error_pos, con.m_error_pos, ERROR_SYNTAX_ERROR); | ||
1064 | } | ||
1065 | |||
1066 | |||
1067 | //get eof error | ||
1068 | static error _eof_error(_context &con) { | ||
1069 | return error(con.m_error_pos, con.m_error_pos, ERROR_INVALID_EOF); | ||
1070 | } | ||
1071 | |||
1072 | |||
1073 | /** constructor from input. | ||
1074 | @param i input. | ||
1075 | */ | ||
1076 | pos::pos(input &i) : | ||
1077 | m_it(i.begin()), | ||
1078 | m_line(1), | ||
1079 | m_col(1) | ||
1080 | { | ||
1081 | } | ||
1082 | |||
1083 | |||
1084 | /** character terminal constructor. | ||
1085 | @param c character. | ||
1086 | */ | ||
1087 | expr::expr(char c) : | ||
1088 | m_expr(new _char(c)) | ||
1089 | { | ||
1090 | } | ||
1091 | |||
1092 | |||
1093 | /** null-terminated string terminal constructor. | ||
1094 | @param s null-terminated string. | ||
1095 | */ | ||
1096 | expr::expr(const char *s) : | ||
1097 | m_expr(new _string(s)) | ||
1098 | { | ||
1099 | } | ||
1100 | |||
1101 | |||
1102 | /** rule reference constructor. | ||
1103 | @param r rule. | ||
1104 | */ | ||
1105 | expr::expr(rule &r) : | ||
1106 | m_expr(new _ref(r)) | ||
1107 | { | ||
1108 | } | ||
1109 | |||
1110 | |||
1111 | /** creates a zero-or-more loop out of this expression. | ||
1112 | @return a zero-or-more loop expression. | ||
1113 | */ | ||
1114 | expr expr::operator *() const { | ||
1115 | return _private::construct_expr(new _loop0(m_expr)); | ||
1116 | } | ||
1117 | |||
1118 | |||
1119 | /** creates a one-or-more loop out of this expression. | ||
1120 | @return a one-or-more loop expression. | ||
1121 | */ | ||
1122 | expr expr::operator +() const { | ||
1123 | return _private::construct_expr(new _loop1(m_expr)); | ||
1124 | } | ||
1125 | |||
1126 | |||
1127 | /** creates an optional out of this expression. | ||
1128 | @return an optional expression. | ||
1129 | */ | ||
1130 | expr expr::operator -() const { | ||
1131 | return _private::construct_expr(new _optional(m_expr)); | ||
1132 | } | ||
1133 | |||
1134 | |||
1135 | /** creates an AND-expression. | ||
1136 | @return an AND-expression. | ||
1137 | */ | ||
1138 | expr expr::operator &() const { | ||
1139 | return _private::construct_expr((new _and(m_expr))); | ||
1140 | } | ||
1141 | |||
1142 | |||
1143 | /** creates a NOT-expression. | ||
1144 | @return a NOT-expression. | ||
1145 | */ | ||
1146 | expr expr::operator !() const { | ||
1147 | return _private::construct_expr(new _not(m_expr)); | ||
1148 | } | ||
1149 | |||
1150 | |||
1151 | /** constructor. | ||
1152 | @param b begin position. | ||
1153 | @param e end position. | ||
1154 | */ | ||
1155 | input_range::input_range(const pos &b, const pos &e) : | ||
1156 | m_begin(b), | ||
1157 | m_end(e) {} | ||
1158 | |||
1159 | |||
1160 | /** constructor. | ||
1161 | @param b begin position. | ||
1162 | @param e end position. | ||
1163 | @param t error type. | ||
1164 | */ | ||
1165 | error::error(const pos &b, const pos &e, int t) : | ||
1166 | input_range(b, e), | ||
1167 | m_type(t) {} | ||
1168 | |||
1169 | |||
1170 | /** compare on begin position. | ||
1171 | @param e the other error to compare this with. | ||
1172 | @return true if this comes before the previous error, false otherwise. | ||
1173 | */ | ||
1174 | bool error::operator < (const error &e) const { | ||
1175 | return m_begin.m_it < e.m_begin.m_it; | ||
1176 | } | ||
1177 | |||
1178 | |||
1179 | /** character terminal constructor. | ||
1180 | @param c character. | ||
1181 | */ | ||
1182 | rule::rule(char c) : | ||
1183 | m_expr(new _char(c)) | ||
1184 | { | ||
1185 | m_parse_proc = _get_parse_proc(this); | ||
1186 | } | ||
1187 | |||
1188 | |||
1189 | /** null-terminated string terminal constructor. | ||
1190 | @param s null-terminated string. | ||
1191 | */ | ||
1192 | rule::rule(const char *s) : | ||
1193 | m_expr(new _string(s)) | ||
1194 | { | ||
1195 | m_parse_proc = _get_parse_proc(this); | ||
1196 | } | ||
1197 | |||
1198 | |||
1199 | /** constructor from expression. | ||
1200 | @param e expression. | ||
1201 | */ | ||
1202 | rule::rule(const expr &e) : | ||
1203 | m_expr(_private::get_expr(e)) | ||
1204 | { | ||
1205 | m_parse_proc = _get_parse_proc(this); | ||
1206 | } | ||
1207 | |||
1208 | |||
1209 | /** constructor from rule. | ||
1210 | @param r rule. | ||
1211 | */ | ||
1212 | rule::rule(rule &r) : | ||
1213 | m_expr(new _ref(r)), | ||
1214 | m_parse_proc(0) | ||
1215 | { | ||
1216 | m_parse_proc = _get_parse_proc(this); | ||
1217 | } | ||
1218 | |||
1219 | |||
1220 | /** invalid constructor from rule (required by gcc). | ||
1221 | @exception std::logic_error always thrown. | ||
1222 | */ | ||
1223 | rule::rule(const rule &) { | ||
1224 | throw std::logic_error("invalid operation"); | ||
1225 | } | ||
1226 | |||
1227 | |||
1228 | /** deletes the internal object that represents the expression. | ||
1229 | */ | ||
1230 | rule::~rule() { | ||
1231 | delete m_expr; | ||
1232 | } | ||
1233 | |||
1234 | |||
1235 | /** creates a zero-or-more loop out of this rule. | ||
1236 | @return a zero-or-more loop rule. | ||
1237 | */ | ||
1238 | expr rule::operator *() { | ||
1239 | return _private::construct_expr(new _loop0(new _ref(*this))); | ||
1240 | } | ||
1241 | |||
1242 | |||
1243 | /** creates a one-or-more loop out of this rule. | ||
1244 | @return a one-or-more loop rule. | ||
1245 | */ | ||
1246 | expr rule::operator +() { | ||
1247 | return _private::construct_expr(new _loop1(new _ref(*this))); | ||
1248 | } | ||
1249 | |||
1250 | |||
1251 | /** creates an optional out of this rule. | ||
1252 | @return an optional rule. | ||
1253 | */ | ||
1254 | expr rule::operator -() { | ||
1255 | return _private::construct_expr(new _optional(new _ref(*this))); | ||
1256 | } | ||
1257 | |||
1258 | |||
1259 | /** creates an AND-expression out of this rule. | ||
1260 | @return an AND-expression out of this rule. | ||
1261 | */ | ||
1262 | expr rule::operator &() { | ||
1263 | return _private::construct_expr(new _and(new _ref(*this))); | ||
1264 | } | ||
1265 | |||
1266 | |||
1267 | /** creates a NOT-expression out of this rule. | ||
1268 | @return a NOT-expression out of this rule. | ||
1269 | */ | ||
1270 | expr rule::operator !() { | ||
1271 | return _private::construct_expr(new _not(new _ref(*this))); | ||
1272 | } | ||
1273 | |||
1274 | |||
1275 | /** sets the parse procedure. | ||
1276 | @param p procedure. | ||
1277 | */ | ||
1278 | void rule::set_parse_proc(parse_proc p) { | ||
1279 | assert(p); | ||
1280 | m_parse_proc = p; | ||
1281 | _parse_proc_map_t& _parse_proc_map = _get_parse_proc_map(); | ||
1282 | _parse_proc_map[this] = p; | ||
1283 | } | ||
1284 | |||
1285 | |||
1286 | /** creates a sequence of expressions. | ||
1287 | @param left left operand. | ||
1288 | @param right right operand. | ||
1289 | @return an expression which parses a sequence. | ||
1290 | */ | ||
1291 | expr operator >> (const expr &left, const expr &right) { | ||
1292 | return _private::construct_expr( | ||
1293 | new _seq(_private::get_expr(left), _private::get_expr(right))); | ||
1294 | } | ||
1295 | |||
1296 | |||
1297 | /** creates a choice of expressions. | ||
1298 | @param left left operand. | ||
1299 | @param right right operand. | ||
1300 | @return an expression which parses a choice. | ||
1301 | */ | ||
1302 | expr operator | (const expr &left, const expr &right) { | ||
1303 | return _private::construct_expr( | ||
1304 | new _choice(_private::get_expr(left), _private::get_expr(right))); | ||
1305 | } | ||
1306 | |||
1307 | |||
1308 | /** converts a parser expression into a terminal. | ||
1309 | @param e expression. | ||
1310 | @return an expression which parses a terminal. | ||
1311 | */ | ||
1312 | expr term(const expr &e) { | ||
1313 | return _private::construct_expr( | ||
1314 | new _term(_private::get_expr(e))); | ||
1315 | } | ||
1316 | |||
1317 | |||
1318 | /** creates a set expression from a null-terminated string. | ||
1319 | @param s null-terminated string with characters of the set. | ||
1320 | @return an expression which parses a single character out of a set. | ||
1321 | */ | ||
1322 | expr set(const char *s) { | ||
1323 | return _private::construct_expr(new _set(s)); | ||
1324 | } | ||
1325 | |||
1326 | |||
1327 | /** creates a range expression. | ||
1328 | @param min min character. | ||
1329 | @param max max character. | ||
1330 | @return an expression which parses a single character out of range. | ||
1331 | */ | ||
1332 | expr range(int min, int max) { | ||
1333 | return _private::construct_expr(new _set(min, max)); | ||
1334 | } | ||
1335 | |||
1336 | |||
1337 | /** creates an expression which increments the line counter | ||
1338 | and resets the column counter when the given expression | ||
1339 | is parsed successfully; used for newline characters. | ||
1340 | @param e expression to wrap into a newline parser. | ||
1341 | @return an expression that handles newlines. | ||
1342 | */ | ||
1343 | expr nl(const expr &e) { | ||
1344 | return _private::construct_expr(new _nl(_private::get_expr(e))); | ||
1345 | } | ||
1346 | |||
1347 | |||
1348 | /** creates an expression which tests for the end of input. | ||
1349 | @return an expression that handles the end of input. | ||
1350 | */ | ||
1351 | expr eof() { | ||
1352 | return _private::construct_expr(new _eof()); | ||
1353 | } | ||
1354 | |||
1355 | |||
1356 | /** creates a not expression. | ||
1357 | @param e expression. | ||
1358 | @return the appropriate expression. | ||
1359 | */ | ||
1360 | expr not_(const expr &e) { | ||
1361 | return !e; | ||
1362 | } | ||
1363 | |||
1364 | |||
1365 | /** creates an and expression. | ||
1366 | @param e expression. | ||
1367 | @return the appropriate expression. | ||
1368 | */ | ||
1369 | expr and_(const expr &e) { | ||
1370 | return &e; | ||
1371 | } | ||
1372 | |||
1373 | |||
1374 | /** creates an expression that parses any character. | ||
1375 | @return the appropriate expression. | ||
1376 | */ | ||
1377 | expr any() { | ||
1378 | return _private::construct_expr(new _any()); | ||
1379 | } | ||
1380 | |||
1381 | |||
1382 | /** parsing succeeds without consuming any input. | ||
1383 | */ | ||
1384 | expr true_() { | ||
1385 | return _private::construct_expr(new _true()); | ||
1386 | } | ||
1387 | |||
1388 | |||
1389 | /** parsing fails without consuming any input. | ||
1390 | */ | ||
1391 | expr false_() { | ||
1392 | return _private::construct_expr(new _false()); | ||
1393 | } | ||
1394 | |||
1395 | |||
1396 | /** parse with target expression and let user handle result. | ||
1397 | */ | ||
1398 | expr user(const expr &e, const user_handler& handler) { | ||
1399 | return _private::construct_expr(new _user(_private::get_expr(e), handler)); | ||
1400 | } | ||
1401 | |||
1402 | |||
1403 | /** parses the given input. | ||
1404 | The parse procedures of each rule parsed are executed | ||
1405 | before this function returns, if parsing succeeds. | ||
1406 | @param i input. | ||
1407 | @param g root rule of grammar. | ||
1408 | @param el list of errors. | ||
1409 | @param d user data, passed to the parse procedures. | ||
1410 | @return true on parsing success, false on failure. | ||
1411 | */ | ||
1412 | bool parse(input &i, rule &g, error_list &el, void *d, void* ud) { | ||
1413 | //prepare context | ||
1414 | _context con(i, ud); | ||
1415 | |||
1416 | //parse grammar | ||
1417 | if (!con.parse_non_term(g)) { | ||
1418 | el.push_back(_syntax_error(con)); | ||
1419 | return false; | ||
1420 | } | ||
1421 | |||
1422 | //if end is not reached, there was an error | ||
1423 | if (!con.end()) { | ||
1424 | if (con.m_error_pos.m_it < con.m_end) { | ||
1425 | el.push_back(_syntax_error(con)); | ||
1426 | } | ||
1427 | else { | ||
1428 | el.push_back(_eof_error(con)); | ||
1429 | } | ||
1430 | return false; | ||
1431 | } | ||
1432 | |||
1433 | //success; execute the parse procedures | ||
1434 | con.do_parse_procs(d); | ||
1435 | return true; | ||
1436 | } | ||
1437 | |||
1438 | |||
1439 | } //namespace parserlib | ||
diff --git a/src/MoonP/parser.hpp b/src/MoonP/parser.hpp new file mode 100644 index 0000000..9739465 --- /dev/null +++ b/src/MoonP/parser.hpp | |||
@@ -0,0 +1,435 @@ | |||
1 | /* Copyright (c) 2012, Achilleas Margaritis, modified by Jin Li | ||
2 | All rights reserved. | ||
3 | |||
4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | ||
5 | |||
6 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | ||
7 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | ||
8 | |||
9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | ||
10 | |||
11 | #pragma once | ||
12 | |||
13 | |||
14 | //gcc chokes without rule::rule(const rule &), | ||
15 | //msvc complains when rule::rule(const rule &) is defined. | ||
16 | #ifdef _MSC_VER | ||
17 | #pragma warning (disable: 4521) | ||
18 | #endif | ||
19 | |||
20 | |||
21 | #include <vector> | ||
22 | #include <string> | ||
23 | #include <list> | ||
24 | #include <functional> | ||
25 | #include <codecvt> | ||
26 | #include <locale> | ||
27 | |||
28 | namespace parserlib { | ||
29 | |||
30 | // const str hash helper functions | ||
31 | inline constexpr size_t hash(char const* input) | ||
32 | { | ||
33 | return *input ? *input + 33ull * hash(input + 1) : 5381; | ||
34 | } | ||
35 | inline size_t hash(const char* input, int size, int index) | ||
36 | { | ||
37 | return index < size ? input[index] + 33ull * hash(input, size, index + 1) : 5381; | ||
38 | } | ||
39 | inline size_t constexpr operator"" _id(const char* s, size_t) | ||
40 | { | ||
41 | return hash(s); | ||
42 | } | ||
43 | |||
44 | ///type of the parser's input. | ||
45 | typedef std::basic_string<wchar_t> input; | ||
46 | typedef input::iterator input_it; | ||
47 | typedef std::wstring_convert<std::codecvt_utf8<input::value_type>> Converter; | ||
48 | |||
49 | class _private; | ||
50 | class _expr; | ||
51 | class _context; | ||
52 | class rule; | ||
53 | |||
54 | |||
55 | struct item_t | ||
56 | { | ||
57 | input_it begin; | ||
58 | input_it end; | ||
59 | void* user_data; | ||
60 | }; | ||
61 | typedef std::function<bool(const item_t&)> user_handler; | ||
62 | |||
63 | |||
64 | ///position into the input. | ||
65 | class pos { | ||
66 | public: | ||
67 | ///interator into the input. | ||
68 | input::iterator m_it; | ||
69 | |||
70 | ///line. | ||
71 | int m_line; | ||
72 | |||
73 | ///column. | ||
74 | int m_col; | ||
75 | |||
76 | ///null constructor. | ||
77 | pos():m_line(-1),m_col(0) {} | ||
78 | |||
79 | /** constructor from input. | ||
80 | @param i input. | ||
81 | */ | ||
82 | pos(input &i); | ||
83 | }; | ||
84 | |||
85 | |||
86 | /** a grammar expression. | ||
87 | */ | ||
88 | class expr { | ||
89 | public: | ||
90 | /** character terminal constructor. | ||
91 | @param c character. | ||
92 | */ | ||
93 | expr(char c); | ||
94 | |||
95 | /** null-terminated string terminal constructor. | ||
96 | @param s null-terminated string. | ||
97 | */ | ||
98 | expr(const char *s); | ||
99 | |||
100 | /** rule reference constructor. | ||
101 | @param r rule. | ||
102 | */ | ||
103 | expr(rule &r); | ||
104 | |||
105 | /** creates a zero-or-more loop out of this expression. | ||
106 | @return a zero-or-more loop expression. | ||
107 | */ | ||
108 | expr operator *() const; | ||
109 | |||
110 | /** creates a one-or-more loop out of this expression. | ||
111 | @return a one-or-more loop expression. | ||
112 | */ | ||
113 | expr operator +() const; | ||
114 | |||
115 | /** creates an optional out of this expression. | ||
116 | @return an optional expression. | ||
117 | */ | ||
118 | expr operator -() const; | ||
119 | |||
120 | /** creates an AND-expression. | ||
121 | @return an AND-expression. | ||
122 | */ | ||
123 | expr operator &() const; | ||
124 | |||
125 | /** creates a NOT-expression. | ||
126 | @return a NOT-expression. | ||
127 | */ | ||
128 | expr operator !() const; | ||
129 | |||
130 | private: | ||
131 | //internal expression | ||
132 | _expr *m_expr; | ||
133 | |||
134 | //internal constructor from internal expression | ||
135 | expr(_expr *e) : m_expr(e) {} | ||
136 | |||
137 | //assignment not allowed | ||
138 | expr &operator = (expr &); | ||
139 | |||
140 | friend class _private; | ||
141 | }; | ||
142 | |||
143 | |||
144 | /** type of procedure to invoke when a rule is successfully parsed. | ||
145 | @param b begin position of input. | ||
146 | @param e end position of input. | ||
147 | @param d pointer to user data. | ||
148 | */ | ||
149 | typedef void (*parse_proc)(const pos &b, const pos &e, void *d); | ||
150 | |||
151 | |||
152 | ///input range. | ||
153 | class input_range { | ||
154 | public: | ||
155 | virtual ~input_range() {} | ||
156 | |||
157 | ///begin position. | ||
158 | pos m_begin; | ||
159 | |||
160 | ///end position. | ||
161 | pos m_end; | ||
162 | |||
163 | ///empty constructor. | ||
164 | input_range() {} | ||
165 | |||
166 | /** constructor. | ||
167 | @param b begin position. | ||
168 | @param e end position. | ||
169 | */ | ||
170 | input_range(const pos &b, const pos &e); | ||
171 | }; | ||
172 | |||
173 | |||
174 | ///enum with error types. | ||
175 | enum ERROR_TYPE { | ||
176 | ///syntax error | ||
177 | ERROR_SYNTAX_ERROR = 1, | ||
178 | |||
179 | ///invalid end of file | ||
180 | ERROR_INVALID_EOF, | ||
181 | |||
182 | ///first user error | ||
183 | ERROR_USER = 100 | ||
184 | }; | ||
185 | |||
186 | |||
187 | ///error. | ||
188 | class error : public input_range { | ||
189 | public: | ||
190 | ///type | ||
191 | int m_type; | ||
192 | |||
193 | /** constructor. | ||
194 | @param b begin position. | ||
195 | @param e end position. | ||
196 | @param t type. | ||
197 | */ | ||
198 | error(const pos &b, const pos &e, int t); | ||
199 | |||
200 | /** compare on begin position. | ||
201 | @param e the other error to compare this with. | ||
202 | @return true if this comes before the previous error, false otherwise. | ||
203 | */ | ||
204 | bool operator < (const error &e) const; | ||
205 | }; | ||
206 | |||
207 | |||
208 | ///type of error list. | ||
209 | typedef std::list<error> error_list; | ||
210 | |||
211 | |||
212 | /** represents a rule. | ||
213 | */ | ||
214 | class rule { | ||
215 | public: | ||
216 | /** character terminal constructor. | ||
217 | @param c character. | ||
218 | */ | ||
219 | rule(char c); | ||
220 | |||
221 | /** null-terminated string terminal constructor. | ||
222 | @param s null-terminated string. | ||
223 | */ | ||
224 | rule(const char *s); | ||
225 | |||
226 | /** constructor from expression. | ||
227 | @param e expression. | ||
228 | */ | ||
229 | rule(const expr &e); | ||
230 | |||
231 | /** constructor from rule. | ||
232 | @param r rule. | ||
233 | */ | ||
234 | rule(rule &r); | ||
235 | |||
236 | /** invalid constructor from rule (required by gcc). | ||
237 | @param r rule. | ||
238 | @exception std::logic_error always thrown. | ||
239 | */ | ||
240 | rule(const rule &r); | ||
241 | |||
242 | /** deletes the internal object that represents the expression. | ||
243 | */ | ||
244 | ~rule(); | ||
245 | |||
246 | /** creates a zero-or-more loop out of this rule. | ||
247 | @return a zero-or-more loop rule. | ||
248 | */ | ||
249 | expr operator *(); | ||
250 | |||
251 | /** creates a one-or-more loop out of this rule. | ||
252 | @return a one-or-more loop rule. | ||
253 | */ | ||
254 | expr operator +(); | ||
255 | |||
256 | /** creates an optional out of this rule. | ||
257 | @return an optional rule. | ||
258 | */ | ||
259 | expr operator -(); | ||
260 | |||
261 | /** creates an AND-expression out of this rule. | ||
262 | @return an AND-expression out of this rule. | ||
263 | */ | ||
264 | expr operator &(); | ||
265 | |||
266 | /** creates a NOT-expression out of this rule. | ||
267 | @return a NOT-expression out of this rule. | ||
268 | */ | ||
269 | expr operator !(); | ||
270 | |||
271 | /** sets the parse procedure. | ||
272 | @param p procedure. | ||
273 | */ | ||
274 | void set_parse_proc(parse_proc p); | ||
275 | |||
276 | /** get the this ptr (since operator & is overloaded). | ||
277 | @return pointer to this. | ||
278 | */ | ||
279 | rule *this_ptr() { return this; } | ||
280 | |||
281 | private: | ||
282 | //mode | ||
283 | enum _MODE { | ||
284 | _PARSE, | ||
285 | _REJECT, | ||
286 | _ACCEPT | ||
287 | }; | ||
288 | |||
289 | //state | ||
290 | struct _state { | ||
291 | //position in source code, relative to start | ||
292 | size_t m_pos; | ||
293 | |||
294 | //mode | ||
295 | _MODE m_mode; | ||
296 | |||
297 | //constructor | ||
298 | _state(size_t pos = -1, _MODE mode = _PARSE) : | ||
299 | m_pos(pos), m_mode(mode) {} | ||
300 | }; | ||
301 | |||
302 | //internal expression | ||
303 | _expr *m_expr; | ||
304 | |||
305 | //associated parse procedure. | ||
306 | parse_proc m_parse_proc; | ||
307 | |||
308 | //state | ||
309 | _state m_state; | ||
310 | |||
311 | //assignment not allowed | ||
312 | rule &operator = (rule &); | ||
313 | |||
314 | friend class _private; | ||
315 | friend class _context; | ||
316 | }; | ||
317 | |||
318 | |||
319 | /** creates a sequence of expressions. | ||
320 | @param left left operand. | ||
321 | @param right right operand. | ||
322 | @return an expression which parses a sequence. | ||
323 | */ | ||
324 | expr operator >> (const expr &left, const expr &right); | ||
325 | |||
326 | |||
327 | /** creates a choice of expressions. | ||
328 | @param left left operand. | ||
329 | @param right right operand. | ||
330 | @return an expression which parses a choice. | ||
331 | */ | ||
332 | expr operator | (const expr &left, const expr &right); | ||
333 | |||
334 | |||
335 | /** converts a parser expression into a terminal. | ||
336 | @param e expression. | ||
337 | @return an expression which parses a terminal. | ||
338 | */ | ||
339 | expr term(const expr &e); | ||
340 | |||
341 | |||
342 | /** creates a set expression from a null-terminated string. | ||
343 | @param s null-terminated string with characters of the set. | ||
344 | @return an expression which parses a single character out of a set. | ||
345 | */ | ||
346 | expr set(const char *s); | ||
347 | |||
348 | |||
349 | /** creates a range expression. | ||
350 | @param min min character. | ||
351 | @param max max character. | ||
352 | @return an expression which parses a single character out of range. | ||
353 | */ | ||
354 | expr range(int min, int max); | ||
355 | |||
356 | |||
357 | /** creates an expression which increments the line counter | ||
358 | and resets the column counter when the given expression | ||
359 | is parsed successfully; used for newline characters. | ||
360 | @param e expression to wrap into a newline parser. | ||
361 | @return an expression that handles newlines. | ||
362 | */ | ||
363 | expr nl(const expr &e); | ||
364 | |||
365 | |||
366 | /** creates an expression which tests for the end of input. | ||
367 | @return an expression that handles the end of input. | ||
368 | */ | ||
369 | expr eof(); | ||
370 | |||
371 | |||
372 | /** creates a not expression. | ||
373 | @param e expression. | ||
374 | @return the appropriate expression. | ||
375 | */ | ||
376 | expr not_(const expr &e); | ||
377 | |||
378 | |||
379 | /** creates an and expression. | ||
380 | @param e expression. | ||
381 | @return the appropriate expression. | ||
382 | */ | ||
383 | expr and_(const expr &e); | ||
384 | |||
385 | |||
386 | /** creates an expression that parses any character. | ||
387 | @return the appropriate expression. | ||
388 | */ | ||
389 | expr any(); | ||
390 | |||
391 | |||
392 | /** parsing succeeds without consuming any input. | ||
393 | */ | ||
394 | expr true_(); | ||
395 | |||
396 | |||
397 | /** parsing fails without consuming any input. | ||
398 | */ | ||
399 | expr false_(); | ||
400 | |||
401 | |||
402 | /** parse with target expression and let user handle result. | ||
403 | */ | ||
404 | expr user(const expr &e, const user_handler& handler); | ||
405 | |||
406 | |||
407 | /** parses the given input. | ||
408 | The parse procedures of each rule parsed are executed | ||
409 | before this function returns, if parsing succeeds. | ||
410 | @param i input. | ||
411 | @param g root rule of grammar. | ||
412 | @param el list of errors. | ||
413 | @param d user data, passed to the parse procedures. | ||
414 | @return true on parsing success, false on failure. | ||
415 | */ | ||
416 | bool parse(input &i, rule &g, error_list &el, void *d, void* ud); | ||
417 | |||
418 | |||
419 | /** output the specific input range to the specific stream. | ||
420 | @param stream stream. | ||
421 | @param ir input range. | ||
422 | @return the stream. | ||
423 | */ | ||
424 | template <class T> T &operator << (T &stream, const input_range &ir) { | ||
425 | for(input::const_iterator it = ir.m_begin.m_it; | ||
426 | it != ir.m_end.m_it; | ||
427 | ++it) | ||
428 | { | ||
429 | stream << (typename T::char_type)*it; | ||
430 | } | ||
431 | return stream; | ||
432 | } | ||
433 | |||
434 | |||
435 | } //namespace parserlib | ||
diff --git a/src/moonc.cpp b/src/moonc.cpp new file mode 100644 index 0000000..d9d3ce3 --- /dev/null +++ b/src/moonc.cpp | |||
@@ -0,0 +1,178 @@ | |||
1 | /* Copyright (c) 2020 Jin Li, http://www.luvfight.me | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
4 | |||
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
6 | |||
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ | ||
8 | #include <iostream> | ||
9 | #include <iomanip> | ||
10 | #include <fstream> | ||
11 | #include <chrono> | ||
12 | #include "MoonP/moon_compiler.h" | ||
13 | #include "MoonP/parser.hpp" | ||
14 | #include "MoonP/moon_ast.h" | ||
15 | |||
16 | int main(int narg, const char** args) { | ||
17 | const char* help = | ||
18 | "Usage: moonc [options|files] ...\n\n" | ||
19 | " -h Print this message\n" | ||
20 | " -t path Specify where to place compiled files\n" | ||
21 | " -o file Write output to file\n" | ||
22 | " -p Write output to standard out\n" | ||
23 | " -b Dump compile time (doesn't write output)\n" | ||
24 | " -l Write line numbers from source codes\n" | ||
25 | " -a Allow expression list not in the end of body block\n" | ||
26 | " -s Use space over tab\n" | ||
27 | " -v Print version\n"; | ||
28 | if (narg == 0) { | ||
29 | std::cout << help; | ||
30 | return 0; | ||
31 | } | ||
32 | MoonP::MoonConfig config; | ||
33 | bool writeToFile = true; | ||
34 | bool dumpCompileTime = false; | ||
35 | std::string targetPath; | ||
36 | std::string resultFile; | ||
37 | std::list<std::string> files; | ||
38 | for (int i = 1; i < narg; ++i) { | ||
39 | switch (hash(args[i])) { | ||
40 | case "-a"_id: | ||
41 | config.allowExprNotInTheEndOfBody = true; | ||
42 | break; | ||
43 | case "-s"_id: | ||
44 | config.spaceOverTab = true; | ||
45 | break; | ||
46 | case "-l"_id: | ||
47 | config.reserveLineNumber = true; | ||
48 | break; | ||
49 | case "-r"_id: | ||
50 | config.reuseVariable = true; | ||
51 | break; | ||
52 | case "-p"_id: | ||
53 | writeToFile = false; | ||
54 | break; | ||
55 | case "-t"_id: | ||
56 | ++i; | ||
57 | if (i < narg) { | ||
58 | targetPath = args[i]; | ||
59 | } else { | ||
60 | std::cout << help; | ||
61 | return 1; | ||
62 | } | ||
63 | break; | ||
64 | case "-b"_id: | ||
65 | dumpCompileTime = true; | ||
66 | break; | ||
67 | case "-h"_id: | ||
68 | std::cout << help; | ||
69 | return 0; | ||
70 | case "-v"_id: | ||
71 | std::cout << "Moonscript version: " << MoonP::moonScriptVersion() << '\n'; | ||
72 | break; | ||
73 | case "-o"_id: | ||
74 | ++i; | ||
75 | if (i < narg) { | ||
76 | resultFile = args[i]; | ||
77 | } else { | ||
78 | std::cout << help; | ||
79 | return 1; | ||
80 | } | ||
81 | break; | ||
82 | default: | ||
83 | files.push_back(args[i]); | ||
84 | break; | ||
85 | } | ||
86 | } | ||
87 | if (files.empty()) { | ||
88 | std::cout << help; | ||
89 | return 0; | ||
90 | } | ||
91 | if (!resultFile.empty() && files.size() > 1) { | ||
92 | std::cout << "Error: -o can not be used with multiple input files.\n"; | ||
93 | std::cout << help; | ||
94 | } | ||
95 | for (const auto& file : files) { | ||
96 | std::ifstream input(file, input.in); | ||
97 | if (input) { | ||
98 | std::string s( | ||
99 | (std::istreambuf_iterator<char>(input)), | ||
100 | std::istreambuf_iterator<char>()); | ||
101 | if (dumpCompileTime) { | ||
102 | auto start = std::chrono::high_resolution_clock::now(); | ||
103 | auto result = MoonP::moonCompile(s, config); | ||
104 | auto end = std::chrono::high_resolution_clock::now(); | ||
105 | if (!std::get<0>(result).empty()) { | ||
106 | std::chrono::duration<double> diff = end - start; | ||
107 | error_list el; | ||
108 | MoonP::State st; | ||
109 | start = std::chrono::high_resolution_clock::now(); | ||
110 | auto input = Converter{}.from_bytes(s); | ||
111 | parserlib::parse<MoonP::File_t>(input, MoonP::File, el, &st); | ||
112 | end = std::chrono::high_resolution_clock::now(); | ||
113 | std::chrono::duration<double> parseDiff = end - start; | ||
114 | std::cout << file << " \n"; | ||
115 | std::cout << "Parse time: " << std::setprecision(5) << parseDiff.count() * 1000 << " ms\n"; | ||
116 | std::cout << "Compile time: " << std::setprecision(5) << (diff.count() - parseDiff.count()) * 1000 << " ms\n\n"; | ||
117 | } else { | ||
118 | std::cout << "Fail to compile: " << file << ".\n"; | ||
119 | std::cout << std::get<1>(result) << '\n'; | ||
120 | return 1; | ||
121 | } | ||
122 | continue; | ||
123 | } | ||
124 | auto result = MoonP::moonCompile(s, config); | ||
125 | if (!std::get<0>(result).empty()) { | ||
126 | if (!writeToFile) { | ||
127 | std::cout << std::get<0>(result) << '\n'; | ||
128 | } else { | ||
129 | std::string targetFile; | ||
130 | if (resultFile.empty()) { | ||
131 | std::string ext; | ||
132 | targetFile = file; | ||
133 | size_t pos = file.rfind('.'); | ||
134 | if (pos != std::string::npos) { | ||
135 | ext = file.substr(pos + 1); | ||
136 | for (size_t i = 0; i < ext.length(); i++) { | ||
137 | ext[i] = static_cast<char>(tolower(ext[i])); | ||
138 | } | ||
139 | targetFile = file.substr(0, pos) + ".lua"; | ||
140 | } | ||
141 | if (!targetPath.empty()) { | ||
142 | std::string name; | ||
143 | pos = targetFile.find_last_of("/\\"); | ||
144 | if (pos == std::string::npos) { | ||
145 | name = targetFile; | ||
146 | } else { | ||
147 | name = targetFile.substr(pos + 1); | ||
148 | } | ||
149 | if (targetPath.back() != '/' && targetPath.back() != '\\') { | ||
150 | targetPath.append("/"); | ||
151 | } | ||
152 | targetFile = targetPath + name; | ||
153 | } | ||
154 | } else { | ||
155 | targetFile = resultFile; | ||
156 | } | ||
157 | std::ofstream output(targetFile, output.trunc | output.out); | ||
158 | if (output) { | ||
159 | const auto& codes = std::get<0>(result); | ||
160 | output.write(codes.c_str(), codes.size()); | ||
161 | std::cout << "Built " << file << '\n'; | ||
162 | } else { | ||
163 | std::cout << "Fail to write file: " << targetFile << ".\n"; | ||
164 | return 1; | ||
165 | } | ||
166 | } | ||
167 | } else { | ||
168 | std::cout << "Fail to compile: " << file << ".\n"; | ||
169 | std::cout << std::get<1>(result) << '\n'; | ||
170 | return 1; | ||
171 | } | ||
172 | } else { | ||
173 | std::cout << "Fail to read file: " << file << ".\n"; | ||
174 | return 1; | ||
175 | } | ||
176 | } | ||
177 | return 0; | ||
178 | } | ||