aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2021-02-08 13:38:07 +0800
committerLi Jin <dragon-fly@qq.com>2021-02-08 13:38:07 +0800
commit24dab43a753538dcf3b85bd09bf76c0a3c3c8b73 (patch)
tree51c59ddf8302657ae3cce5d28ba27c66737fc842
parent32651cccb380bf4682fa8f6d3e70d74952171f7b (diff)
downloadyuescript-24dab43a753538dcf3b85bd09bf76c0a3c3c8b73.tar.gz
yuescript-24dab43a753538dcf3b85bd09bf76c0a3c3c8b73.tar.bz2
yuescript-24dab43a753538dcf3b85bd09bf76c0a3c3c8b73.zip
simplify macro syntax. fix issue #38 again.
-rw-r--r--spec/inputs/ambiguous.mp2
-rw-r--r--spec/inputs/attrib.mp6
-rw-r--r--spec/inputs/macro-export.mp9
-rw-r--r--spec/inputs/macro-teal.mp51
-rw-r--r--spec/inputs/macro.mp74
-rw-r--r--src/MoonP/moon_ast.h6
-rw-r--r--src/MoonP/moon_compiler.cpp245
-rw-r--r--src/MoonP/moon_parser.cpp3
-rw-r--r--src/MoonP/moon_parser.h1
9 files changed, 226 insertions, 171 deletions
diff --git a/spec/inputs/ambiguous.mp b/spec/inputs/ambiguous.mp
index a5980db..d147e8e 100644
--- a/spec/inputs/ambiguous.mp
+++ b/spec/inputs/ambiguous.mp
@@ -10,7 +10,7 @@ import c from d
10a, b = c, d 10a, b = c, d
11(d a) c 11(d a) c
12 12
13macro block f = (func,arg)-> "(#{func}) #{arg}" 13macro f = (func,arg)-> "(#{func}) #{arg}"
14for i = 1, 10 14for i = 1, 10
15 a = -> 15 a = ->
16 $f print, 1 16 $f print, 1
diff --git a/spec/inputs/attrib.mp b/spec/inputs/attrib.mp
index bc1e67e..7e9a42c 100644
--- a/spec/inputs/attrib.mp
+++ b/spec/inputs/attrib.mp
@@ -14,8 +14,8 @@ do
14 close f = with io.open "file.txt" 14 close f = with io.open "file.txt"
15 \write "Hello" 15 \write "Hello"
16 16
17macro block defer = (item)-> "close _ = #{item}" 17macro defer = (item)-> "close _ = #{item}"
18macro block defer_f = (func)-> "close _ = setmetatable {},__close:#{func}" 18macro defer_f = (func)-> "close _ = setmetatable {},__close:#{func}"
19 19
20do 20do
21 $defer with io.open "file.txt" 21 $defer with io.open "file.txt"
@@ -29,7 +29,7 @@ _defers = setmetatable {},__close:=>
29 @[#@]! 29 @[#@]!
30 @[#@] = nil 30 @[#@] = nil
31 31
32macro block defer_i = (item)-> " 32macro defer_i = (item)-> "
33_defers[#_defers + 1] = #{item} 33_defers[#_defers + 1] = #{item}
34close _ = _defers" 34close _ = _defers"
35 35
diff --git a/spec/inputs/macro-export.mp b/spec/inputs/macro-export.mp
index b6079ca..d669975 100644
--- a/spec/inputs/macro-export.mp
+++ b/spec/inputs/macro-export.mp
@@ -1,9 +1,9 @@
1export macro block config = (debugging = true)-> 1export macro config = (debugging = true)->
2 global debugMode = debugging == "true" 2 global debugMode = debugging == "true"
3 global debugMacro = true 3 global debugMacro = true
4 "" 4 ""
5 5
6export macro expr showMacro = (name,res)-> 6export macro showMacro = (name,res)->
7 if debugMacro 7 if debugMacro
8 "do 8 "do
9 txt = #{res} 9 txt = #{res}
@@ -13,16 +13,17 @@ export macro expr showMacro = (name,res)->
13 else 13 else
14 res 14 res
15 15
16export macro block asserts = (cond)-> 16export macro asserts = (cond)->
17 if debugMode 17 if debugMode
18 $showMacro "assert", "assert #{cond}" 18 $showMacro "assert", "assert #{cond}"
19 else 19 else
20 "" 20 ""
21 21
22export macro expr assert = (cond)-> 22export macro assert = (cond)->
23 if debugMode 23 if debugMode
24 $showMacro "assert", "assert #{cond}" 24 $showMacro "assert", "assert #{cond}"
25 else 25 else
26 "#{cond}" 26 "#{cond}"
27 27
28$config! 28$config!
29
diff --git a/spec/inputs/macro-teal.mp b/spec/inputs/macro-teal.mp
index 9ce1bcd..37cde1c 100644
--- a/spec/inputs/macro-teal.mp
+++ b/spec/inputs/macro-teal.mp
@@ -4,24 +4,29 @@ $ ->
4 options.target_extension = "tl" 4 options.target_extension = "tl"
5 package.path ..= "?.lua;./spec/lib/?.lua" 5 package.path ..= "?.lua;./spec/lib/?.lua"
6 6
7macro expr to_lua = (codes)-> 7macro to_lua = (codes)->
8 "require('moonp').to_lua(#{codes}, reserve_line_number:false, same_module:true)" 8 "require('moonp').to_lua(#{codes}, reserve_line_number:false, same_module:true)"
9 9
10macro expr trim = (name)-> 10macro trim = (name)->
11 "if result = #{name}\\match '[\\'\"](.*)[\\'\"]' then result else #{name}" 11 "if result = #{name}\\match '[\\'\"](.*)[\\'\"]' then result else #{name}"
12 12
13export macro text local = (decl, value = nil)-> 13export macro local = (decl, value = nil)->
14 import "moonp" as {options:{:tl_enabled}} 14 import "moonp" as {options:{:tl_enabled}}
15 name, type = ($trim decl)\match "(.-):(.*)" 15 name, type = ($trim decl)\match "(.-):(.*)"
16 if not (name and type) 16 if not (name and type)
17 error "invalid local varaible declaration for \"#{decl}\"" 17 error "invalid local varaible declaration for \"#{decl}\""
18 value = $to_lua(value)\gsub "^return ", "" 18 value = $to_lua(value)\gsub "^return ", ""
19 if tl_enabled 19 codes = if tl_enabled
20 "local #{name}:#{$trim type} = #{value}", {name} 20 "local #{name}:#{$trim type} = #{value}"
21 else 21 else
22 "local #{name} = #{value}", {name} 22 "local #{name} = #{value}"
23 {
24 :codes
25 type: "text"
26 locals: {name}
27 }
23 28
24export macro text function = (decl, value)-> 29export macro function = (decl, value)->
25 import "moonp" as {options:{:tl_enabled}} 30 import "moonp" as {options:{:tl_enabled}}
26 import "tl" 31 import "tl"
27 decl = $trim decl 32 decl = $trim decl
@@ -32,23 +37,33 @@ export macro text function = (decl, value)->
32 _, node = tl.parse_program tokens,{},"macro-function" 37 _, node = tl.parse_program tokens,{},"macro-function"
33 args = table.concat [arg.tk for arg in *node[1].args],", " 38 args = table.concat [arg.tk for arg in *node[1].args],", "
34 value = "(#{args})#{value}" 39 value = "(#{args})#{value}"
35 if tl_enabled 40 codes = if tl_enabled
36 value = $to_lua(value)\match "function%([^\n]*%)(.*)end" 41 value = $to_lua(value)\match "function%([^\n]*%)(.*)end"
37 "local function #{name}#{type}\n#{value}\nend", {name} 42 "local function #{name}#{type}\n#{value}\nend"
38 else 43 else
39 value = $to_lua(value)\gsub "^return ", "" 44 value = $to_lua(value)\gsub "^return ", ""
40 "local #{name} = #{value}", {name} 45 "local #{name} = #{value}"
46 {
47 :codes
48 type: "text"
49 locals: {name}
50 }
41 51
42export macro text record = (name, decl)-> 52export macro record = (name, decl)->
43 import "moonp" as {options:{:tl_enabled}} 53 import "moonp" as {options:{:tl_enabled}}
44 if tl_enabled 54 codes = if tl_enabled
45 "local record #{name} 55 "local record #{name}
46 #{decl} 56 #{decl}
47end", {name} 57end"
48 else 58 else
49 "local #{name} = {}", {name} 59 "local #{name} = {}"
60 {
61 :codes
62 type: "text"
63 locals: {name}
64 }
50 65
51export macro text method = (decl, value)-> 66export macro method = (decl, value)->
52 import "moonp" as {options:{:tl_enabled}} 67 import "moonp" as {options:{:tl_enabled}}
53 import "tl" 68 import "tl"
54 decl = $trim decl 69 decl = $trim decl
@@ -59,10 +74,14 @@ export macro text method = (decl, value)->
59 _, node = tl.parse_program tokens,{},"macro-function" 74 _, node = tl.parse_program tokens,{},"macro-function"
60 args = table.concat [arg.tk for arg in *node[1].args],", " 75 args = table.concat [arg.tk for arg in *node[1].args],", "
61 value = "(#{args})->#{value\match "[%-=]>(.*)"}" 76 value = "(#{args})->#{value\match "[%-=]>(.*)"}"
62 if tl_enabled 77 codes = if tl_enabled
63 value = $to_lua(value)\match "^return function%(.-%)\n(.*)end" 78 value = $to_lua(value)\match "^return function%(.-%)\n(.*)end"
64 "function #{tab}#{sym}#{func}#{type}\n#{value}\nend" 79 "function #{tab}#{sym}#{func}#{type}\n#{value}\nend"
65 else 80 else
66 value = $to_lua(value)\gsub "^return ", "" 81 value = $to_lua(value)\gsub "^return ", ""
67 "#{tab}.#{func} = #{value}" 82 "#{tab}.#{func} = #{value}"
83 {
84 :codes
85 type: "text"
86 }
68 87
diff --git a/spec/inputs/macro.mp b/spec/inputs/macro.mp
index da696bd..f0292c7 100644
--- a/spec/inputs/macro.mp
+++ b/spec/inputs/macro.mp
@@ -12,7 +12,7 @@ $myconfig false
12 12
13v = $assert item == nil 13v = $assert item == nil
14 14
15macro expr and = (...)-> 15macro and = (...)->
16 values = [value for value in *{...}] 16 values = [value for value in *{...}]
17 $showMacro "and", "#{ table.concat values, " and " }" 17 $showMacro "and", "#{ table.concat values, " and " }"
18 18
@@ -22,20 +22,20 @@ if $and f1!
22if $and f1!, f2!, f3! 22if $and f1!, f2!, f3!
23 print "OK" 23 print "OK"
24 24
25macro expr in = (target, ...)-> 25macro in = (target, ...)->
26 values = [value for value in *{...}] 26 values = [value for value in *{...}]
27 $showMacro "in", table.concat ["#{target} == #{item}" for item in *values], " or " 27 $showMacro "in", table.concat ["#{target} == #{item}" for item in *values], " or "
28 28
29if x |> $in "Apple", "Pig", "Dog" 29if x |> $in "Apple", "Pig", "Dog"
30 print "exist" 30 print "exist"
31 31
32macro expr map = (items, action)-> 32macro map = (items, action)->
33 $showMacro "map", "[#{action} for _ in *#{items}]" 33 $showMacro "map", "[#{action} for _ in *#{items}]"
34 34
35macro expr filter = (items, action)-> 35macro filter = (items, action)->
36 $showMacro "filter", "[_ for _ in *#{items} when #{action}]" 36 $showMacro "filter", "[_ for _ in *#{items} when #{action}]"
37 37
38macro expr reduce = (items, def, action)-> 38macro reduce = (items, def, action)->
39 $showMacro "reduce", "if ##{items} == 0 39 $showMacro "reduce", "if ##{items} == 0
40 #{def} 40 #{def}
41else 41else
@@ -44,11 +44,11 @@ else
44 _1 = #{action} 44 _1 = #{action}
45 _1" 45 _1"
46 46
47macro block foreach = (items, action)-> 47macro foreach = (items, action)->
48 $showMacro "foreach", "for _ in *#{items} 48 $showMacro "foreach", "for _ in *#{items}
49 #{action}" 49 #{action}"
50 50
51macro expr pipe = (...)-> 51macro pipe = (...)->
52 switch select "#", ... 52 switch select "#", ...
53 when 0 then return "" 53 when 0 then return ""
54 when 1 then return ... 54 when 1 then return ...
@@ -74,13 +74,13 @@ val = $pipe(
74 $reduce(0, _1 + _2) 74 $reduce(0, _1 + _2)
75) 75)
76 76
77macro expr plus = (a, b)-> "#{a} + #{b}" 77macro plus = (a, b)-> "#{a} + #{b}"
78 78
79$plus(1,2)\call 123 79$plus(1,2)\call 123
80 80
81res = 1 |> $plus 2 81res = 1 |> $plus 2
82 82
83macro expr curry = (...)-> 83macro curry = (...)->
84 args = {...} 84 args = {...}
85 len = #args 85 len = #args
86 body = args[len] 86 body = args[len]
@@ -90,11 +90,11 @@ macro expr curry = (...)->
90f = $curry x,y,z,do 90f = $curry x,y,z,do
91 print x,y,z 91 print x,y,z
92 92
93macro expr get_inner = (var)-> "do 93macro get_inner = (var)-> "do
94 a = 1 94 a = 1
95 a + 1" 95 a + 1"
96 96
97macro expr get_inner_hygienic = (var)-> "(-> 97macro get_inner_hygienic = (var)-> "(->
98 local a = 1 98 local a = 1
99 a + 1)!" 99 a + 1)!"
100 100
@@ -110,7 +110,10 @@ do
110 a += $get_inner_hygienic! 110 a += $get_inner_hygienic!
111 print a 111 print a
112 112
113macro lua lua = (codes)-> codes 113macro lua = (codes)-> {
114 :codes
115 type: "lua"
116}
114 117
115x = 0 118x = 0
116 119
@@ -129,12 +132,15 @@ end
129 132
130print x 133print x
131 134
132macro lua def = (fname, ...)-> 135macro def = (fname, ...)->
133 args = {...} 136 args = {...}
134 last = table.remove args 137 last = table.remove args
135 $showMacro "def", "local function #{fname}(#{table.concat args, ', '}) 138 {
139 codes: $showMacro "def", "local function #{fname}(#{table.concat args, ', '})
136 #{last} 140 #{last}
137end" 141end"
142 type: "lua"
143 }
138 144
139sel = (a, b, c)-> if a then b else c 145sel = (a, b, c)-> if a then b else c
140 146
@@ -148,13 +154,16 @@ $def sel, a, b, c, [[
148 154
149$def dummy,[[]] 155$def dummy,[[]]
150 156
151macro lua insertComment = (text)-> "-- #{text\match '[\'"](.*)[\'"]'}" 157macro insertComment = (text)-> {
158 codes: "-- #{text\match '[\'"](.*)[\'"]'}"
159 type: "lua"
160}
152 161
153$insertComment "a comment here" 162$insertComment "a comment here"
154 163
155import 'underscore' as _ 164import 'underscore' as _
156 165
157macro expr chain = (...)-> 166macro chain = (...)->
158 callable = nil 167 callable = nil
159 for item in *{...} 168 for item in *{...}
160 callable = callable? and "(#{callable})\\#{item}" or item 169 callable = callable? and "(#{callable})\\#{item}" or item
@@ -186,7 +195,7 @@ result = $chain(
186 Destroy! 195 Destroy!
187) 196)
188 197
189macro block chainB = (...)-> 198macro chainB = (...)->
190 switch select "#", ... 199 switch select "#", ...
191 when 0 then return "" 200 when 0 then return ""
192 when 1 then return ... 201 when 1 then return ...
@@ -216,7 +225,34 @@ $chainB(
216 Destroy! 225 Destroy!
217) 226)
218 227
219macro block implicitReturnblockMacroIsAllowed = -> "123" 228macro chainC = (...)->
229 import "moonp" as {:to_lua}
230 callable = nil
231 config = {
232 implicit_return_root: false
233 reserve_line_number: false
234 }
235 for item in *{...}
236 if callable?
237 callable = "#{callable}:#{to_lua(item,config)\gsub '%s*$',''}"
238 else
239 callable = to_lua(item,config)\gsub '%s*$',''
240 {
241 codes: $showMacro "chainC", callable
242 type: "lua"
243 }
244
245$chainC(
246 origin.transform.root.gameObject\Parents!
247 Descendants!
248 SelectEnable!
249 SelectVisible!
250 TagEqual "fx"
251 Where (x) -> x.name\EndsWith "(Clone)"
252 Destroy!
253)
254
255macro implicitReturnMacroIsAllowed = -> "print 'abc'\n123"
220 256
221$implicitReturnblockMacroIsAllowed! 257$implicitReturnMacroIsAllowed!
222 258
diff --git a/src/MoonP/moon_ast.h b/src/MoonP/moon_ast.h
index 576b2cf..c426ef7 100644
--- a/src/MoonP/moon_ast.h
+++ b/src/MoonP/moon_ast.h
@@ -632,9 +632,6 @@ AST_NODE(FunLit)
632 AST_MEMBER(FunLit, &argsDef, &arrow, &body) 632 AST_MEMBER(FunLit, &argsDef, &arrow, &body)
633AST_END(FunLit) 633AST_END(FunLit)
634 634
635AST_LEAF(macro_type)
636AST_END(macro_type)
637
638AST_NODE(MacroName) 635AST_NODE(MacroName)
639 ast_ptr<false, Name_t> name; 636 ast_ptr<false, Name_t> name;
640 AST_MEMBER(MacroName, &name) 637 AST_MEMBER(MacroName, &name)
@@ -647,10 +644,9 @@ AST_NODE(MacroLit)
647AST_END(MacroLit) 644AST_END(MacroLit)
648 645
649AST_NODE(Macro) 646AST_NODE(Macro)
650 ast_ptr<true, macro_type_t> type;
651 ast_ptr<true, Name_t> name; 647 ast_ptr<true, Name_t> name;
652 ast_ptr<true, MacroLit_t> macroLit; 648 ast_ptr<true, MacroLit_t> macroLit;
653 AST_MEMBER(Macro, &type, &name, &macroLit) 649 AST_MEMBER(Macro, &name, &macroLit)
654AST_END(Macro) 650AST_END(Macro)
655 651
656AST_NODE(NameOrDestructure) 652AST_NODE(NameOrDestructure)
diff --git a/src/MoonP/moon_compiler.cpp b/src/MoonP/moon_compiler.cpp
index 4812cf4..d63b1c7 100644
--- a/src/MoonP/moon_compiler.cpp
+++ b/src/MoonP/moon_compiler.cpp
@@ -53,7 +53,7 @@ inline std::string s(std::string_view sv) {
53 return std::string(sv); 53 return std::string(sv);
54} 54}
55 55
56const std::string_view version = "0.4.26"sv; 56const std::string_view version = "0.5.0"sv;
57const std::string_view extension = "mp"sv; 57const std::string_view extension = "mp"sv;
58 58
59class MoonCompilerImpl { 59class MoonCompilerImpl {
@@ -2290,7 +2290,6 @@ private:
2290 if (_scopes.size() > 1) { 2290 if (_scopes.size() > 1) {
2291 throw std::logic_error(_info.errorMessage("can not define macro outside the root block"sv, macro)); 2291 throw std::logic_error(_info.errorMessage("can not define macro outside the root block"sv, macro));
2292 } 2292 }
2293 auto type = _parser.toString(macro->type);
2294 auto macroName = _parser.toString(macro->name); 2293 auto macroName = _parser.toString(macro->name);
2295 auto argsDef = macro->macroLit->argsDef.get(); 2294 auto argsDef = macro->macroLit->argsDef.get();
2296 str_list newArgs; 2295 str_list newArgs;
@@ -2314,9 +2313,8 @@ private:
2314 newArgs.emplace_back(_parser.toString(argsDef->varArg)); 2313 newArgs.emplace_back(_parser.toString(argsDef->varArg));
2315 } 2314 }
2316 } 2315 }
2317 _buf << "fmacro = ("sv << join(newArgs, ","sv) << ")->"sv; 2316 _buf << "("sv << join(newArgs, ","sv) << ")->"sv;
2318 _buf << _parser.toString(macro->macroLit->body) << '\n'; 2317 _buf << _parser.toString(macro->macroLit->body);
2319 _buf << "{fmacro, \"" << type << "\"}"sv;
2320 auto macroCodes = clearBuf(); 2318 auto macroCodes = clearBuf();
2321 _buf << "=(macro "sv << macroName << ")"; 2319 _buf << "=(macro "sv << macroName << ")";
2322 auto chunkName = clearBuf(); 2320 auto chunkName = clearBuf();
@@ -3128,16 +3126,15 @@ private:
3128 std::string err = lua_tostring(L, -1); 3126 std::string err = lua_tostring(L, -1);
3129 throw std::logic_error(_info.errorMessage(s("failed to expand macro: "sv) + err, x)); 3127 throw std::logic_error(_info.errorMessage(s("failed to expand macro: "sv) + err, x));
3130 } 3128 }
3131 return {s("block"sv), Empty, {}}; 3129 return {Empty, Empty, {}};
3132 } 3130 }
3133 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macroName 3131 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macroName
3134 lua_rawget(L, -2); // cur[macroName], cur macro 3132 lua_rawget(L, -2); // cur[macroName], cur macroFunc
3135 if (lua_istable(L, -1) == 0) { 3133 if (lua_isfunction(L, -1) == 0) {
3136 throw std::logic_error(_info.errorMessage("can not resolve macro"sv, x)); 3134 throw std::logic_error(_info.errorMessage("can not resolve macro"sv, x));
3137 } 3135 } // cur macroFunc
3138 lua_rawgeti(L, -1, 1); // cur macro func 3136 pushMoonp("pcall"sv); // cur macroFunc pcall
3139 pushMoonp("pcall"sv); // cur macro func pcall 3137 lua_insert(L, -2); // cur pcall macroFunc
3140 lua_insert(L, -2); // cur macro pcall func
3141 auto item = *(++chainList.begin()); 3138 auto item = *(++chainList.begin());
3142 const node_container* args = nullptr; 3139 const node_container* args = nullptr;
3143 if (auto invoke = ast_cast<Invoke_t>(item)) { 3140 if (auto invoke = ast_cast<Invoke_t>(item)) {
@@ -3186,47 +3183,60 @@ private:
3186 Utils::trim(str); 3183 Utils::trim(str);
3187 Utils::replace(str, "\r\n"sv, "\n"sv); 3184 Utils::replace(str, "\r\n"sv, "\n"sv);
3188 lua_pushlstring(L, str.c_str(), str.size()); 3185 lua_pushlstring(L, str.c_str(), str.size());
3189 } // cur macro pcall func args... 3186 } // cur pcall macroFunc args...
3190 bool success = lua_pcall(L, static_cast<int>(args->size()) + 1, 3, 0) == 0; 3187 bool success = lua_pcall(L, static_cast<int>(args->size()) + 1, 2, 0) == 0;
3191 if (!success) { // cur macro err 3188 if (!success) { // cur err
3192 std::string err = lua_tostring(L, -1); 3189 std::string err = lua_tostring(L, -1);
3193 throw std::logic_error(_info.errorMessage(s("failed to expand macro: "sv) + err, x)); 3190 throw std::logic_error(_info.errorMessage(s("failed to expand macro: "sv) + err, x));
3194 } // cur macro success res option 3191 } // cur success res
3195 if (lua_toboolean(L, -3) == 0) { 3192 if (lua_toboolean(L, -2) == 0) {
3196 std::string err = lua_tostring(L, -2); 3193 std::string err = lua_tostring(L, -2);
3197 throw std::logic_error(_info.errorMessage(s("failed to expand macro: "sv) + err, x)); 3194 throw std::logic_error(_info.errorMessage(s("failed to expand macro: "sv) + err, x));
3198 } 3195 }
3199 lua_remove(L, -3); // cur macro res option 3196 lua_remove(L, -2); // cur res
3200 if (lua_isstring(L, -2) == 0) { 3197 if (lua_isstring(L, -1) == 0 && lua_istable(L, -1) == 0) {
3201 throw std::logic_error(_info.errorMessage(s("macro function must return string with expanded codes"sv), x)); 3198 throw std::logic_error(_info.errorMessage(s("macro function must return string or table"sv), x));
3202 } // cur macro codes option 3199 } // cur res
3203 lua_rawgeti(L, -3, 2); // cur macro codes option type 3200 std::string codes;
3204 std::string type = lua_tostring(L, -1); 3201 std::string type;
3205 lua_pop(L, 1); // cur macro codes option
3206 str_list localVars; 3202 str_list localVars;
3207 if (lua_isnil(L, -1) == 0) { 3203 if (lua_istable(L, -1) != 0) {
3208 if (lua_istable(L, -1) == 0) { 3204 lua_getfield(L, -1, "codes"); // cur res codes
3209 throw std::logic_error(_info.errorMessage(s("macro function must return expanded codes followed by a config table"sv), x)); 3205 if (lua_isstring(L, -1) != 0) {
3210 } 3206 codes = lua_tostring(L, -1);
3211 if (type == "expr"sv || type == "block"sv) { 3207 } else {
3212 throw std::logic_error(_info.errorMessage(s("expr or block macro is not accepting config table"sv), x)); 3208 throw std::logic_error(_info.errorMessage(s("macro table must contain field \"codes\" of string"sv), x));
3213 } 3209 }
3214 for (int i = 0; i < static_cast<int>(lua_objlen(L, -1)); i++) { 3210 lua_pop(L, 1); // cur res
3215 lua_rawgeti(L, -1, i + 1); // cur macro codes option item 3211 lua_getfield(L, -1, "type"); // cur res type
3216 size_t len = 0; 3212 if (lua_isstring(L, -1) != 0) {
3217 if (lua_isstring(L, -1) == 0) { 3213 type = lua_tostring(L, -1);
3218 throw std::logic_error(_info.errorMessage(s("macro config table must contains strings"sv), x)); 3214 }
3219 } 3215 if (type != "lua"sv && type != "text"sv) {
3220 auto name = lua_tolstring(L, -1, &len); 3216 throw std::logic_error(_info.errorMessage(s("macro table must contain field \"type\" of value \"lua\" or \"text\""sv), x));
3221 if (_parser.match<Variable_t>({name, len})) { 3217 }
3222 localVars.push_back(std::string(name, len)); 3218 lua_pop(L, 1); // cur res
3223 } else { 3219 lua_getfield(L, -1, "locals"); // cur res locals
3224 throw std::logic_error(_info.errorMessage(s("macro config table must contains names for local variables, got \""sv) + std::string(name, len) + '"', x)); 3220 if (lua_istable(L, -1) != 0) {
3221 for (int i = 0; i < static_cast<int>(lua_objlen(L, -1)); i++) {
3222 lua_rawgeti(L, -1, i + 1); // cur res locals item
3223 size_t len = 0;
3224 if (lua_isstring(L, -1) == 0) {
3225 throw std::logic_error(_info.errorMessage(s("macro table field \"locals\" must be a table of strings"sv), x));
3226 }
3227 auto name = lua_tolstring(L, -1, &len);
3228 if (_parser.match<Variable_t>({name, len})) {
3229 localVars.push_back(std::string(name, len));
3230 } else {
3231 throw std::logic_error(_info.errorMessage(s("macro table field \"locals\" must contain names for local variables, got \""sv) + std::string(name, len) + '"', x));
3232 }
3233 lua_pop(L, 1);
3225 } 3234 }
3226 lua_pop(L, 1);
3227 } 3235 }
3228 } // cur macro codes option 3236 lua_pop(L, 1); // cur res
3229 std::string codes = lua_tostring(L, -2); 3237 } else {
3238 codes = lua_tostring(L, -1);
3239 }
3230 return {type, codes, std::move(localVars)}; 3240 return {type, codes, std::move(localVars)};
3231 } 3241 }
3232 3242
@@ -3236,10 +3246,10 @@ private:
3236 std::string type, codes; 3246 std::string type, codes;
3237 str_list localVars; 3247 str_list localVars;
3238 std::tie(type, codes, localVars) = expandMacroStr(chainValue); 3248 std::tie(type, codes, localVars) = expandMacroStr(chainValue);
3239 std::string targetType(usage != ExpUsage::Common || chainList.size() > 2 ? "expr"sv : "block"sv); 3249 bool isBlock = (usage == ExpUsage::Common) && (chainList.size() <= 2);
3240 ParseInfo info; 3250 ParseInfo info;
3241 if (type == "lua"sv) { 3251 if (type == "lua"sv) {
3242 if (!allowBlockMacroReturn && targetType != "block"sv) { 3252 if (!allowBlockMacroReturn && !isBlock) {
3243 throw std::logic_error(_info.errorMessage("lua macro can only be placed where block macro is allowed"sv, x)); 3253 throw std::logic_error(_info.errorMessage("lua macro can only be placed where block macro is allowed"sv, x));
3244 } 3254 }
3245 auto macroChunk = s("=(macro "sv) + _parser.toString(x->name) + ')'; 3255 auto macroChunk = s("=(macro "sv) + _parser.toString(x->name) + ')';
@@ -3251,85 +3261,77 @@ private:
3251 } 3261 }
3252 return {nullptr, nullptr, std::move(codes), std::move(localVars)}; 3262 return {nullptr, nullptr, std::move(codes), std::move(localVars)};
3253 } else if (type == "text"sv) { 3263 } else if (type == "text"sv) {
3254 if (!allowBlockMacroReturn && targetType != "block"sv) {
3255 throw std::logic_error(_info.errorMessage("text macro can only be placed where block macro is allowed"sv, x));
3256 }
3257 return {nullptr, nullptr, std::move(codes), std::move(localVars)}; 3264 return {nullptr, nullptr, std::move(codes), std::move(localVars)};
3258 } else if (!allowBlockMacroReturn && type != targetType) {
3259 if (!codes.empty() && targetType == "block") {
3260 info = _parser.parse<Block_t>(codes);
3261 }
3262 if (info.node) type = "block";
3263 else throw std::logic_error(_info.errorMessage(s("macro type mismatch, "sv) + targetType + s(" expected, got "sv) + type, x));
3264 }
3265 BLOCK_START
3266 BREAK_IF(info.node);
3267 if (usage == ExpUsage::Common) {
3268 if (codes.empty()) {
3269 return {x->new_ptr<Block_t>().get(), std::move(info.codes), Empty, std::move(localVars)};
3270 }
3271 if (type == "expr"sv) {
3272 info = _parser.parse<Exp_t>(codes);
3273 } else {
3274 info = _parser.parse<Block_t>(codes);
3275 }
3276 } else if (allowBlockMacroReturn) {
3277 if (type == "expr"sv) {
3278 info = _parser.parse<Exp_t>(codes);
3279 } else {
3280 info = _parser.parse<Block_t>(codes);
3281 }
3282 } else { 3265 } else {
3283 info = _parser.parse<Exp_t>(codes); 3266 if (!codes.empty()) {
3284 } 3267 if (isBlock) {
3285 BLOCK_END 3268 info = _parser.parse<Block_t>(codes);
3286 if (!info.node) { 3269 if (!info.node) {
3287 info.error = info.error.substr(info.error.find(':') + 2); 3270 info.error = info.error.substr(info.error.find(':') + 2);
3288 throw std::logic_error(_info.errorMessage("failed to parse expanded codes: " + info.error, x)); 3271 throw std::logic_error(_info.errorMessage(s("failed to expanded macro as block: "sv) + info.error, x));
3289 } 3272 }
3290 int line = x->m_begin.m_line; 3273 } else {
3291 int col = x->m_begin.m_col; 3274 info = _parser.parse<Exp_t>(codes);
3292 info.node->traverse([&](ast_node* node) { 3275 if (!info.node && allowBlockMacroReturn) {
3293 node->m_begin.m_line = line; 3276 info = _parser.parse<Block_t>(codes);
3294 node->m_end.m_line = line; 3277 if (!info.node) {
3295 node->m_begin.m_col = col; 3278 info.error = info.error.substr(info.error.find(':') + 2);
3296 node->m_end.m_col = col; 3279 throw std::logic_error(_info.errorMessage(s("failed to expanded macro as expr or block: "sv) + info.error, x));
3297 return traversal::Continue; 3280 }
3298 }); 3281 isBlock = true;
3299 if (type == "expr"sv) { 3282 } else if (!info.node) {
3300 ast_ptr<false, Exp_t> exp; 3283 info.error = info.error.substr(info.error.find(':') + 2);
3301 exp.set(info.node); 3284 throw std::logic_error(_info.errorMessage(s("failed to expanded macro as expr: "sv) + info.error, x));
3302 if (!exp->opValues.empty() || chainList.size() > 2) { 3285 }
3303 auto paren = x->new_ptr<Parens_t>();
3304 paren->expr.set(exp);
3305 auto callable = x->new_ptr<Callable_t>();
3306 callable->item.set(paren);
3307 auto newChain = x->new_ptr<ChainValue_t>();
3308 newChain->items.push_back(callable);
3309 auto it = chainList.begin();
3310 it++; it++;
3311 for (; it != chainList.end(); ++it) {
3312 newChain->items.push_back(*it);
3313 } 3286 }
3314 auto value = x->new_ptr<Value_t>(); 3287 int line = x->m_begin.m_line;
3315 value->item.set(newChain); 3288 int col = x->m_begin.m_col;
3316 exp = newExp(value, x); 3289 info.node->traverse([&](ast_node* node) {
3317 } 3290 node->m_begin.m_line = line;
3318 if (usage == ExpUsage::Common) { 3291 node->m_end.m_line = line;
3319 auto expList = x->new_ptr<ExpList_t>(); 3292 node->m_begin.m_col = col;
3320 expList->exprs.push_back(exp); 3293 node->m_end.m_col = col;
3321 auto exps = x->new_ptr<ExpListAssign_t>(); 3294 return traversal::Continue;
3322 exps->expList.set(expList); 3295 });
3323 auto stmt = x->new_ptr<Statement_t>(); 3296 if (!isBlock) {
3324 stmt->content.set(exps); 3297 ast_ptr<false, Exp_t> exp;
3325 auto block = x->new_ptr<Block_t>(); 3298 exp.set(info.node);
3326 block->statements.push_back(stmt); 3299 if (!exp->opValues.empty() || chainList.size() > 2) {
3327 info.node.set(block); 3300 auto paren = x->new_ptr<Parens_t>();
3301 paren->expr.set(exp);
3302 auto callable = x->new_ptr<Callable_t>();
3303 callable->item.set(paren);
3304 auto newChain = x->new_ptr<ChainValue_t>();
3305 newChain->items.push_back(callable);
3306 auto it = chainList.begin();
3307 it++; it++;
3308 for (; it != chainList.end(); ++it) {
3309 newChain->items.push_back(*it);
3310 }
3311 auto value = x->new_ptr<Value_t>();
3312 value->item.set(newChain);
3313 exp = newExp(value, x);
3314 }
3315 if (usage == ExpUsage::Common) {
3316 auto expList = x->new_ptr<ExpList_t>();
3317 expList->exprs.push_back(exp);
3318 auto exps = x->new_ptr<ExpListAssign_t>();
3319 exps->expList.set(expList);
3320 auto stmt = x->new_ptr<Statement_t>();
3321 stmt->content.set(exps);
3322 auto block = x->new_ptr<Block_t>();
3323 block->statements.push_back(stmt);
3324 info.node.set(block);
3325 } else {
3326 info.node.set(exp);
3327 }
3328 }
3329 return {info.node, std::move(info.codes), Empty, std::move(localVars)};
3328 } else { 3330 } else {
3329 info.node.set(exp); 3331 if (!isBlock) throw std::logic_error(_info.errorMessage(s("failed to expanded empty macro as expr"sv), x));
3332 return {x->new_ptr<Block_t>().get(), std::move(info.codes), Empty, std::move(localVars)};
3330 } 3333 }
3331 } 3334 }
3332 return {info.node, std::move(info.codes), Empty, std::move(localVars)};
3333 } 3335 }
3334#endif // MOONP_NO_MACRO 3336#endif // MOONP_NO_MACRO
3335 3337
@@ -3345,6 +3347,9 @@ private:
3345 Utils::trim(luaCodes); 3347 Utils::trim(luaCodes);
3346 if (!node) { 3348 if (!node) {
3347 if (!luaCodes.empty()) { 3349 if (!luaCodes.empty()) {
3350 if (usage == ExpUsage::Return) {
3351 luaCodes.insert(0, "return "sv);
3352 }
3348 if (_config.reserveLineNumber) { 3353 if (_config.reserveLineNumber) {
3349 luaCodes.insert(0, nll(chainValue).substr(1)); 3354 luaCodes.insert(0, nll(chainValue).substr(1));
3350 } 3355 }
diff --git a/src/MoonP/moon_parser.cpp b/src/MoonP/moon_parser.cpp
index ec95530..6c1382d 100644
--- a/src/MoonP/moon_parser.cpp
+++ b/src/MoonP/moon_parser.cpp
@@ -510,10 +510,9 @@ MoonParser::MoonParser() {
510 FunLit = -FnArgsDef >> Space >> fn_arrow >> -Body; 510 FunLit = -FnArgsDef >> Space >> fn_arrow >> -Body;
511 511
512 MacroName = expr('$') >> -Name; 512 MacroName = expr('$') >> -Name;
513 macro_type = expr("expr") | expr("block") | expr("lua") | expr("text");
514 macro_args_def = sym('(') >> White >> -FnArgDefList >> White >> sym(')'); 513 macro_args_def = sym('(') >> White >> -FnArgDefList >> White >> sym(')');
515 MacroLit = -macro_args_def >> Space >> expr("->") >> Body; 514 MacroLit = -macro_args_def >> Space >> expr("->") >> Body;
516 Macro = key("macro") >> Space >> macro_type >> Space >> Name >> sym('=') >> MacroLit; 515 Macro = key("macro") >> Space >> Name >> sym('=') >> MacroLit;
517 516
518 NameList = Seperator >> Space >> Variable >> *(sym(',') >> Space >> Variable); 517 NameList = Seperator >> Space >> Variable >> *(sym(',') >> Space >> Variable);
519 NameOrDestructure = Space >> Variable | TableLit; 518 NameOrDestructure = Space >> Variable | TableLit;
diff --git a/src/MoonP/moon_parser.h b/src/MoonP/moon_parser.h
index d965d87..f036a7c 100644
--- a/src/MoonP/moon_parser.h
+++ b/src/MoonP/moon_parser.h
@@ -280,7 +280,6 @@ private:
280 AST_RULE(FnArgsDef) 280 AST_RULE(FnArgsDef)
281 AST_RULE(fn_arrow) 281 AST_RULE(fn_arrow)
282 AST_RULE(FunLit) 282 AST_RULE(FunLit)
283 AST_RULE(macro_type)
284 AST_RULE(MacroName) 283 AST_RULE(MacroName)
285 AST_RULE(MacroLit) 284 AST_RULE(MacroLit)
286 AST_RULE(Macro) 285 AST_RULE(Macro)