diff options
author | Li Jin <dragon-fly@qq.com> | 2021-04-27 15:31:12 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2021-04-27 15:31:12 +0800 |
commit | 956cacc11b6b3b45ba5bc914b8332d8a7c23be05 (patch) | |
tree | 322b7e61f1014726bb70f91280b978eed2d2d158 | |
parent | 705dfda89c7795f84419e176e3f861780fbd0fcb (diff) | |
download | yuescript-956cacc11b6b3b45ba5bc914b8332d8a7c23be05.tar.gz yuescript-956cacc11b6b3b45ba5bc914b8332d8a7c23be05.tar.bz2 yuescript-956cacc11b6b3b45ba5bc914b8332d8a7c23be05.zip |
implemented local declaration with const attribute in Yuescript.
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 167 |
1 files changed, 98 insertions, 69 deletions
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 5f59340..ff554ac 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -59,7 +59,7 @@ inline std::string s(std::string_view sv) { | |||
59 | return std::string(sv); | 59 | return std::string(sv); |
60 | } | 60 | } |
61 | 61 | ||
62 | const std::string_view version = "0.7.9"sv; | 62 | const std::string_view version = "0.7.10"sv; |
63 | const std::string_view extension = "yue"sv; | 63 | const std::string_view extension = "yue"sv; |
64 | 64 | ||
65 | class YueCompilerImpl { | 65 | class YueCompilerImpl { |
@@ -218,7 +218,7 @@ private: | |||
218 | }; | 218 | }; |
219 | struct Scope { | 219 | struct Scope { |
220 | GlobalMode mode = GlobalMode::None; | 220 | GlobalMode mode = GlobalMode::None; |
221 | std::unique_ptr<std::unordered_set<std::string>> vars; | 221 | std::unique_ptr<std::unordered_map<std::string,bool>> vars; |
222 | std::unique_ptr<std::unordered_set<std::string>> allows; | 222 | std::unique_ptr<std::unordered_set<std::string>> allows; |
223 | std::unique_ptr<std::unordered_set<std::string>> globals; | 223 | std::unique_ptr<std::unordered_set<std::string>> globals; |
224 | }; | 224 | }; |
@@ -257,7 +257,7 @@ private: | |||
257 | 257 | ||
258 | void pushScope() { | 258 | void pushScope() { |
259 | _scopes.emplace_back(); | 259 | _scopes.emplace_back(); |
260 | _scopes.back().vars = std::make_unique<std::unordered_set<std::string>>(); | 260 | _scopes.back().vars = std::make_unique<std::unordered_map<std::string,bool>>(); |
261 | } | 261 | } |
262 | 262 | ||
263 | void popScope() { | 263 | void popScope() { |
@@ -272,11 +272,11 @@ private: | |||
272 | if (current.globals) { | 272 | if (current.globals) { |
273 | if (current.globals->find(name) != current.globals->end()) { | 273 | if (current.globals->find(name) != current.globals->end()) { |
274 | isDefined = true; | 274 | isDefined = true; |
275 | current.vars->insert(name); | 275 | current.vars->insert_or_assign(name, false); |
276 | } | 276 | } |
277 | } else { | 277 | } else { |
278 | isDefined = true; | 278 | isDefined = true; |
279 | current.vars->insert(name); | 279 | current.vars->insert_or_assign(name, false); |
280 | } | 280 | } |
281 | } | 281 | } |
282 | decltype(_scopes.back().allows.get()) allows = nullptr; | 282 | decltype(_scopes.back().allows.get()) allows = nullptr; |
@@ -310,6 +310,30 @@ private: | |||
310 | return isDefined; | 310 | return isDefined; |
311 | } | 311 | } |
312 | 312 | ||
313 | bool isConst(const std::string& name) const { | ||
314 | bool isConst = false; | ||
315 | for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { | ||
316 | auto vars = it->vars.get(); | ||
317 | auto vit = vars->find(name); | ||
318 | if (vit != vars->end()) { | ||
319 | isConst = vit->second; | ||
320 | break; | ||
321 | } | ||
322 | } | ||
323 | return isConst; | ||
324 | } | ||
325 | |||
326 | void checkConst(const std::string& name, ast_node* x) const { | ||
327 | if (isConst(name)) { | ||
328 | throw std::logic_error(_info.errorMessage(s("attempt to assign to const variable '"sv) + name + '\'', x)); | ||
329 | } | ||
330 | } | ||
331 | |||
332 | void markVarConst(const std::string& name) { | ||
333 | auto& scope = _scopes.back(); | ||
334 | scope.vars->insert_or_assign(name, true); | ||
335 | } | ||
336 | |||
313 | void markVarShadowed() { | 337 | void markVarShadowed() { |
314 | auto& scope = _scopes.back(); | 338 | auto& scope = _scopes.back(); |
315 | scope.allows = std::make_unique<std::unordered_set<std::string>>(); | 339 | scope.allows = std::make_unique<std::unordered_set<std::string>>(); |
@@ -335,7 +359,7 @@ private: | |||
335 | 359 | ||
336 | void forceAddToScope(const std::string& name) { | 360 | void forceAddToScope(const std::string& name) { |
337 | auto& scope = _scopes.back(); | 361 | auto& scope = _scopes.back(); |
338 | scope.vars->insert(name); | 362 | scope.vars->insert_or_assign(name, false); |
339 | } | 363 | } |
340 | 364 | ||
341 | Scope& currentScope() { | 365 | Scope& currentScope() { |
@@ -346,7 +370,7 @@ private: | |||
346 | bool defined = isDefined(name); | 370 | bool defined = isDefined(name); |
347 | if (!defined) { | 371 | if (!defined) { |
348 | auto& scope = currentScope(); | 372 | auto& scope = currentScope(); |
349 | scope.vars->insert(name); | 373 | scope.vars->insert_or_assign(name, false); |
350 | } | 374 | } |
351 | return !defined; | 375 | return !defined; |
352 | } | 376 | } |
@@ -723,19 +747,21 @@ private: | |||
723 | return nullptr; | 747 | return nullptr; |
724 | } | 748 | } |
725 | 749 | ||
726 | bool isAssignable(const node_container& chainItems) const { | 750 | bool isAssignable(const node_container& chainItems) { |
727 | if (chainItems.size() == 1) { | 751 | if (chainItems.size() == 1) { |
728 | auto firstItem = chainItems.back(); | 752 | auto firstItem = chainItems.back(); |
729 | if (auto callable = ast_cast<Callable_t>(firstItem)) { | 753 | if (auto callable = ast_cast<Callable_t>(firstItem)) { |
730 | switch (callable->item->getId()) { | 754 | switch (callable->item->getId()) { |
731 | case id<Variable_t>(): | 755 | case id<Variable_t>(): |
732 | case id<SelfName_t>(): | 756 | checkConst(_parser.toString(callable->item.get()), callable->item.get()); |
733 | return true; | 757 | return true; |
734 | } | 758 | case id<SelfName_t>(): |
735 | } else if (firstItem->getId() == id<DotChainItem_t>()) { | 759 | return true; |
736 | return true; | 760 | } |
737 | } | 761 | } else if (firstItem->getId() == id<DotChainItem_t>()) { |
738 | } else { | 762 | return true; |
763 | } | ||
764 | } else { | ||
739 | auto lastItem = chainItems.back(); | 765 | auto lastItem = chainItems.back(); |
740 | switch (lastItem->getId()) { | 766 | switch (lastItem->getId()) { |
741 | case id<DotChainItem_t>(): | 767 | case id<DotChainItem_t>(): |
@@ -746,7 +772,7 @@ private: | |||
746 | return false; | 772 | return false; |
747 | } | 773 | } |
748 | 774 | ||
749 | bool isAssignable(Exp_t* exp) const { | 775 | bool isAssignable(Exp_t* exp) { |
750 | if (auto value = singleValueFrom(exp)) { | 776 | if (auto value = singleValueFrom(exp)) { |
751 | auto item = value->item.get(); | 777 | auto item = value->item.get(); |
752 | switch (item->getId()) { | 778 | switch (item->getId()) { |
@@ -768,14 +794,14 @@ private: | |||
768 | return false; | 794 | return false; |
769 | } | 795 | } |
770 | 796 | ||
771 | bool isAssignable(Assignable_t* assignable) const { | 797 | bool isAssignable(Assignable_t* assignable) { |
772 | if (auto assignableChain = ast_cast<AssignableChain_t>(assignable->item)) { | 798 | if (auto assignableChain = ast_cast<AssignableChain_t>(assignable->item)) { |
773 | return isAssignable(assignableChain->items.objects()); | 799 | return isAssignable(assignableChain->items.objects()); |
774 | } | 800 | } |
775 | return true; | 801 | return true; |
776 | } | 802 | } |
777 | 803 | ||
778 | void checkAssignable(ExpList_t* expList) const { | 804 | void checkAssignable(ExpList_t* expList) { |
779 | for (auto exp_ : expList->exprs.objects()) { | 805 | for (auto exp_ : expList->exprs.objects()) { |
780 | Exp_t* exp = static_cast<Exp_t*>(exp_); | 806 | Exp_t* exp = static_cast<Exp_t*>(exp_); |
781 | if (!isAssignable(exp)) { | 807 | if (!isAssignable(exp)) { |
@@ -1014,36 +1040,13 @@ private: | |||
1014 | return vars; | 1040 | return vars; |
1015 | } | 1041 | } |
1016 | 1042 | ||
1017 | str_list getAssignDefs(ExpList_t* expList) { | 1043 | enum class DefOp { |
1018 | str_list preDefs; | 1044 | Get, |
1019 | for (auto exp_ : expList->exprs.objects()) { | 1045 | Check, |
1020 | auto exp = static_cast<Exp_t*>(exp_); | 1046 | Mark |
1021 | if (auto value = singleValueFrom(exp)) { | 1047 | }; |
1022 | if (auto chain = value->item.as<ChainValue_t>()) { | ||
1023 | BLOCK_START | ||
1024 | BREAK_IF(chain->items.size() != 1); | ||
1025 | auto callable = ast_cast<Callable_t>(chain->items.front()); | ||
1026 | BREAK_IF(!callable); | ||
1027 | std::string name; | ||
1028 | if (auto var = callable->item.as<Variable_t>()) { | ||
1029 | name = _parser.toString(var); | ||
1030 | } else if (auto self = callable->item.as<SelfName_t>()) { | ||
1031 | if (self->name.is<self_t>()) name = "self"sv; | ||
1032 | } | ||
1033 | BREAK_IF(name.empty()); | ||
1034 | if (!isDefined(name)) { | ||
1035 | preDefs.push_back(name); | ||
1036 | } | ||
1037 | BLOCK_END | ||
1038 | } | ||
1039 | } else { | ||
1040 | throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, exp)); | ||
1041 | } | ||
1042 | } | ||
1043 | return preDefs; | ||
1044 | } | ||
1045 | 1048 | ||
1046 | str_list transformAssignDefs(ExpList_t* expList, bool markDefined = true) { | 1049 | str_list transformAssignDefs(ExpList_t* expList, DefOp op) { |
1047 | str_list defs; | 1050 | str_list defs; |
1048 | for (auto exp_ : expList->exprs.objects()) { | 1051 | for (auto exp_ : expList->exprs.objects()) { |
1049 | auto exp = static_cast<Exp_t*>(exp_); | 1052 | auto exp = static_cast<Exp_t*>(exp_); |
@@ -1060,8 +1063,16 @@ private: | |||
1060 | if (self->name.is<self_t>()) name = "self"sv; | 1063 | if (self->name.is<self_t>()) name = "self"sv; |
1061 | } | 1064 | } |
1062 | BREAK_IF(name.empty()); | 1065 | BREAK_IF(name.empty()); |
1063 | if (!markDefined || addToScope(name)) { | 1066 | switch (op) { |
1064 | defs.push_back(name); | 1067 | case DefOp::Mark: |
1068 | if (addToScope(name)) defs.push_back(name); | ||
1069 | break; | ||
1070 | case DefOp::Check: | ||
1071 | if (!isDefined(name)) defs.push_back(name); | ||
1072 | break; | ||
1073 | case DefOp::Get: | ||
1074 | defs.push_back(name); | ||
1075 | break; | ||
1065 | } | 1076 | } |
1066 | BLOCK_END | 1077 | BLOCK_END |
1067 | } | 1078 | } |
@@ -1096,7 +1107,7 @@ private: | |||
1096 | std::string getPredefine(ExpListAssign_t* assignment) { | 1107 | std::string getPredefine(ExpListAssign_t* assignment) { |
1097 | auto preDefine = getDestrucureDefine(assignment); | 1108 | auto preDefine = getDestrucureDefine(assignment); |
1098 | if (preDefine.empty()) { | 1109 | if (preDefine.empty()) { |
1099 | preDefine = getPredefine(transformAssignDefs(assignment->expList)); | 1110 | preDefine = getPredefine(transformAssignDefs(assignment->expList, DefOp::Mark)); |
1100 | } | 1111 | } |
1101 | return preDefine; | 1112 | return preDefine; |
1102 | } | 1113 | } |
@@ -1183,7 +1194,7 @@ private: | |||
1183 | case id<Unless_t>(): { | 1194 | case id<Unless_t>(): { |
1184 | auto expList = assignment->expList.get(); | 1195 | auto expList = assignment->expList.get(); |
1185 | str_list temp; | 1196 | str_list temp; |
1186 | auto defs = transformAssignDefs(expList); | 1197 | auto defs = transformAssignDefs(expList, DefOp::Mark); |
1187 | if (!defs.empty()) temp.push_back(getPredefine(defs) + nll(expList)); | 1198 | if (!defs.empty()) temp.push_back(getPredefine(defs) + nll(expList)); |
1188 | switch (value->getId()) { | 1199 | switch (value->getId()) { |
1189 | case id<If_t>(): transformIf(static_cast<If_t*>(value), temp, ExpUsage::Assignment, expList); break; | 1200 | case id<If_t>(): transformIf(static_cast<If_t*>(value), temp, ExpUsage::Assignment, expList); break; |
@@ -1302,8 +1313,9 @@ private: | |||
1302 | if (destruct.items.size() == 1) { | 1313 | if (destruct.items.size() == 1) { |
1303 | auto& pair = destruct.items.front(); | 1314 | auto& pair = destruct.items.front(); |
1304 | _buf << indent(); | 1315 | _buf << indent(); |
1305 | if (pair.isVariable && !isDefined(pair.name)) { | 1316 | if (pair.isVariable) { |
1306 | _buf << s("local "sv); | 1317 | checkConst(pair.name, assignment); |
1318 | if (!isDefined(pair.name)) _buf << s("local "sv); | ||
1307 | } | 1319 | } |
1308 | _buf << pair.name << " = "sv << destruct.value << pair.structure << nll(assignment); | 1320 | _buf << pair.name << " = "sv << destruct.value << pair.structure << nll(assignment); |
1309 | addToScope(pair.name); | 1321 | addToScope(pair.name); |
@@ -1311,8 +1323,9 @@ private: | |||
1311 | } else if (_parser.match<Name_t>(destruct.value) && isDefined(destruct.value)) { | 1323 | } else if (_parser.match<Name_t>(destruct.value) && isDefined(destruct.value)) { |
1312 | str_list defs, names, values; | 1324 | str_list defs, names, values; |
1313 | for (const auto& item : destruct.items) { | 1325 | for (const auto& item : destruct.items) { |
1314 | if (item.isVariable && addToScope(item.name)) { | 1326 | if (item.isVariable) { |
1315 | defs.push_back(item.name); | 1327 | checkConst(item.name, assignment); |
1328 | if (addToScope(item.name)) defs.push_back(item.name); | ||
1316 | } | 1329 | } |
1317 | names.push_back(item.name); | 1330 | names.push_back(item.name); |
1318 | values.push_back(item.structure); | 1331 | values.push_back(item.structure); |
@@ -1331,8 +1344,9 @@ private: | |||
1331 | } else { | 1344 | } else { |
1332 | str_list defs, names, values; | 1345 | str_list defs, names, values; |
1333 | for (const auto& item : destruct.items) { | 1346 | for (const auto& item : destruct.items) { |
1334 | if (item.isVariable && addToScope(item.name)) { | 1347 | if (item.isVariable) { |
1335 | defs.push_back(item.name); | 1348 | checkConst(item.name, assignment); |
1349 | if (addToScope(item.name)) defs.push_back(item.name); | ||
1336 | } | 1350 | } |
1337 | names.push_back(item.name); | 1351 | names.push_back(item.name); |
1338 | values.push_back(item.structure); | 1352 | values.push_back(item.structure); |
@@ -1711,7 +1725,7 @@ private: | |||
1711 | right = s("("sv) + right + s(")"sv); | 1725 | right = s("("sv) + right + s(")"sv); |
1712 | } | 1726 | } |
1713 | _buf << join(temp) << indent() << left << " = "sv << left << | 1727 | _buf << join(temp) << indent() << left << " = "sv << left << |
1714 | " "sv << _parser.toString(update->op) << " "sv << right << nll(assignment); | 1728 | ' ' << _parser.toString(update->op) << ' ' << right << nll(assignment); |
1715 | out.push_back(clearBuf()); | 1729 | out.push_back(clearBuf()); |
1716 | break; | 1730 | break; |
1717 | } | 1731 | } |
@@ -1728,7 +1742,7 @@ private: | |||
1728 | } | 1742 | } |
1729 | } | 1743 | } |
1730 | } | 1744 | } |
1731 | auto defs = getAssignDefs(expList); | 1745 | auto defs = transformAssignDefs(expList, DefOp::Check); |
1732 | if (oneLined && defs.size() == expList->exprs.objects().size()) { | 1746 | if (oneLined && defs.size() == expList->exprs.objects().size()) { |
1733 | for (auto value : assign->values.objects()) { | 1747 | for (auto value : assign->values.objects()) { |
1734 | transformAssignItem(value, temp); | 1748 | transformAssignItem(value, temp); |
@@ -2374,7 +2388,7 @@ private: | |||
2374 | } | 2388 | } |
2375 | } | 2389 | } |
2376 | if (info.second) { | 2390 | if (info.second) { |
2377 | auto defs = transformAssignDefs(info.second->expList, false); | 2391 | auto defs = transformAssignDefs(info.second->expList, DefOp::Get); |
2378 | for (const auto& def : defs) { | 2392 | for (const auto& def : defs) { |
2379 | if (std::isupper(def[0]) && capital) { capital->decls.push_back(def); | 2393 | if (std::isupper(def[0]) && capital) { capital->decls.push_back(def); |
2380 | } else if (any) { | 2394 | } else if (any) { |
@@ -4589,7 +4603,7 @@ private: | |||
4589 | if (auto statement = ast_cast<Statement_t>(item)) { | 4603 | if (auto statement = ast_cast<Statement_t>(item)) { |
4590 | ClassDecl_t* clsDecl = nullptr; | 4604 | ClassDecl_t* clsDecl = nullptr; |
4591 | if (auto assignment = assignmentFrom(statement)) { | 4605 | if (auto assignment = assignmentFrom(statement)) { |
4592 | auto names = transformAssignDefs(assignment->expList.get()); | 4606 | auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark); |
4593 | varDefs.insert(varDefs.end(), names.begin(), names.end()); | 4607 | varDefs.insert(varDefs.end(), names.begin(), names.end()); |
4594 | auto info = extractDestructureInfo(assignment, true); | 4608 | auto info = extractDestructureInfo(assignment, true); |
4595 | if (!info.first.empty()) { | 4609 | if (!info.first.empty()) { |
@@ -4906,7 +4920,6 @@ private: | |||
4906 | std::string withVar; | 4920 | std::string withVar; |
4907 | bool scoped = false; | 4921 | bool scoped = false; |
4908 | if (with->assigns) { | 4922 | if (with->assigns) { |
4909 | checkAssignable(with->valueList); | ||
4910 | auto vars = getAssignVars(with); | 4923 | auto vars = getAssignVars(with); |
4911 | if (vars.front().empty()) { | 4924 | if (vars.front().empty()) { |
4912 | if (with->assigns->values.objects().size() == 1) { | 4925 | if (with->assigns->values.objects().size() == 1) { |
@@ -4978,7 +4991,7 @@ private: | |||
4978 | if (auto statement = ast_cast<Statement_t>(node)) { | 4991 | if (auto statement = ast_cast<Statement_t>(node)) { |
4979 | ClassDecl_t* clsDecl = nullptr; | 4992 | ClassDecl_t* clsDecl = nullptr; |
4980 | if (auto assignment = assignmentFrom(statement)) { | 4993 | if (auto assignment = assignmentFrom(statement)) { |
4981 | auto names = getAssignDefs(assignment->expList.get()); | 4994 | auto names = transformAssignDefs(assignment->expList.get(), DefOp::Get); |
4982 | if (!names.empty()) { | 4995 | if (!names.empty()) { |
4983 | return traversal::Stop; | 4996 | return traversal::Stop; |
4984 | } | 4997 | } |
@@ -5132,7 +5145,7 @@ private: | |||
5132 | assignment->expList.set(expList); | 5145 | assignment->expList.set(expList); |
5133 | assignment->action.set(exportNode->assign); | 5146 | assignment->action.set(exportNode->assign); |
5134 | transformAssignment(assignment, out); | 5147 | transformAssignment(assignment, out); |
5135 | str_list names = transformAssignDefs(expList, false); | 5148 | str_list names = transformAssignDefs(expList, DefOp::Get); |
5136 | auto info = extractDestructureInfo(assignment, true); | 5149 | auto info = extractDestructureInfo(assignment, true); |
5137 | if (!info.first.empty()) { | 5150 | if (!info.first.empty()) { |
5138 | for (const auto& destruct : info.first) | 5151 | for (const auto& destruct : info.first) |
@@ -5501,7 +5514,7 @@ private: | |||
5501 | } | 5514 | } |
5502 | } | 5515 | } |
5503 | if (objAssign) { | 5516 | if (objAssign) { |
5504 | auto preDef = getPredefine(transformAssignDefs(expList)); | 5517 | auto preDef = getPredefine(transformAssignDefs(expList, DefOp::Mark)); |
5505 | if (!preDef.empty()) { | 5518 | if (!preDef.empty()) { |
5506 | temp.push_back(preDef + nll(import)); | 5519 | temp.push_back(preDef + nll(import)); |
5507 | } | 5520 | } |
@@ -5886,6 +5899,22 @@ private: | |||
5886 | if (attrib != "close"sv && attrib != "const"sv) { | 5899 | if (attrib != "close"sv && attrib != "const"sv) { |
5887 | throw std::logic_error(_info.errorMessage(s("unknown attribute '"sv) + attrib + '\'', localAttrib->attrib)); | 5900 | throw std::logic_error(_info.errorMessage(s("unknown attribute '"sv) + attrib + '\'', localAttrib->attrib)); |
5888 | } | 5901 | } |
5902 | if (attrib == "const"sv) { | ||
5903 | str_list vars; | ||
5904 | for (auto name : localAttrib->nameList->names.objects()) { | ||
5905 | vars.push_back(_parser.toString(name)); | ||
5906 | } | ||
5907 | auto varStr = join(vars, ", "sv); | ||
5908 | auto varList = toAst<ExpList_t>(varStr, x); | ||
5909 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
5910 | assignment->expList.set(varList); | ||
5911 | assignment->action.set(localAttrib->assign); | ||
5912 | transformAssignment(assignment, out); | ||
5913 | for (const auto& var : vars) { | ||
5914 | markVarConst(var); | ||
5915 | } | ||
5916 | return; | ||
5917 | } | ||
5889 | auto expList = x->new_ptr<ExpList_t>(); | 5918 | auto expList = x->new_ptr<ExpList_t>(); |
5890 | str_list tmpVars; | 5919 | str_list tmpVars; |
5891 | str_list vars; | 5920 | str_list vars; |