diff options
author | Li Jin <dragon-fly@qq.com> | 2021-11-19 13:23:11 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2021-11-19 13:23:11 +0800 |
commit | 2ff18b4fb66d25d22e5a25fb386fe171853e0b06 (patch) | |
tree | d6e6f1671f74a4430b24869c74767aaf0ee2e128 | |
parent | a8e5aaf64969792741f3a094fe0070ddb5e3bc7d (diff) | |
download | yuescript-2ff18b4fb66d25d22e5a25fb386fe171853e0b06.tar.gz yuescript-2ff18b4fb66d25d22e5a25fb386fe171853e0b06.tar.bz2 yuescript-2ff18b4fb66d25d22e5a25fb386fe171853e0b06.zip |
try to fix issue #69 with new macro functions. add builtin macro $MODULE and $LINE.
-rw-r--r-- | spec/inputs/macro-teal.yue | 20 | ||||
-rw-r--r-- | spec/inputs/macro.yue | 38 | ||||
-rw-r--r-- | spec/outputs/macro.lua | 31 | ||||
-rw-r--r-- | src/yue.cpp | 6 | ||||
-rw-r--r-- | src/yuescript/stacktraceplus.h | 2 | ||||
-rwxr-xr-x | src/yuescript/yue_compiler.cpp | 157 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.h | 2 | ||||
-rw-r--r-- | src/yuescript/yuescript.cpp | 6 | ||||
-rw-r--r-- | src/yuescript/yuescript.h | 3 |
9 files changed, 171 insertions, 94 deletions
diff --git a/spec/inputs/macro-teal.yue b/spec/inputs/macro-teal.yue index 3a9bb2b..951e882 100644 --- a/spec/inputs/macro-teal.yue +++ b/spec/inputs/macro-teal.yue | |||
@@ -4,8 +4,8 @@ $ -> | |||
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 | ||
7 | macro to_lua = (codes)-> | 7 | macro to_lua = (code)-> |
8 | "require('yue').to_lua(#{codes}, reserve_line_number:false, same_module:true)" | 8 | "require('yue').to_lua(#{code}, reserve_line_number:false, same_module:true)" |
9 | 9 | ||
10 | macro trim = (name)-> | 10 | macro trim = (name)-> |
11 | "if result = #{name}\\match '[\\'\"](.*)[\\'\"]' then result else #{name}" | 11 | "if result = #{name}\\match '[\\'\"](.*)[\\'\"]' then result else #{name}" |
@@ -16,12 +16,12 @@ export macro local = (decl, value = nil)-> | |||
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 | codes = if tl_enabled | 19 | code = if tl_enabled |
20 | "local #{name}:#{$trim type} = #{value}" | 20 | "local #{name}:#{$trim type} = #{value}" |
21 | else | 21 | else |
22 | "local #{name} = #{value}" | 22 | "local #{name} = #{value}" |
23 | { | 23 | { |
24 | :codes | 24 | :code |
25 | type: "text" | 25 | type: "text" |
26 | locals: {name} | 26 | locals: {name} |
27 | } | 27 | } |
@@ -37,28 +37,28 @@ export macro function = (decl, value)-> | |||
37 | _, node = tl.parse_program tokens,{},"macro-function" | 37 | _, node = tl.parse_program tokens,{},"macro-function" |
38 | args = table.concat [arg.tk for arg in *node[1].args],", " | 38 | args = table.concat [arg.tk for arg in *node[1].args],", " |
39 | value = "(#{args})#{value}" | 39 | value = "(#{args})#{value}" |
40 | codes = if tl_enabled | 40 | code = if tl_enabled |
41 | value = $to_lua(value)\match "function%([^\n]*%)(.*)end" | 41 | value = $to_lua(value)\match "function%([^\n]*%)(.*)end" |
42 | "local function #{name}#{type}\n#{value}\nend" | 42 | "local function #{name}#{type}\n#{value}\nend" |
43 | else | 43 | else |
44 | value = $to_lua(value)\gsub "^return ", "" | 44 | value = $to_lua(value)\gsub "^return ", "" |
45 | "local #{name} = #{value}" | 45 | "local #{name} = #{value}" |
46 | { | 46 | { |
47 | :codes | 47 | :code |
48 | type: "text" | 48 | type: "text" |
49 | locals: {name} | 49 | locals: {name} |
50 | } | 50 | } |
51 | 51 | ||
52 | export macro record = (name, decl)-> | 52 | export macro record = (name, decl)-> |
53 | import "yue" as {options:{:tl_enabled}} | 53 | import "yue" as {options:{:tl_enabled}} |
54 | codes = if tl_enabled | 54 | code = if tl_enabled |
55 | "local record #{name} | 55 | "local record #{name} |
56 | #{decl} | 56 | #{decl} |
57 | end" | 57 | end" |
58 | else | 58 | else |
59 | "local #{name} = {}" | 59 | "local #{name} = {}" |
60 | { | 60 | { |
61 | :codes | 61 | :code |
62 | type: "text" | 62 | type: "text" |
63 | locals: {name} | 63 | locals: {name} |
64 | } | 64 | } |
@@ -74,14 +74,14 @@ export macro method = (decl, value)-> | |||
74 | _, node = tl.parse_program tokens,{},"macro-function" | 74 | _, node = tl.parse_program tokens,{},"macro-function" |
75 | args = table.concat [arg.tk for arg in *node[1].args],", " | 75 | args = table.concat [arg.tk for arg in *node[1].args],", " |
76 | value = "(#{args})->#{value\match "[%-=]>(.*)"}" | 76 | value = "(#{args})->#{value\match "[%-=]>(.*)"}" |
77 | codes = if tl_enabled | 77 | code = if tl_enabled |
78 | value = $to_lua(value)\match "^return function%(.-%)\n(.*)end" | 78 | value = $to_lua(value)\match "^return function%(.-%)\n(.*)end" |
79 | "function #{tab}#{sym}#{func}#{type}\n#{value}\nend" | 79 | "function #{tab}#{sym}#{func}#{type}\n#{value}\nend" |
80 | else | 80 | else |
81 | value = $to_lua(value)\gsub "^return ", "" | 81 | value = $to_lua(value)\gsub "^return ", "" |
82 | "#{tab}.#{func} = #{value}" | 82 | "#{tab}.#{func} = #{value}" |
83 | { | 83 | { |
84 | :codes | 84 | :code |
85 | type: "text" | 85 | type: "text" |
86 | } | 86 | } |
87 | 87 | ||
diff --git a/spec/inputs/macro.yue b/spec/inputs/macro.yue index 2dd15ac..366a3d9 100644 --- a/spec/inputs/macro.yue +++ b/spec/inputs/macro.yue | |||
@@ -69,9 +69,9 @@ $foreach $filter($map({1,2,3}, _ * 2), _ > 4), print _ | |||
69 | 69 | ||
70 | val = $pipe( | 70 | val = $pipe( |
71 | {1, 2, 3} | 71 | {1, 2, 3} |
72 | $map(_ * 2) | 72 | [[$map(_ * 2)]] |
73 | $filter(_ > 4) | 73 | [[$filter(_ > 4)]] |
74 | $reduce(0, _1 + _2) | 74 | [[$reduce(0, _1 + _2)]] |
75 | ) | 75 | ) |
76 | 76 | ||
77 | macro plus = (a, b)-> "#{a} + #{b}" | 77 | macro plus = (a, b)-> "#{a} + #{b}" |
@@ -110,8 +110,8 @@ do | |||
110 | a += $get_inner_hygienic! | 110 | a += $get_inner_hygienic! |
111 | print a | 111 | print a |
112 | 112 | ||
113 | macro lua = (codes)-> { | 113 | macro lua = (code)-> { |
114 | :codes | 114 | :code |
115 | type: "lua" | 115 | type: "lua" |
116 | } | 116 | } |
117 | 117 | ||
@@ -136,7 +136,7 @@ macro def = (fname, ...)-> | |||
136 | args = {...} | 136 | args = {...} |
137 | last = table.remove args | 137 | last = table.remove args |
138 | { | 138 | { |
139 | codes: $showMacro "def", "local function #{fname}(#{table.concat args, ', '}) | 139 | code: $showMacro "def", "local function #{fname}(#{table.concat args, ', '}) |
140 | #{last} | 140 | #{last} |
141 | end" | 141 | end" |
142 | type: "lua" | 142 | type: "lua" |
@@ -155,7 +155,7 @@ $def sel, a, b, c, [[ | |||
155 | $def dummy,[[]] | 155 | $def dummy,[[]] |
156 | 156 | ||
157 | macro insertComment = (text)-> { | 157 | macro insertComment = (text)-> { |
158 | codes: "-- #{text\match '[\'"](.*)[\'"]'}" | 158 | code: "-- #{text\match '[\'"](.*)[\'"]'}" |
159 | type: "lua" | 159 | type: "lua" |
160 | } | 160 | } |
161 | 161 | ||
@@ -239,7 +239,7 @@ macro chainC = (...)-> | |||
239 | else | 239 | else |
240 | callable = itemCodes | 240 | callable = itemCodes |
241 | { | 241 | { |
242 | codes: $showMacro "chainC", callable | 242 | code: $showMacro "chainC", callable |
243 | type: "lua" | 243 | type: "lua" |
244 | } | 244 | } |
245 | 245 | ||
@@ -253,7 +253,27 @@ $chainC( | |||
253 | Destroy! | 253 | Destroy! |
254 | ) | 254 | ) |
255 | 255 | ||
256 | macro tb = -> "{'abc', a:123, call#:=> 998}" | ||
257 | print $tb[1], $tb.a, ($tb)!, $tb! | ||
258 | |||
259 | print "current line: #{ $LINE }" | ||
260 | |||
261 | macro todoInner = (module, line, msg)-> | ||
262 | print "TODO#{msg and ': ' .. msg or ''} in file #{module}, at line #{line}" | ||
263 | { | ||
264 | code: "-- TODO#{msg and ': ' .. msg or ''}" | ||
265 | type: "lua" | ||
266 | } | ||
267 | |||
268 | macro todo = (msg)-> | ||
269 | if msg | ||
270 | "$todoInner $MODULE, $LINE, #{msg}" | ||
271 | else | ||
272 | "$todoInner $MODULE, $LINE" | ||
273 | |||
274 | $todo | ||
275 | |||
256 | macro implicitReturnMacroIsAllowed = -> "print 'abc'\n123" | 276 | macro implicitReturnMacroIsAllowed = -> "print 'abc'\n123" |
257 | 277 | ||
258 | $implicitReturnMacroIsAllowed! | 278 | $implicitReturnMacroIsAllowed |
259 | 279 | ||
diff --git a/spec/outputs/macro.lua b/spec/outputs/macro.lua index a2430a2..7812182 100644 --- a/spec/outputs/macro.lua +++ b/spec/outputs/macro.lua | |||
@@ -229,5 +229,36 @@ end | |||
229 | origin.transform.root.gameObject:Parents():Descendants():SelectEnable():SelectVisible():TagEqual("fx"):Where(function(x) | 229 | origin.transform.root.gameObject:Parents():Descendants():SelectEnable():SelectVisible():TagEqual("fx"):Where(function(x) |
230 | return x.name:EndsWith("(Clone)") | 230 | return x.name:EndsWith("(Clone)") |
231 | end):Destroy() | 231 | end):Destroy() |
232 | print((setmetatable({ | ||
233 | 'abc', | ||
234 | a = 123, | ||
235 | }, { | ||
236 | __call = function(self) | ||
237 | return 998 | ||
238 | end | ||
239 | }))[1], (setmetatable({ | ||
240 | 'abc', | ||
241 | a = 123, | ||
242 | }, { | ||
243 | __call = function(self) | ||
244 | return 998 | ||
245 | end | ||
246 | })).a, (setmetatable({ | ||
247 | 'abc', | ||
248 | a = 123, | ||
249 | }, { | ||
250 | __call = function(self) | ||
251 | return 998 | ||
252 | end | ||
253 | }))(), setmetatable({ | ||
254 | 'abc', | ||
255 | a = 123, | ||
256 | }, { | ||
257 | __call = function(self) | ||
258 | return 998 | ||
259 | end | ||
260 | })) | ||
261 | print("current line: " .. tostring(259)) | ||
262 | -- TODO | ||
232 | print('abc') | 263 | print('abc') |
233 | return 123 | 264 | return 123 |
diff --git a/src/yue.cpp b/src/yue.cpp index b04bd92..1704b57 100644 --- a/src/yue.cpp +++ b/src/yue.cpp | |||
@@ -429,9 +429,11 @@ int main(int narg, const char** args) { | |||
429 | std::string s( | 429 | std::string s( |
430 | (std::istreambuf_iterator<char>(input)), | 430 | (std::istreambuf_iterator<char>(input)), |
431 | std::istreambuf_iterator<char>()); | 431 | std::istreambuf_iterator<char>()); |
432 | auto conf = config; | ||
433 | conf.module = file.first; | ||
432 | if (dumpCompileTime) { | 434 | if (dumpCompileTime) { |
433 | auto start = std::chrono::high_resolution_clock::now(); | 435 | auto start = std::chrono::high_resolution_clock::now(); |
434 | auto result = yue::YueCompiler{YUE_ARGS}.compile(s, config); | 436 | auto result = yue::YueCompiler{YUE_ARGS}.compile(s, conf); |
435 | auto end = std::chrono::high_resolution_clock::now(); | 437 | auto end = std::chrono::high_resolution_clock::now(); |
436 | if (!result.codes.empty()) { | 438 | if (!result.codes.empty()) { |
437 | std::chrono::duration<double> diff = end - start; | 439 | std::chrono::duration<double> diff = end - start; |
@@ -451,7 +453,7 @@ int main(int narg, const char** args) { | |||
451 | return std::tuple{1, file.first, buf.str()}; | 453 | return std::tuple{1, file.first, buf.str()}; |
452 | } | 454 | } |
453 | } | 455 | } |
454 | auto result = yue::YueCompiler{YUE_ARGS}.compile(s, config); | 456 | auto result = yue::YueCompiler{YUE_ARGS}.compile(s, conf); |
455 | if (result.error.empty()) { | 457 | if (result.error.empty()) { |
456 | if (!writeToFile) { | 458 | if (!writeToFile) { |
457 | return std::tuple{0, file.first, result.codes + '\n'}; | 459 | return std::tuple{0, file.first, result.codes + '\n'}; |
diff --git a/src/yuescript/stacktraceplus.h b/src/yuescript/stacktraceplus.h index ac61ba7..83460ef 100644 --- a/src/yuescript/stacktraceplus.h +++ b/src/yuescript/stacktraceplus.h | |||
@@ -335,7 +335,7 @@ local function getYueLineNumber(fname, line) | |||
335 | end | 335 | end |
336 | if file_exist then | 336 | if file_exist then |
337 | local codes = yue.read_file(file_path) | 337 | local codes = yue.read_file(file_path) |
338 | local yueFile = codes:match("^%s*--%s*%[yue%]:%s*([^\n]*)") | 338 | local yueFile = codes:match("^%s*--%s*%[.*%]:%s*([^\n]*)") |
339 | if yueFile then | 339 | if yueFile then |
340 | fname = yueFile:gsub("^%s*(.-)%s*$", "%1") | 340 | fname = yueFile:gsub("^%s*(.-)%s*$", "%1") |
341 | source = codes | 341 | source = codes |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index e004821..14e33a5 100755 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -60,7 +60,7 @@ using namespace parserlib; | |||
60 | 60 | ||
61 | typedef std::list<std::string> str_list; | 61 | typedef std::list<std::string> str_list; |
62 | 62 | ||
63 | const std::string_view version = "0.8.5"sv; | 63 | const std::string_view version = "0.9.0"sv; |
64 | const std::string_view extension = "yue"sv; | 64 | const std::string_view extension = "yue"sv; |
65 | 65 | ||
66 | class YueCompilerImpl { | 66 | class YueCompilerImpl { |
@@ -68,11 +68,9 @@ public: | |||
68 | #ifndef YUE_NO_MACRO | 68 | #ifndef YUE_NO_MACRO |
69 | YueCompilerImpl(lua_State* sharedState, | 69 | YueCompilerImpl(lua_State* sharedState, |
70 | const std::function<void(void*)>& luaOpen, | 70 | const std::function<void(void*)>& luaOpen, |
71 | bool sameModule, | 71 | bool sameModule): |
72 | std::string_view moduleName = {}): | ||
73 | L(sharedState), | 72 | L(sharedState), |
74 | _luaOpen(luaOpen), | 73 | _luaOpen(luaOpen) { |
75 | _moduleName(moduleName) { | ||
76 | BLOCK_START | 74 | BLOCK_START |
77 | BREAK_IF(!sameModule); | 75 | BREAK_IF(!sameModule); |
78 | BREAK_IF(!L); | 76 | BREAK_IF(!L); |
@@ -210,7 +208,6 @@ private: | |||
210 | std::ostringstream _buf; | 208 | std::ostringstream _buf; |
211 | std::ostringstream _joinBuf; | 209 | std::ostringstream _joinBuf; |
212 | const std::string _newLine = "\n"; | 210 | const std::string _newLine = "\n"; |
213 | std::string _moduleName; | ||
214 | 211 | ||
215 | enum class LocalMode { | 212 | enum class LocalMode { |
216 | None = 0, | 213 | None = 0, |
@@ -863,16 +860,10 @@ private: | |||
863 | 860 | ||
864 | bool isMacroChain(ChainValue_t* chainValue) const { | 861 | bool isMacroChain(ChainValue_t* chainValue) const { |
865 | const auto& chainList = chainValue->items.objects(); | 862 | const auto& chainList = chainValue->items.objects(); |
866 | BLOCK_START | ||
867 | auto callable = ast_cast<Callable_t>(chainList.front()); | 863 | auto callable = ast_cast<Callable_t>(chainList.front()); |
868 | BREAK_IF(!callable); | 864 | if (callable && callable->item.is<MacroName_t>()) { |
869 | BREAK_IF(!callable->item.is<MacroName_t>()); | 865 | return true; |
870 | if (chainList.size() == 1 || | ||
871 | !ast_is<Invoke_t,InvokeArgs_t>(*(++chainList.begin()))) { | ||
872 | throw std::logic_error(_info.errorMessage("macro expression must be followed by arguments list"sv, callable)); | ||
873 | } | 866 | } |
874 | return true; | ||
875 | BLOCK_END | ||
876 | return false; | 867 | return false; |
877 | } | 868 | } |
878 | 869 | ||
@@ -1052,7 +1043,7 @@ private: | |||
1052 | } | 1043 | } |
1053 | } | 1044 | } |
1054 | if (auto chainValue = singleValue->item.as<ChainValue_t>()) { | 1045 | if (auto chainValue = singleValue->item.as<ChainValue_t>()) { |
1055 | if (isChainValueCall(chainValue)) { | 1046 | if (isChainValueCall(chainValue) || isMacroChain(chainValue)) { |
1056 | transformChainValue(chainValue, out, ExpUsage::Common); | 1047 | transformChainValue(chainValue, out, ExpUsage::Common); |
1057 | break; | 1048 | break; |
1058 | } | 1049 | } |
@@ -3139,8 +3130,8 @@ private: | |||
3139 | throw std::logic_error(_info.errorMessage("failed to generate macro function\n"s + err, macro->macroLit)); | 3130 | throw std::logic_error(_info.errorMessage("failed to generate macro function\n"s + err, macro->macroLit)); |
3140 | } // cur true macro | 3131 | } // cur true macro |
3141 | lua_remove(L, -2); // cur macro | 3132 | lua_remove(L, -2); // cur macro |
3142 | if (exporting && !_moduleName.empty()) { | 3133 | if (exporting && _config.exporting && !_config.module.empty()) { |
3143 | pushModuleTable(_moduleName); // cur macro module | 3134 | pushModuleTable(_config.module); // cur macro module |
3144 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name | 3135 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name |
3145 | lua_pushvalue(L, -3); // cur macro module name macro | 3136 | lua_pushvalue(L, -3); // cur macro module name macro |
3146 | lua_rawset(L, -3); // cur macro module | 3137 | lua_rawset(L, -3); // cur macro module |
@@ -3929,11 +3920,23 @@ private: | |||
3929 | } | 3920 | } |
3930 | 3921 | ||
3931 | #ifndef YUE_NO_MACRO | 3922 | #ifndef YUE_NO_MACRO |
3923 | std::string expandBuiltinMacro(const std::string& name, ast_node* x) { | ||
3924 | if (name == "LINE"sv) { | ||
3925 | return std::to_string(x->m_begin.m_line + _config.lineOffset); | ||
3926 | } | ||
3927 | if (name == "MODULE"sv) { | ||
3928 | return _config.module.empty() ? "\"yuescript\""s : '"' + _config.module + '"'; | ||
3929 | } | ||
3930 | return Empty; | ||
3931 | } | ||
3932 | |||
3932 | std::tuple<std::string,std::string,str_list> expandMacroStr(ChainValue_t* chainValue) { | 3933 | std::tuple<std::string,std::string,str_list> expandMacroStr(ChainValue_t* chainValue) { |
3933 | const auto& chainList = chainValue->items.objects(); | 3934 | const auto& chainList = chainValue->items.objects(); |
3934 | auto x = ast_to<Callable_t>(chainList.front())->item.to<MacroName_t>(); | 3935 | auto x = ast_to<Callable_t>(chainList.front())->item.to<MacroName_t>(); |
3935 | auto macroName = x->name ? _parser.toString(x->name) : Empty; | 3936 | auto macroName = x->name ? _parser.toString(x->name) : Empty; |
3936 | if (!macroName.empty() && !_useModule) { | 3937 | if (!macroName.empty() && !_useModule) { |
3938 | auto code = expandBuiltinMacro(macroName, x); | ||
3939 | if (!code.empty()) return {Empty, code, {}}; | ||
3937 | throw std::logic_error(_info.errorMessage("can not resolve macro"sv, x)); | 3940 | throw std::logic_error(_info.errorMessage("can not resolve macro"sv, x)); |
3938 | } | 3941 | } |
3939 | pushCurrentModule(); // cur | 3942 | pushCurrentModule(); // cur |
@@ -3941,8 +3944,8 @@ private: | |||
3941 | DEFER(lua_settop(L, top)); | 3944 | DEFER(lua_settop(L, top)); |
3942 | if (macroName.empty()) { | 3945 | if (macroName.empty()) { |
3943 | lua_pop(L, 1); // empty | 3946 | lua_pop(L, 1); // empty |
3944 | auto item = *(++chainList.begin()); | ||
3945 | const node_container* args = nullptr; | 3947 | const node_container* args = nullptr; |
3948 | auto item = *(++chainList.begin()); | ||
3946 | if (auto invoke = ast_cast<Invoke_t>(item)) { | 3949 | if (auto invoke = ast_cast<Invoke_t>(item)) { |
3947 | args = &invoke->args.objects(); | 3950 | args = &invoke->args.objects(); |
3948 | } else { | 3951 | } else { |
@@ -3993,60 +3996,69 @@ private: | |||
3993 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macroName | 3996 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macroName |
3994 | lua_rawget(L, -2); // cur[macroName], cur macroFunc | 3997 | lua_rawget(L, -2); // cur[macroName], cur macroFunc |
3995 | if (lua_isfunction(L, -1) == 0) { | 3998 | if (lua_isfunction(L, -1) == 0) { |
3999 | auto code = expandBuiltinMacro(macroName, x); | ||
4000 | if (!code.empty()) return {Empty, code, {}}; | ||
3996 | throw std::logic_error(_info.errorMessage("can not resolve macro"sv, x)); | 4001 | throw std::logic_error(_info.errorMessage("can not resolve macro"sv, x)); |
3997 | } // cur macroFunc | 4002 | } // cur macroFunc |
3998 | pushYue("pcall"sv); // cur macroFunc pcall | 4003 | pushYue("pcall"sv); // cur macroFunc pcall |
3999 | lua_insert(L, -2); // cur pcall macroFunc | 4004 | lua_insert(L, -2); // cur pcall macroFunc |
4000 | auto item = *(++chainList.begin()); | ||
4001 | const node_container* args = nullptr; | 4005 | const node_container* args = nullptr; |
4002 | if (auto invoke = ast_cast<Invoke_t>(item)) { | 4006 | if (chainList.size() > 1) { |
4003 | args = &invoke->args.objects(); | 4007 | auto item = *(++chainList.begin()); |
4004 | } else { | 4008 | if (auto invoke = ast_cast<Invoke_t>(item)) { |
4005 | args = &ast_to<InvokeArgs_t>(item)->args.objects(); | 4009 | args = &invoke->args.objects(); |
4006 | } | 4010 | } else if (auto invoke = ast_cast<InvokeArgs_t>(item)){ |
4007 | for (auto arg : *args) { | 4011 | args = &invoke->args.objects(); |
4008 | std::string str; | 4012 | } |
4009 | // check whether arg is reassembled | 4013 | } |
4010 | // do some workaround for pipe expression | 4014 | if (args) { |
4011 | if (ast_is<Exp_t>(arg) && arg->m_begin.m_it == arg->m_end.m_it) { | 4015 | for (auto arg : *args) { |
4012 | auto exp = static_cast<Exp_t*>(arg); | 4016 | std::string str; |
4013 | BLOCK_START | 4017 | bool rawString = false; |
4014 | BREAK_IF(!exp->opValues.empty()); | 4018 | if (auto lstr = ast_cast<LuaString_t>(arg)) { |
4015 | auto chainValue = exp->getByPath<unary_exp_t, Value_t, ChainValue_t>(); | 4019 | str = _parser.toString(lstr->content); |
4016 | BREAK_IF(!chainValue); | 4020 | rawString = true; |
4017 | BREAK_IF(!isMacroChain(chainValue)); | 4021 | } else { |
4018 | BREAK_IF(chainValue->items.size() != 2); | 4022 | BLOCK_START |
4019 | str = std::get<1>(expandMacroStr(chainValue)); | 4023 | auto exp = ast_cast<Exp_t>(arg); |
4020 | BLOCK_END | 4024 | BREAK_IF(!exp); |
4021 | if (str.empty()) { | 4025 | auto value = singleValueFrom(exp); |
4022 | // exp is reassembled due to pipe expressions | 4026 | BREAK_IF(!value); |
4023 | // in transform stage, toString(exp) won't be able | 4027 | auto lstr = value->getByPath<String_t, LuaString_t>(); |
4024 | // to convert its whole text content | 4028 | BREAK_IF(!lstr); |
4025 | str = _parser.toString(exp->pipeExprs.front()); | 4029 | str = _parser.toString(lstr->content); |
4026 | } | 4030 | rawString = true; |
4027 | } else if (auto lstr = ast_cast<LuaString_t>(arg)) { | 4031 | BLOCK_END |
4028 | str = _parser.toString(lstr->content); | 4032 | } |
4029 | } else { | 4033 | if (!rawString && str.empty()) { |
4030 | bool multiLineStr = false; | 4034 | // check whether arg is reassembled |
4031 | BLOCK_START | 4035 | // do some workaround for pipe expression |
4032 | auto exp = ast_cast<Exp_t>(arg); | 4036 | if (ast_is<Exp_t>(arg)) { |
4033 | BREAK_IF(!exp); | 4037 | auto exp = static_cast<Exp_t*>(arg); |
4034 | auto value = singleValueFrom(exp); | 4038 | BLOCK_START |
4035 | BREAK_IF(!value); | 4039 | BREAK_IF(!exp->opValues.empty()); |
4036 | auto lstr = value->getByPath<String_t, LuaString_t>(); | 4040 | auto chainValue = exp->getByPath<unary_exp_t, Value_t, ChainValue_t>(); |
4037 | BREAK_IF(!lstr); | 4041 | BREAK_IF(!chainValue); |
4038 | str = _parser.toString(lstr->content); | 4042 | BREAK_IF(!isMacroChain(chainValue)); |
4039 | multiLineStr = true; | 4043 | str = std::get<1>(expandMacroStr(chainValue)); |
4040 | BLOCK_END | 4044 | BLOCK_END |
4041 | if (!multiLineStr) { | 4045 | if (str.empty() && arg->m_begin.m_it == arg->m_end.m_it) { |
4046 | // exp is reassembled due to pipe expressions | ||
4047 | // in transform stage, toString(exp) won't be able | ||
4048 | // to convert its whole text content | ||
4049 | str = _parser.toString(exp->pipeExprs.front()); | ||
4050 | } | ||
4051 | } | ||
4052 | } | ||
4053 | if (!rawString && str.empty()) { | ||
4042 | str = _parser.toString(arg); | 4054 | str = _parser.toString(arg); |
4043 | } | 4055 | } |
4044 | } | 4056 | Utils::trim(str); |
4045 | Utils::trim(str); | 4057 | Utils::replace(str, "\r\n"sv, "\n"sv); |
4046 | Utils::replace(str, "\r\n"sv, "\n"sv); | 4058 | lua_pushlstring(L, str.c_str(), str.size()); |
4047 | lua_pushlstring(L, str.c_str(), str.size()); | 4059 | } // cur pcall macroFunc args... |
4048 | } // cur pcall macroFunc args... | 4060 | } |
4049 | bool success = lua_pcall(L, static_cast<int>(args->size()) + 1, 2, 0) == 0; | 4061 | bool success = lua_pcall(L, (args ? static_cast<int>(args->size()) : 0) + 1, 2, 0) == 0; |
4050 | if (!success) { // cur err | 4062 | if (!success) { // cur err |
4051 | std::string err = lua_tostring(L, -1); | 4063 | std::string err = lua_tostring(L, -1); |
4052 | throw std::logic_error(_info.errorMessage("failed to expand macro: "s + err, x)); | 4064 | throw std::logic_error(_info.errorMessage("failed to expand macro: "s + err, x)); |
@@ -4063,11 +4075,11 @@ private: | |||
4063 | std::string type; | 4075 | std::string type; |
4064 | str_list localVars; | 4076 | str_list localVars; |
4065 | if (lua_istable(L, -1) != 0) { | 4077 | if (lua_istable(L, -1) != 0) { |
4066 | lua_getfield(L, -1, "codes"); // cur res codes | 4078 | lua_getfield(L, -1, "code"); // cur res code |
4067 | if (lua_isstring(L, -1) != 0) { | 4079 | if (lua_isstring(L, -1) != 0) { |
4068 | codes = lua_tostring(L, -1); | 4080 | codes = lua_tostring(L, -1); |
4069 | } else { | 4081 | } else { |
4070 | throw std::logic_error(_info.errorMessage("macro table must contain field \"codes\" of string"sv, x)); | 4082 | throw std::logic_error(_info.errorMessage("macro table must contain field \"code\" of string"sv, x)); |
4071 | } | 4083 | } |
4072 | lua_pop(L, 1); // cur res | 4084 | lua_pop(L, 1); // cur res |
4073 | lua_getfield(L, -1, "type"); // cur res type | 4085 | lua_getfield(L, -1, "type"); // cur res type |
@@ -4108,7 +4120,7 @@ private: | |||
4108 | std::string type, codes; | 4120 | std::string type, codes; |
4109 | str_list localVars; | 4121 | str_list localVars; |
4110 | std::tie(type, codes, localVars) = expandMacroStr(chainValue); | 4122 | std::tie(type, codes, localVars) = expandMacroStr(chainValue); |
4111 | bool isBlock = (usage == ExpUsage::Common) && (chainList.size() <= 2); | 4123 | bool isBlock = (usage == ExpUsage::Common) && (chainList.size() < 2 || (chainList.size() == 2 && ast_is<Invoke_t, InvokeArgs_t>(chainList.back()))); |
4112 | ParseInfo info; | 4124 | ParseInfo info; |
4113 | if (type == "lua"sv) { | 4125 | if (type == "lua"sv) { |
4114 | if (!isBlock) { | 4126 | if (!isBlock) { |
@@ -4161,7 +4173,7 @@ private: | |||
4161 | if (!isBlock) { | 4173 | if (!isBlock) { |
4162 | ast_ptr<false, Exp_t> exp; | 4174 | ast_ptr<false, Exp_t> exp; |
4163 | exp.set(info.node); | 4175 | exp.set(info.node); |
4164 | if (!exp->opValues.empty() || chainList.size() > 2) { | 4176 | if (!exp->opValues.empty() || (chainList.size() > 2 || (chainList.size() == 2 && !ast_is<Invoke_t, InvokeArgs_t>(chainList.back())))) { |
4165 | auto paren = x->new_ptr<Parens_t>(); | 4177 | auto paren = x->new_ptr<Parens_t>(); |
4166 | paren->expr.set(exp); | 4178 | paren->expr.set(exp); |
4167 | auto callable = x->new_ptr<Callable_t>(); | 4179 | auto callable = x->new_ptr<Callable_t>(); |
@@ -4169,7 +4181,8 @@ private: | |||
4169 | auto newChain = x->new_ptr<ChainValue_t>(); | 4181 | auto newChain = x->new_ptr<ChainValue_t>(); |
4170 | newChain->items.push_back(callable); | 4182 | newChain->items.push_back(callable); |
4171 | auto it = chainList.begin(); | 4183 | auto it = chainList.begin(); |
4172 | it++; it++; | 4184 | it++; |
4185 | if (chainList.size() > 1 && ast_is<Invoke_t, InvokeArgs_t>(*it)) it++; | ||
4173 | for (; it != chainList.end(); ++it) { | 4186 | for (; it != chainList.end(); ++it) { |
4174 | newChain->items.push_back(*it); | 4187 | newChain->items.push_back(*it); |
4175 | } | 4188 | } |
@@ -6146,12 +6159,14 @@ private: | |||
6146 | throw std::logic_error(_info.errorMessage("failed to get module text"sv, x)); | 6159 | throw std::logic_error(_info.errorMessage("failed to get module text"sv, x)); |
6147 | } // cur text | 6160 | } // cur text |
6148 | std::string text = lua_tostring(L, -1); | 6161 | std::string text = lua_tostring(L, -1); |
6149 | auto compiler = YueCompilerImpl(L, _luaOpen, false, moduleFullName); | 6162 | auto compiler = YueCompilerImpl(L, _luaOpen, false); |
6150 | YueConfig config; | 6163 | YueConfig config; |
6151 | config.lineOffset = 0; | 6164 | config.lineOffset = 0; |
6152 | config.lintGlobalVariable = false; | 6165 | config.lintGlobalVariable = false; |
6153 | config.reserveLineNumber = false; | 6166 | config.reserveLineNumber = false; |
6154 | config.implicitReturnRoot = _config.implicitReturnRoot; | 6167 | config.implicitReturnRoot = _config.implicitReturnRoot; |
6168 | config.module = moduleFullName; | ||
6169 | config.exporting = true; | ||
6155 | auto result = compiler.compile(text, config); | 6170 | auto result = compiler.compile(text, config); |
6156 | if (result.codes.empty() && !result.error.empty()) { | 6171 | if (result.codes.empty() && !result.error.empty()) { |
6157 | throw std::logic_error(_info.errorMessage("failed to compile module '"s + moduleName + "\': "s + result.error, x)); | 6172 | throw std::logic_error(_info.errorMessage("failed to compile module '"s + moduleName + "\': "s + result.error, x)); |
diff --git a/src/yuescript/yue_compiler.h b/src/yuescript/yue_compiler.h index 2e8c86a..f15bcfb 100644 --- a/src/yuescript/yue_compiler.h +++ b/src/yuescript/yue_compiler.h | |||
@@ -28,7 +28,9 @@ struct YueConfig { | |||
28 | bool implicitReturnRoot = true; | 28 | bool implicitReturnRoot = true; |
29 | bool reserveLineNumber = true; | 29 | bool reserveLineNumber = true; |
30 | bool useSpaceOverTab = false; | 30 | bool useSpaceOverTab = false; |
31 | bool exporting = false; | ||
31 | int lineOffset = 0; | 32 | int lineOffset = 0; |
33 | std::string module; | ||
32 | Options options; | 34 | Options options; |
33 | }; | 35 | }; |
34 | 36 | ||
diff --git a/src/yuescript/yuescript.cpp b/src/yuescript/yuescript.cpp index d534f3e..b83a454 100644 --- a/src/yuescript/yuescript.cpp +++ b/src/yuescript/yuescript.cpp | |||
@@ -85,6 +85,12 @@ static int yuetolua(lua_State* L) { | |||
85 | config.lineOffset = static_cast<int>(lua_tonumber(L, -1)); | 85 | config.lineOffset = static_cast<int>(lua_tonumber(L, -1)); |
86 | } | 86 | } |
87 | lua_pop(L, 1); | 87 | lua_pop(L, 1); |
88 | lua_pushliteral(L, "module"); | ||
89 | lua_gettable(L, -2); | ||
90 | if (lua_isstring(L, -1) != 0) { | ||
91 | config.module = lua_tostring(L, -1); | ||
92 | } | ||
93 | lua_pop(L, 1); | ||
88 | } | 94 | } |
89 | std::string s(input, size); | 95 | std::string s(input, size); |
90 | auto result = yue::YueCompiler(L, nullptr, sameModule).compile(s, config); | 96 | auto result = yue::YueCompiler(L, nullptr, sameModule).compile(s, config); |
diff --git a/src/yuescript/yuescript.h b/src/yuescript/yuescript.h index 4428fbe..eac95da 100644 --- a/src/yuescript/yuescript.h +++ b/src/yuescript/yuescript.h | |||
@@ -103,6 +103,7 @@ end | |||
103 | yue_loadstring = function(...) | 103 | yue_loadstring = function(...) |
104 | local options, str, chunk_name, mode, env = get_options(...) | 104 | local options, str, chunk_name, mode, env = get_options(...) |
105 | chunk_name = chunk_name or "=(yuescript.loadstring)" | 105 | chunk_name = chunk_name or "=(yuescript.loadstring)" |
106 | options.module = chunk_name | ||
106 | local code, err = yue.to_lua(str, options) | 107 | local code, err = yue.to_lua(str, options) |
107 | if not code then | 108 | if not code then |
108 | return nil, err | 109 | return nil, err |
@@ -117,7 +118,7 @@ yue_loadstring = function(...) | |||
117 | end | 118 | end |
118 | local function yue_loadfile(fname, ...) | 119 | local function yue_loadfile(fname, ...) |
119 | local text = yue.read_file(fname) | 120 | local text = yue.read_file(fname) |
120 | return yue_loadstring(text, tostring(fname), ...) | 121 | return yue_loadstring(text, fname, ...) |
121 | end | 122 | end |
122 | local function yue_dofile(...) | 123 | local function yue_dofile(...) |
123 | local f = assert(yue_loadfile(...)) | 124 | local f = assert(yue_loadfile(...)) |