summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2021-04-27 15:31:12 +0800
committerLi Jin <dragon-fly@qq.com>2021-04-27 15:31:12 +0800
commit956cacc11b6b3b45ba5bc914b8332d8a7c23be05 (patch)
tree322b7e61f1014726bb70f91280b978eed2d2d158
parent705dfda89c7795f84419e176e3f861780fbd0fcb (diff)
downloadyuescript-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.cpp167
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
62const std::string_view version = "0.7.9"sv; 62const std::string_view version = "0.7.10"sv;
63const std::string_view extension = "yue"sv; 63const std::string_view extension = "yue"sv;
64 64
65class YueCompilerImpl { 65class 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;