aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2021-11-19 13:23:11 +0800
committerLi Jin <dragon-fly@qq.com>2021-11-19 13:23:11 +0800
commit2ff18b4fb66d25d22e5a25fb386fe171853e0b06 (patch)
treed6e6f1671f74a4430b24869c74767aaf0ee2e128
parenta8e5aaf64969792741f3a094fe0070ddb5e3bc7d (diff)
downloadyuescript-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.yue20
-rw-r--r--spec/inputs/macro.yue38
-rw-r--r--spec/outputs/macro.lua31
-rw-r--r--src/yue.cpp6
-rw-r--r--src/yuescript/stacktraceplus.h2
-rwxr-xr-xsrc/yuescript/yue_compiler.cpp157
-rw-r--r--src/yuescript/yue_compiler.h2
-rw-r--r--src/yuescript/yuescript.cpp6
-rw-r--r--src/yuescript/yuescript.h3
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
7macro to_lua = (codes)-> 7macro 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
10macro trim = (name)-> 10macro 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
52export macro record = (name, decl)-> 52export 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}
57end" 57end"
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
70val = $pipe( 70val = $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
77macro plus = (a, b)-> "#{a} + #{b}" 77macro 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
113macro lua = (codes)-> { 113macro 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}
141end" 141end"
142 type: "lua" 142 type: "lua"
@@ -155,7 +155,7 @@ $def sel, a, b, c, [[
155$def dummy,[[]] 155$def dummy,[[]]
156 156
157macro insertComment = (text)-> { 157macro 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
256macro tb = -> "{'abc', a:123, call#:=> 998}"
257print $tb[1], $tb.a, ($tb)!, $tb!
258
259print "current line: #{ $LINE }"
260
261macro 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
268macro todo = (msg)->
269 if msg
270 "$todoInner $MODULE, $LINE, #{msg}"
271 else
272 "$todoInner $MODULE, $LINE"
273
274$todo
275
256macro implicitReturnMacroIsAllowed = -> "print 'abc'\n123" 276macro 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
229origin.transform.root.gameObject:Parents():Descendants():SelectEnable():SelectVisible():TagEqual("fx"):Where(function(x) 229origin.transform.root.gameObject:Parents():Descendants():SelectEnable():SelectVisible():TagEqual("fx"):Where(function(x)
230 return x.name:EndsWith("(Clone)") 230 return x.name:EndsWith("(Clone)")
231end):Destroy() 231end):Destroy()
232print((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}))
261print("current line: " .. tostring(259))
262-- TODO
232print('abc') 263print('abc')
233return 123 264return 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
61typedef std::list<std::string> str_list; 61typedef std::list<std::string> str_list;
62 62
63const std::string_view version = "0.8.5"sv; 63const std::string_view version = "0.9.0"sv;
64const std::string_view extension = "yue"sv; 64const std::string_view extension = "yue"sv;
65 65
66class YueCompilerImpl { 66class 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
103yue_loadstring = function(...) 103yue_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(...)
117end 118end
118local function yue_loadfile(fname, ...) 119local 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, ...)
121end 122end
122local function yue_dofile(...) 123local function yue_dofile(...)
123 local f = assert(yue_loadfile(...)) 124 local f = assert(yue_loadfile(...))