From fced0c4f4101ad7c8d81432a0e8c45d38b72616c Mon Sep 17 00:00:00 2001 From: Li Jin Date: Thu, 15 Jan 2026 17:07:11 +0800 Subject: Added `import global` syntax. --- src/yuescript/yue_ast.cpp | 3 ++ src/yuescript/yue_ast.h | 5 ++- src/yuescript/yue_compiler.cpp | 78 +++++++++++++++++++++++++++++++++++------- src/yuescript/yue_parser.cpp | 16 +++++---- src/yuescript/yue_parser.h | 1 + 5 files changed, 83 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp index 14d8db8..c9fd23f 100644 --- a/src/yuescript/yue_ast.cpp +++ b/src/yuescript/yue_ast.cpp @@ -326,6 +326,9 @@ std::string ImportGlobal_t::to_string(void* ud) const { } return item; } +std::string ImportAllGlobal_t::to_string(void*) const { + return "global"s; +} std::string Import_t::to_string(void* ud) const { if (ast_is(content)) { return content->to_string(ud); diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index ba4186d..af2355a 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h @@ -233,6 +233,9 @@ AST_NODE(ImportAs) AST_MEMBER(ImportAs, &literal, &target) AST_END(ImportAs) +AST_LEAF(ImportAllGlobal) +AST_END(ImportAllGlobal) + AST_NODE(ImportGlobal) ast_ptr sep; ast_list segs; @@ -241,7 +244,7 @@ AST_NODE(ImportGlobal) AST_END(ImportGlobal) AST_NODE(Import) - ast_sel content; + ast_sel content; AST_MEMBER(Import, &content) AST_END(Import) diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index cffa7a8..10f8719 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -78,7 +78,7 @@ static std::unordered_set Metamethods = { "close"s // Lua 5.4 }; -const std::string_view version = "0.30.4"sv; +const std::string_view version = "0.31.0"sv; const std::string_view extension = "yue"sv; class CompileError : public std::logic_error { @@ -434,6 +434,14 @@ private: Global = 2, GlobalConst = 3 }; + struct Scope; + struct ImportedGlobal { + std::string* globalCodeLine = nullptr; + Scope* importingScope = nullptr; + std::string indent; + std::string nl; + std::unordered_set globals; + }; struct Scope { GlobalMode mode = GlobalMode::None; bool lastStatement = false; @@ -442,8 +450,10 @@ private: #endif std::unique_ptr> vars; std::unique_ptr> allows; + std::unique_ptr importedGlobal; }; std::list _scopes; + ImportedGlobal* _importedGlobal = nullptr; static const std::string Empty; enum class MemType { @@ -1612,7 +1622,12 @@ private: std::string globalVar(std::string_view var, ast_node* x, AccessType accessType) { std::string str(var); - if (_config.lintGlobalVariable) { + if (_importedGlobal) { + if (_importedGlobal->globals.find(str) == _importedGlobal->globals.end() && !isSolidDefined(str)) { + _importedGlobal->globals.insert(str); + _importedGlobal->importingScope->vars->insert_or_assign(str, VarType::LocalConst); + } + } else if (_config.lintGlobalVariable) { if (!isLocal(str)) { auto key = str + ':' + std::to_string(x->m_begin.m_line) + ':' + std::to_string(x->m_begin.m_col); if (_globals.find(key) == _globals.end()) { @@ -4617,13 +4632,21 @@ private: switch (item->get_id()) { case id(): { transformVariable(static_cast(item), out); - if (_config.lintGlobalVariable && accessType != AccessType::None && !isLocal(out.back())) { - auto key = out.back() + ':' + std::to_string(item->m_begin.m_line) + ':' + std::to_string(item->m_begin.m_col); - if (_globals.find(key) == _globals.end()) { - if (accessType == AccessType::Read && _funcLevel > 1) { - accessType = AccessType::Capture; + if (accessType != AccessType::None) { + if (_importedGlobal) { + const auto& str = out.back(); + if (_importedGlobal->globals.find(str) == _importedGlobal->globals.end() && !isSolidDefined(str)) { + _importedGlobal->globals.insert(str); + _importedGlobal->importingScope->vars->insert_or_assign(str, VarType::LocalConst); + } + } else if (_config.lintGlobalVariable && !isLocal(out.back())) { + auto key = out.back() + ':' + std::to_string(item->m_begin.m_line) + ':' + std::to_string(item->m_begin.m_col); + if (_globals.find(key) == _globals.end()) { + if (accessType == AccessType::Read && _funcLevel > 1) { + accessType = AccessType::Capture; + } + _globals[key] = {out.back(), item->m_begin.m_line, item->m_begin.m_col, accessType, isSolidDefined(out.back())}; } - _globals[key] = {out.back(), item->m_begin.m_line, item->m_begin.m_col, accessType, isSolidDefined(out.back())}; } } break; @@ -5299,7 +5322,23 @@ private: } auto transformNode = [&]() { currentScope().lastStatement = (node == lastStmt) && currentScope().mode == GlobalMode::None; - transformStatement(static_cast(node), temp); + auto stmt = static_cast(node); + if (auto importNode = stmt->content.as(); + importNode && importNode->content.is()) { + if (_importedGlobal) { + throw CompileError("import global redeclared in same scope"sv, importNode); + } else { + auto& scope = currentScope(); + scope.importedGlobal = std::make_unique(); + _importedGlobal = scope.importedGlobal.get(); + _importedGlobal->importingScope = &scope; + _importedGlobal->indent = indent(); + _importedGlobal->nl = nl(stmt); + _importedGlobal->globalCodeLine = &temp.emplace_back(); + } + } else { + transformStatement(stmt, temp); + } if (isRoot && !_rootDefs.empty()) { auto last = std::move(temp.back()); temp.pop_back(); @@ -5338,6 +5377,14 @@ private: transformNode(); } } + if (auto importedGlobal = currentScope().importedGlobal.get()) { + str_list globalCodes; + for (const auto& global : importedGlobal->globals) { + globalCodes.emplace_back(importedGlobal->indent + "local "s + global + " = "s + global + importedGlobal->nl); + } + *importedGlobal->globalCodeLine = join(globalCodes); + _importedGlobal = nullptr; + } out.push_back(join(temp)); } else { out.push_back(Empty); @@ -9313,7 +9360,12 @@ private: } else { out.push_back(name + " = "s + name); } - if (_config.lintGlobalVariable && !isLocal(name)) { + if (_importedGlobal) { + if (_importedGlobal->globals.find(name) == _importedGlobal->globals.end() && !isSolidDefined(name)) { + _importedGlobal->globals.insert(name); + _importedGlobal->importingScope->vars->insert_or_assign(name, VarType::LocalConst); + } + } else if (_config.lintGlobalVariable && !isLocal(name)) { auto key = name + ':' + std::to_string(pair->name->m_begin.m_line) + ':' + std::to_string(pair->name->m_begin.m_col); if (_globals.find(key) == _globals.end()) { _globals[key] = {name, pair->name->m_begin.m_line, pair->name->m_begin.m_col, _funcLevel > 1 ? AccessType::Capture : AccessType::Read, isSolidDefined(name)}; @@ -10348,8 +10400,10 @@ private: } assignment->action.set(assign); transformAssignment(assignment, out); - for (const auto& name : varNames) { - markVarGlobalConst(name); + if (global->constAttrib) { + for (const auto& name : varNames) { + markVarGlobalConst(name); + } } } else { for (auto name : values->nameList->names.objects()) { diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 1dfe978..6990e31 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -464,7 +464,9 @@ YueParser::YueParser() { ImportGlobal = Seperator >> UnicodeName >> *('.' >> UnicodeName) >> space >> not_(',' | key("from")) >> -(key("as") >> space >> must_variable); - Import = key("import") >> space >> (ImportGlobal | ImportAs | ImportFrom | invalid_import_syntax_error) | FromImport; + ImportAllGlobal = key("global"); + + Import = key("import") >> space >> (ImportAllGlobal | ImportGlobal | ImportAs | ImportFrom | invalid_import_syntax_error) | FromImport; Label = "::" >> (and_(LuaKeyword >> "::") >> keyword_as_label_error | UnicodeName >> "::"); @@ -982,7 +984,7 @@ YueParser::YueParser() { return true; }) | invalid_export_syntax_error - ) >> not_(space >> StatementAppendix); + ); VariablePair = ':' >> Variable; @@ -1125,14 +1127,14 @@ YueParser::YueParser() { StatementAppendix = (IfLine | WhileLine | CompFor) >> space; Statement = ( - Import | While | Repeat | For | - Return | Local | Global | Export | Macro | - MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending | + Import | Export | Global | Macro | MacroInPlace | Label + ) | ( + Local | While | Repeat | For | Return | + BreakLoop | Goto | ShortTabAppending | LocalAttrib | Backcall | PipeBody | ExpListAssign | ChainAssign | StatementAppendix >> empty_block_error | and_(key("else") | key("elseif") | key("when")) >> dangling_clause_error - ) >> space >> - -StatementAppendix; + ) >> space >> -StatementAppendix; StatementSep = white >> (set("('\"") | "[[" | "[="); diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index acb56d0..c516ccd 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -352,6 +352,7 @@ private: AST_RULE(ImportTabLit); AST_RULE(ImportAs); AST_RULE(ImportGlobal); + AST_RULE(ImportAllGlobal); AST_RULE(Import); AST_RULE(Label); AST_RULE(Goto); -- cgit v1.2.3-55-g6feb