diff options
author | Li Jin <dragon-fly@qq.com> | 2021-05-07 17:06:00 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2021-05-07 17:06:00 +0800 |
commit | 4c9209b131936ad97c73a7c0e71042fe24369a8e (patch) | |
tree | 4e0ea3a2e9b4cdf3cb8e1ddc8b974faaddcab94b | |
parent | c46703c3d7c756608ca050143703483368ebf466 (diff) | |
download | yuescript-4c9209b131936ad97c73a7c0e71042fe24369a8e.tar.gz yuescript-4c9209b131936ad97c73a7c0e71042fe24369a8e.tar.bz2 yuescript-4c9209b131936ad97c73a7c0e71042fe24369a8e.zip |
fix variable type check functions.
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 71 |
1 files changed, 39 insertions, 32 deletions
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 78fb5e2..4646288 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.12"sv; | 62 | const std::string_view version = "0.7.13"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 { |
@@ -216,9 +216,14 @@ private: | |||
216 | Capital = 1, | 216 | Capital = 1, |
217 | Any = 2 | 217 | Any = 2 |
218 | }; | 218 | }; |
219 | enum class VarType { | ||
220 | Local = 0, | ||
221 | Const = 1, | ||
222 | Global = 2 | ||
223 | }; | ||
219 | struct Scope { | 224 | struct Scope { |
220 | GlobalMode mode = GlobalMode::None; | 225 | GlobalMode mode = GlobalMode::None; |
221 | std::unique_ptr<std::unordered_map<std::string,bool>> vars; | 226 | std::unique_ptr<std::unordered_map<std::string,VarType>> vars; |
222 | std::unique_ptr<std::unordered_set<std::string>> allows; | 227 | std::unique_ptr<std::unordered_set<std::string>> allows; |
223 | std::unique_ptr<std::unordered_set<std::string>> globals; | 228 | std::unique_ptr<std::unordered_set<std::string>> globals; |
224 | }; | 229 | }; |
@@ -257,7 +262,7 @@ private: | |||
257 | 262 | ||
258 | void pushScope() { | 263 | void pushScope() { |
259 | _scopes.emplace_back(); | 264 | _scopes.emplace_back(); |
260 | _scopes.back().vars = std::make_unique<std::unordered_map<std::string,bool>>(); | 265 | _scopes.back().vars = std::make_unique<std::unordered_map<std::string,VarType>>(); |
261 | } | 266 | } |
262 | 267 | ||
263 | void popScope() { | 268 | void popScope() { |
@@ -272,11 +277,11 @@ private: | |||
272 | if (current.globals) { | 277 | if (current.globals) { |
273 | if (current.globals->find(name) != current.globals->end()) { | 278 | if (current.globals->find(name) != current.globals->end()) { |
274 | isDefined = true; | 279 | isDefined = true; |
275 | current.vars->insert_or_assign(name, false); | 280 | current.vars->insert_or_assign(name, VarType::Global); |
276 | } | 281 | } |
277 | } else { | 282 | } else { |
278 | isDefined = true; | 283 | isDefined = true; |
279 | current.vars->insert_or_assign(name, false); | 284 | current.vars->insert_or_assign(name, VarType::Global); |
280 | } | 285 | } |
281 | } | 286 | } |
282 | decltype(_scopes.back().allows.get()) allows = nullptr; | 287 | decltype(_scopes.back().allows.get()) allows = nullptr; |
@@ -298,11 +303,12 @@ private: | |||
298 | return isDefined; | 303 | return isDefined; |
299 | } | 304 | } |
300 | 305 | ||
301 | bool isSolidDefined(const std::string& name) const { | 306 | bool isLocal(const std::string& name) const { |
302 | bool isDefined = false; | 307 | bool isDefined = false; |
303 | for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { | 308 | for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { |
304 | auto vars = it->vars.get(); | 309 | auto vars = it->vars.get(); |
305 | if (vars->find(name) != vars->end()) { | 310 | auto vit = vars->find(name); |
311 | if (vit != vars->end() && vit->second != VarType::Global) { | ||
306 | isDefined = true; | 312 | isDefined = true; |
307 | break; | 313 | break; |
308 | } | 314 | } |
@@ -324,7 +330,7 @@ private: | |||
324 | auto vars = it->vars.get(); | 330 | auto vars = it->vars.get(); |
325 | auto vit = vars->find(name); | 331 | auto vit = vars->find(name); |
326 | if (vit != vars->end()) { | 332 | if (vit != vars->end()) { |
327 | isConst = vit->second; | 333 | isConst = (vit->second == VarType::Const); |
328 | break; | 334 | break; |
329 | } | 335 | } |
330 | if (checkShadowScopeOnly && it->allows) break; | 336 | if (checkShadowScopeOnly && it->allows) break; |
@@ -340,7 +346,7 @@ private: | |||
340 | 346 | ||
341 | void markVarConst(const std::string& name) { | 347 | void markVarConst(const std::string& name) { |
342 | auto& scope = _scopes.back(); | 348 | auto& scope = _scopes.back(); |
343 | scope.vars->insert_or_assign(name, true); | 349 | scope.vars->insert_or_assign(name, VarType::Const); |
344 | } | 350 | } |
345 | 351 | ||
346 | void markVarShadowed() { | 352 | void markVarShadowed() { |
@@ -348,16 +354,17 @@ private: | |||
348 | scope.allows = std::make_unique<std::unordered_set<std::string>>(); | 354 | scope.allows = std::make_unique<std::unordered_set<std::string>>(); |
349 | } | 355 | } |
350 | 356 | ||
351 | void markVarGlobal(GlobalMode mode, bool specified) { | 357 | void markVarsGlobal(GlobalMode mode) { |
352 | auto& scope = _scopes.back(); | 358 | auto& scope = _scopes.back(); |
353 | scope.mode = mode; | 359 | scope.mode = mode; |
354 | if (specified && !scope.globals) { | ||
355 | scope.globals = std::make_unique<std::unordered_set<std::string>>(); | ||
356 | } | ||
357 | } | 360 | } |
358 | 361 | ||
359 | void addGlobalVar(const std::string& name) { | 362 | void addGlobalVar(const std::string& name, ast_node* x) { |
363 | if (isLocal(name)) throw std::logic_error(_info.errorMessage("can not declare a local variable to be global"sv, x)); | ||
360 | auto& scope = _scopes.back(); | 364 | auto& scope = _scopes.back(); |
365 | if (!scope.globals) { | ||
366 | scope.globals = std::make_unique<std::unordered_set<std::string>>(); | ||
367 | } | ||
361 | scope.globals->insert(name); | 368 | scope.globals->insert(name); |
362 | } | 369 | } |
363 | 370 | ||
@@ -368,7 +375,7 @@ private: | |||
368 | 375 | ||
369 | void forceAddToScope(const std::string& name) { | 376 | void forceAddToScope(const std::string& name) { |
370 | auto& scope = _scopes.back(); | 377 | auto& scope = _scopes.back(); |
371 | scope.vars->insert_or_assign(name, false); | 378 | scope.vars->insert_or_assign(name, VarType::Local); |
372 | } | 379 | } |
373 | 380 | ||
374 | Scope& currentScope() { | 381 | Scope& currentScope() { |
@@ -379,7 +386,7 @@ private: | |||
379 | bool defined = isDefined(name); | 386 | bool defined = isDefined(name); |
380 | if (!defined) { | 387 | if (!defined) { |
381 | auto& scope = currentScope(); | 388 | auto& scope = currentScope(); |
382 | scope.vars->insert_or_assign(name, false); | 389 | scope.vars->insert_or_assign(name, VarType::Local); |
383 | } | 390 | } |
384 | return !defined; | 391 | return !defined; |
385 | } | 392 | } |
@@ -390,7 +397,7 @@ private: | |||
390 | do { | 397 | do { |
391 | newName = s(name) + std::to_string(index); | 398 | newName = s(name) + std::to_string(index); |
392 | index++; | 399 | index++; |
393 | } while (isSolidDefined(newName)); | 400 | } while (isLocal(newName)); |
394 | return newName; | 401 | return newName; |
395 | } | 402 | } |
396 | 403 | ||
@@ -2105,7 +2112,7 @@ private: | |||
2105 | switch (item->getId()) { | 2112 | switch (item->getId()) { |
2106 | case id<Variable_t>(): { | 2113 | case id<Variable_t>(): { |
2107 | transformVariable(static_cast<Variable_t*>(item), out); | 2114 | transformVariable(static_cast<Variable_t*>(item), out); |
2108 | if (_config.lintGlobalVariable && !isSolidDefined(out.back())) { | 2115 | if (_config.lintGlobalVariable && !isLocal(out.back())) { |
2109 | if (_globals.find(out.back()) == _globals.end()) { | 2116 | if (_globals.find(out.back()) == _globals.end()) { |
2110 | _globals[out.back()] = {item->m_begin.m_line, item->m_begin.m_col}; | 2117 | _globals[out.back()] = {item->m_begin.m_line, item->m_begin.m_col}; |
2111 | } | 2118 | } |
@@ -4060,7 +4067,7 @@ private: | |||
4060 | case id<star_exp_t>(): { | 4067 | case id<star_exp_t>(): { |
4061 | auto star_exp = static_cast<star_exp_t*>(loopTarget); | 4068 | auto star_exp = static_cast<star_exp_t*>(loopTarget); |
4062 | auto listVar = singleVariableFrom(star_exp->value); | 4069 | auto listVar = singleVariableFrom(star_exp->value); |
4063 | if (!isSolidDefined(listVar)) listVar.clear(); | 4070 | if (!isLocal(listVar)) listVar.clear(); |
4064 | auto indexVar = getUnusedName("_index_"sv); | 4071 | auto indexVar = getUnusedName("_index_"sv); |
4065 | varAfter.push_back(indexVar); | 4072 | varAfter.push_back(indexVar); |
4066 | auto value = singleValueFrom(star_exp->value); | 4073 | auto value = singleValueFrom(star_exp->value); |
@@ -4076,7 +4083,7 @@ private: | |||
4076 | if (listVar.empty() && chainList.size() == 2) { | 4083 | if (listVar.empty() && chainList.size() == 2) { |
4077 | if (auto var = chainList.front()->getByPath<Variable_t>()) { | 4084 | if (auto var = chainList.front()->getByPath<Variable_t>()) { |
4078 | listVar = _parser.toString(var); | 4085 | listVar = _parser.toString(var); |
4079 | if (!isSolidDefined(listVar)) listVar.clear(); | 4086 | if (!isLocal(listVar)) listVar.clear(); |
4080 | } | 4087 | } |
4081 | } | 4088 | } |
4082 | chainList.pop_back(); | 4089 | chainList.pop_back(); |
@@ -4439,7 +4446,7 @@ private: | |||
4439 | 4446 | ||
4440 | void transform_variable_pair(variable_pair_t* pair, str_list& out) { | 4447 | void transform_variable_pair(variable_pair_t* pair, str_list& out) { |
4441 | auto name = _parser.toString(pair->name); | 4448 | auto name = _parser.toString(pair->name); |
4442 | if (_config.lintGlobalVariable && !isSolidDefined(name)) { | 4449 | if (_config.lintGlobalVariable && !isLocal(name)) { |
4443 | if (_globals.find(name) == _globals.end()) { | 4450 | if (_globals.find(name) == _globals.end()) { |
4444 | _globals[name] = {pair->name->m_begin.m_line, pair->name->m_begin.m_col}; | 4451 | _globals[name] = {pair->name->m_begin.m_line, pair->name->m_begin.m_col}; |
4445 | } | 4452 | } |
@@ -4938,7 +4945,7 @@ private: | |||
4938 | if (vars.front().empty()) { | 4945 | if (vars.front().empty()) { |
4939 | if (with->assigns->values.objects().size() == 1) { | 4946 | if (with->assigns->values.objects().size() == 1) { |
4940 | auto var = singleVariableFrom(with->assigns->values.objects().front()); | 4947 | auto var = singleVariableFrom(with->assigns->values.objects().front()); |
4941 | if (!var.empty() && isSolidDefined(var)) { | 4948 | if (!var.empty() && isLocal(var)) { |
4942 | withVar = var; | 4949 | withVar = var; |
4943 | } | 4950 | } |
4944 | } | 4951 | } |
@@ -4984,7 +4991,7 @@ private: | |||
4984 | } | 4991 | } |
4985 | } else { | 4992 | } else { |
4986 | withVar = singleVariableFrom(with->valueList); | 4993 | withVar = singleVariableFrom(with->valueList); |
4987 | if (withVar.empty() || !isSolidDefined(withVar)) { | 4994 | if (withVar.empty() || !isLocal(withVar)) { |
4988 | withVar = getUnusedName("_with_"sv); | 4995 | withVar = getUnusedName("_with_"sv); |
4989 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 4996 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
4990 | assignment->expList.set(toAst<ExpList_t>(withVar, x)); | 4997 | assignment->expList.set(toAst<ExpList_t>(withVar, x)); |
@@ -5086,26 +5093,26 @@ private: | |||
5086 | case id<ClassDecl_t>(): { | 5093 | case id<ClassDecl_t>(): { |
5087 | auto classDecl = static_cast<ClassDecl_t*>(item); | 5094 | auto classDecl = static_cast<ClassDecl_t*>(item); |
5088 | if (classDecl->name && classDecl->name->item->getId() == id<Variable_t>()) { | 5095 | if (classDecl->name && classDecl->name->item->getId() == id<Variable_t>()) { |
5089 | markVarGlobal(GlobalMode::Any, true); | 5096 | markVarsGlobal(GlobalMode::Any); |
5090 | addGlobalVar(_parser.toString(classDecl->name->item)); | 5097 | addGlobalVar(_parser.toString(classDecl->name->item), classDecl->name->item); |
5091 | } | 5098 | } |
5092 | transformClassDecl(classDecl, out, ExpUsage::Common); | 5099 | transformClassDecl(classDecl, out, ExpUsage::Common); |
5093 | break; | 5100 | break; |
5094 | } | 5101 | } |
5095 | case id<global_op_t>(): | 5102 | case id<global_op_t>(): |
5096 | if (_parser.toString(item) == "*"sv) { | 5103 | if (_parser.toString(item) == "*"sv) { |
5097 | markVarGlobal(GlobalMode::Any, false); | 5104 | markVarsGlobal(GlobalMode::Any); |
5098 | } else { | 5105 | } else { |
5099 | markVarGlobal(GlobalMode::Capital, false); | 5106 | markVarsGlobal(GlobalMode::Capital); |
5100 | } | 5107 | } |
5101 | break; | 5108 | break; |
5102 | case id<global_values_t>(): { | 5109 | case id<global_values_t>(): { |
5103 | markVarGlobal(GlobalMode::Any, true); | 5110 | markVarsGlobal(GlobalMode::Any); |
5104 | auto values = global->item.to<global_values_t>(); | 5111 | auto values = global->item.to<global_values_t>(); |
5105 | if (values->valueList) { | 5112 | if (values->valueList) { |
5106 | auto expList = x->new_ptr<ExpList_t>(); | 5113 | auto expList = x->new_ptr<ExpList_t>(); |
5107 | for (auto name : values->nameList->names.objects()) { | 5114 | for (auto name : values->nameList->names.objects()) { |
5108 | addGlobalVar(_parser.toString(name)); | 5115 | addGlobalVar(_parser.toString(name), name); |
5109 | auto callable = x->new_ptr<Callable_t>(); | 5116 | auto callable = x->new_ptr<Callable_t>(); |
5110 | callable->item.set(name); | 5117 | callable->item.set(name); |
5111 | auto chainValue = x->new_ptr<ChainValue_t>(); | 5118 | auto chainValue = x->new_ptr<ChainValue_t>(); |
@@ -5128,7 +5135,7 @@ private: | |||
5128 | transformAssignment(assignment, out); | 5135 | transformAssignment(assignment, out); |
5129 | } else { | 5136 | } else { |
5130 | for (auto name : values->nameList->names.objects()) { | 5137 | for (auto name : values->nameList->names.objects()) { |
5131 | addGlobalVar(_parser.toString(name)); | 5138 | addGlobalVar(_parser.toString(name), name); |
5132 | } | 5139 | } |
5133 | } | 5140 | } |
5134 | break; | 5141 | break; |
@@ -5810,7 +5817,7 @@ private: | |||
5810 | _enableReturn.push(true); | 5817 | _enableReturn.push(true); |
5811 | } | 5818 | } |
5812 | auto objVar = singleVariableFrom(switchNode->target); | 5819 | auto objVar = singleVariableFrom(switchNode->target); |
5813 | if (objVar.empty()) { | 5820 | if (objVar.empty() || !isLocal(objVar)) { |
5814 | objVar = getUnusedName("_exp_"sv); | 5821 | objVar = getUnusedName("_exp_"sv); |
5815 | addToScope(objVar); | 5822 | addToScope(objVar); |
5816 | transformExp(switchNode->target, temp, ExpUsage::Closure); | 5823 | transformExp(switchNode->target, temp, ExpUsage::Closure); |
@@ -5921,7 +5928,7 @@ private: | |||
5921 | } | 5928 | } |
5922 | str_list temp; | 5929 | str_list temp; |
5923 | auto varStr = join(vars, ", "sv); | 5930 | auto varStr = join(vars, ", "sv); |
5924 | temp.push_back(s("local "sv) + varStr + nll(x)); | 5931 | temp.push_back(indent() + s("local "sv) + varStr + nll(x)); |
5925 | auto varList = toAst<ExpList_t>(varStr, x); | 5932 | auto varList = toAst<ExpList_t>(varStr, x); |
5926 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 5933 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
5927 | assignment->expList.set(varList); | 5934 | assignment->expList.set(varList); |