aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2022-02-08 16:39:20 +0800
committerLi Jin <dragon-fly@qq.com>2022-02-08 16:39:20 +0800
commita6744ed09b49b740dfc2852d655f5ed6dd471cbf (patch)
tree4209b5f16c67f79259ad4c6bf116a8428b589ad3
parentd22ae154b57ac80107020e98f04f76fffaa9cd90 (diff)
downloadyuescript-a6744ed09b49b740dfc2852d655f5ed6dd471cbf.tar.gz
yuescript-a6744ed09b49b740dfc2852d655f5ed6dd471cbf.tar.bz2
yuescript-a6744ed09b49b740dfc2852d655f5ed6dd471cbf.zip
fix a case combining the use of existential op and metatable op. raise error when use existential op in the left part in an assignment.
-rw-r--r--spec/inputs/existential.yue7
-rw-r--r--spec/outputs/existential.lua28
-rwxr-xr-xsrc/yuescript/yue_compiler.cpp90
3 files changed, 78 insertions, 47 deletions
diff --git a/spec/inputs/existential.yue b/spec/inputs/existential.yue
index 3055705..101e1d8 100644
--- a/spec/inputs/existential.yue
+++ b/spec/inputs/existential.yue
@@ -49,3 +49,10 @@ with? io.open "test.txt", "w"
49 \write "hello" 49 \write "hello"
50 \close! 50 \close!
51 51
52tb?.a#? 123
53
54with? tb.#?.index#
55 .a = 1
56
57nil
58
diff --git a/spec/outputs/existential.lua b/spec/outputs/existential.lua
index 4a64c49..b594218 100644
--- a/spec/outputs/existential.lua
+++ b/spec/outputs/existential.lua
@@ -148,9 +148,27 @@ end)() ~= nil) or (function()
148 end 148 end
149 return nil 149 return nil
150end)() 150end)()
151local _with_0 = io.open("test.txt", "w") 151do
152if _with_0 ~= nil then 152 local _with_0 = io.open("test.txt", "w")
153 _with_0:write("hello") 153 if _with_0 ~= nil then
154 _with_0:close() 154 _with_0:write("hello")
155 _with_0:close()
156 end
157end
158if tb ~= nil then
159 local _obj_1 = getmetatable(tb).__a
160 if _obj_1 ~= nil then
161 _obj_1(123)
162 end
163end
164do
165 local _with_0
166 local _obj_1 = getmetatable(tb)
167 if _obj_1 ~= nil then
168 _with_0 = getmetatable(_obj_1).__index
169 end
170 if _with_0 ~= nil then
171 _with_0.a = 1
172 end
155end 173end
156return _with_0 174return nil
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 2da72da..17822c6 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.9.6"sv; 63const std::string_view version = "0.9.7"sv;
64const std::string_view extension = "yue"sv; 64const std::string_view extension = "yue"sv;
65 65
66class YueCompilerImpl { 66class YueCompilerImpl {
@@ -800,6 +800,11 @@ private:
800 return true; 800 return true;
801 } 801 }
802 } else { 802 } else {
803 if (std::find_if(chainItems.begin(), chainItems.end(), [](ast_node* node) {
804 return ast_is<existential_op_t>(node);
805 }) != chainItems.end()) {
806 return false;
807 }
803 auto lastItem = chainItems.back(); 808 auto lastItem = chainItems.back();
804 switch (lastItem->getId()) { 809 switch (lastItem->getId()) {
805 case id<DotChainItem_t>(): 810 case id<DotChainItem_t>():
@@ -1207,48 +1212,49 @@ private:
1207 BREAK_IF(!value); 1212 BREAK_IF(!value);
1208 auto chainValue = value->item.as<ChainValue_t>(); 1213 auto chainValue = value->item.as<ChainValue_t>();
1209 BREAK_IF(!chainValue); 1214 BREAK_IF(!chainValue);
1210 if (specialChainValue(chainValue) == ChainType::Metatable) { 1215 auto dot = ast_cast<DotChainItem_t>(chainValue->items.back());
1211 str_list args; 1216 BREAK_IF(!dot);
1212 chainValue->items.pop_back(); 1217 BREAK_IF(!dot->name.is<Metatable_t>());
1213 if (chainValue->items.empty()) { 1218 str_list args;
1214 if (_withVars.empty()) { 1219 chainValue->items.pop_back();
1215 throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x)); 1220 if (chainValue->items.empty()) {
1216 } else { 1221 if (_withVars.empty()) {
1217 args.push_back(_withVars.top()); 1222 throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x));
1218 }
1219 } else { 1223 } else {
1220 transformExp(static_cast<Exp_t*>(*it), args, ExpUsage::Closure); 1224 args.push_back(_withVars.top());
1221 } 1225 }
1222 if (vit != values.end()) transformAssignItem(*vit, args); 1226 } else {
1223 else args.push_back("nil"s); 1227 transformExp(static_cast<Exp_t*>(*it), args, ExpUsage::Closure);
1224 _buf << indent() << globalVar("setmetatable"sv, x) << '(' << join(args, ", "sv) << ')' << nll(x); 1228 }
1225 str_list temp; 1229 if (vit != values.end()) transformAssignItem(*vit, args);
1226 temp.push_back(clearBuf()); 1230 else args.push_back("nil"s);
1227 auto newExpList = x->new_ptr<ExpList_t>(); 1231 _buf << indent() << globalVar("setmetatable"sv, x) << '(' << join(args, ", "sv) << ')' << nll(x);
1228 auto newAssign = x->new_ptr<Assign_t>(); 1232 str_list temp;
1229 auto newAssignment = x->new_ptr<ExpListAssign_t>(); 1233 temp.push_back(clearBuf());
1230 newAssignment->expList.set(newExpList); 1234 auto newExpList = x->new_ptr<ExpList_t>();
1231 newAssignment->action.set(newAssign); 1235 auto newAssign = x->new_ptr<Assign_t>();
1232 for (auto exp : exprs) { 1236 auto newAssignment = x->new_ptr<ExpListAssign_t>();
1233 if (exp != *it) newExpList->exprs.push_back(exp); 1237 newAssignment->expList.set(newExpList);
1234 } 1238 newAssignment->action.set(newAssign);
1235 for (auto value : values) { 1239 for (auto exp : exprs) {
1236 if (value != *vit) newAssign->values.push_back(value); 1240 if (exp != *it) newExpList->exprs.push_back(exp);
1237 } 1241 }
1238 if (newExpList->exprs.empty() && newAssign->values.empty()) { 1242 for (auto value : values) {
1239 out.push_back(temp.back()); 1243 if (value != *vit) newAssign->values.push_back(value);
1240 return; 1244 }
1241 } 1245 if (newExpList->exprs.empty() && newAssign->values.empty()) {
1242 if (newExpList->exprs.size() < newAssign->values.size()) { 1246 out.push_back(temp.back());
1243 auto exp = toAst<Exp_t>("_"sv, x);
1244 while (newExpList->exprs.size() < newAssign->values.size()) {
1245 newExpList->exprs.push_back(exp);
1246 }
1247 }
1248 transformAssignment(newAssignment, temp);
1249 out.push_back(join(temp));
1250 return; 1247 return;
1251 } 1248 }
1249 if (newExpList->exprs.size() < newAssign->values.size()) {
1250 auto exp = toAst<Exp_t>("_"sv, x);
1251 while (newExpList->exprs.size() < newAssign->values.size()) {
1252 newExpList->exprs.push_back(exp);
1253 }
1254 }
1255 transformAssignment(newAssignment, temp);
1256 out.push_back(join(temp));
1257 return;
1252 BLOCK_END 1258 BLOCK_END
1253 if (vit != values.end()) ++vit; 1259 if (vit != values.end()) ++vit;
1254 } 1260 }
@@ -4287,15 +4293,15 @@ private:
4287#endif // YUE_NO_MACRO 4293#endif // YUE_NO_MACRO
4288 } 4294 }
4289 const auto& chainList = chainValue->items.objects(); 4295 const auto& chainList = chainValue->items.objects();
4290 if (transformChainWithMetatable(chainList, out, usage, assignList)) {
4291 return;
4292 }
4293 if (transformChainEndWithEOP(chainList, out, usage, assignList)) { 4296 if (transformChainEndWithEOP(chainList, out, usage, assignList)) {
4294 return; 4297 return;
4295 } 4298 }
4296 if (transformChainWithEOP(chainList, out, usage, assignList)) { 4299 if (transformChainWithEOP(chainList, out, usage, assignList)) {
4297 return; 4300 return;
4298 } 4301 }
4302 if (transformChainWithMetatable(chainList, out, usage, assignList)) {
4303 return;
4304 }
4299 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) { 4305 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) {
4300 return; 4306 return;
4301 } 4307 }