From bb563257953628a9849c8532a684b5064bf8e655 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Mon, 8 Dec 2025 10:21:10 +0800 Subject: Refactored FnArgsDef rules. Fixed issue #224. --- spec/inputs/syntax.yue | 4 ++-- spec/inputs/unicode/syntax.yue | 4 ++-- src/yuescript/yue_compiler.cpp | 20 ++++++++++++-------- src/yuescript/yue_parser.cpp | 43 ++++++++++++++++++++++++++++++++---------- src/yuescript/yue_parser.h | 2 ++ 5 files changed, 51 insertions(+), 22 deletions(-) diff --git a/spec/inputs/syntax.yue b/spec/inputs/syntax.yue index 4c0c56c..eee518a 100644 --- a/spec/inputs/syntax.yue +++ b/spec/inputs/syntax.yue @@ -392,7 +392,7 @@ invokeA( v = { a -1 a( --1) + -1) a \ - 1 a-1 @@ -405,7 +405,7 @@ v = { a ~1 a( -~1) + ~1) a \ ~ 1 a~1 diff --git a/spec/inputs/unicode/syntax.yue b/spec/inputs/unicode/syntax.yue index 8a98416..01d5c87 100644 --- a/spec/inputs/unicode/syntax.yue +++ b/spec/inputs/unicode/syntax.yue @@ -376,7 +376,7 @@ with 对象 变量v = { 变量a -1 变量a( --1) + -1) 变量a \ - 1 变量a-1 @@ -389,7 +389,7 @@ with 对象 变量a ~1 变量a( -~1) + ~1) 变量a \ ~ 1 变量a~1 diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 753ba7b..77643d3 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -876,6 +876,10 @@ private: return false; } + bool isListComp(Comprehension_t* comp) const { + return comp->items.size() == 2 && ast_is(comp->items.back()); + } + void markVarLocalConst(const std::string& name) { auto& scope = _scopes.back(); scope.vars->insert_or_assign(name, VarType::LocalConst); @@ -1474,7 +1478,7 @@ private: if (simpleValue->value.is()) { return true; } else if (auto comp = simpleValue->value.as()) { - if (comp->items.size() != 2 || !ast_is(comp->items.back())) { + if (!isListComp(comp)) { return true; } } @@ -1877,7 +1881,7 @@ private: case id(): transformTry(static_cast(value), out, ExpUsage::Common); break; case id(): { auto comp = static_cast(value); - if (comp->items.size() == 2 && ast_is(comp->items.back())) { + if (isListComp(comp)) { transformCompCommon(comp, out); } else { specialSingleValue = false; @@ -2468,7 +2472,7 @@ private: case id(): { auto comp = static_cast(value); auto expList = assignment->expList.get(); - if (comp->items.size() == 2 && ast_is(comp->items.back())) { + if (isListComp(comp)) { std::string preDefine = getPreDefineLine(assignment); transformComprehension(comp, out, ExpUsage::Assignment, expList); out.back().insert(0, preDefine); @@ -2893,7 +2897,7 @@ private: if (auto tbA = item->get_by_path()) { tableItems = &tbA->values.objects(); } else if (auto tbB = item->get_by_path()) { - if (tbB->items.size() == 2 && ast_is(tbB->items.back())) { + if (isListComp(tbB)) { throw CompileError("invalid destructure value"sv, tbB); } tableItems = &tbB->items.objects(); @@ -2924,7 +2928,7 @@ private: } case id(): { auto table = static_cast(node); - if (table->items.size() == 2 && ast_is(table->items.back())) { + if (isListComp(table)) { throw CompileError("invalid destructure value"sv, table); } tableItems = &table->items.objects(); @@ -3295,7 +3299,7 @@ private: if (auto tab = sVal->value.as()) { destructNode = tab; } else if (auto comp = sVal->value.as()) { - if (comp->items.size() != 2 || !ast_is(comp->items.back())) { + if (!isListComp(comp)) { destructNode = comp; } } @@ -7422,7 +7426,7 @@ private: } } } else if (auto comp = sval->value.as()) { - if (comp->items.size() != 2 || !ast_is(comp->items.back())) { + if (!isListComp(comp)) { discrete = inExp->new_ptr(); for (ast_node* val : comp->items.objects()) { if (auto def = ast_cast(val)) { @@ -8285,7 +8289,7 @@ private: void transformComprehension(Comprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { auto x = comp; - if (comp->items.size() != 2 || !ast_is(comp->items.back())) { + if (!isListComp(comp)) { switch (usage) { case ExpUsage::Assignment: { auto tableLit = x->new_ptr(); diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 1b72a8c..1999721 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -50,6 +50,15 @@ public: } \ } while (false) +#define RaiseErrorI(msg, item) \ + do { \ + if (reinterpret_cast(item.user_data)->lax) { \ + return -1; \ + } else { \ + throw ParserError(msg, item.begin); \ + } \ + } while (false) + // clang-format off YueParser::YueParser() { plain_space = *set(" \t"); @@ -316,14 +325,14 @@ YueParser::YueParser() { for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) { switch (*i) { case '\t': indent += 4; break; - default: RaiseError("can not mix the use of tabs and spaces as indents"sv, item); break; + default: RaiseErrorI("can not mix the use of tabs and spaces as indents"sv, item); break; } } } else { for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) { switch (*i) { case ' ': indent++; break; - default: RaiseError("can not mix the use of tabs and spaces as indents"sv, item); break; + default: RaiseErrorI("can not mix the use of tabs and spaces as indents"sv, item); break; } } } @@ -357,6 +366,12 @@ YueParser::YueParser() { } } State* st = reinterpret_cast(item.user_data); + if (st->indents.empty()) { + RaiseError("unknown indent level"sv, item); + } + if (st->indents.top() > indent) { + RaiseError("unexpected dedent"sv, item); + } st->indents.push(indent); return true; }); @@ -1014,16 +1029,24 @@ YueParser::YueParser() { FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '`' >> space >> Name) >> -(space >> '=' >> space >> Exp) | TableLit | SimpleTable; - check_vararg_position = and_(white >> ')') | white >> -(',' >> white) >> vararg_position_error; + check_vararg_position = and_(white >> (')' | key("using"))) | white >> -(',' >> white) >> vararg_position_error; - FnArgDefList = Seperator >> ( - fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg >> -(space >> '`' >> space >> Name) >> check_vararg_position) | - white >> VarArg >> -(space >> '`' >> space >> Name) >> check_vararg_position - ); + var_arg_def = ( + VarArg | + +space_break >> push_indent_match >> ensure(space >> VarArg >> -(space >> '`' >> space >> Name), pop_indent) + ) >> check_vararg_position; + + FnArgDefList = Seperator >> + -fn_arg_def_list >> + -(-(space >> ',') >> +space_break >> fn_arg_def_lit_lines) >> + -(-(space >> ',') >> space >> var_arg_def); OuterVarShadow = key("using") >> space >> (key("nil") | NameList); - FnArgsDef = '(' >> *space_break >> -FnArgDefList >> -(white >> OuterVarShadow) >> white >> -(and_(',') >> unexpected_comma_error) >> ')'; + outer_var_shadow_def = OuterVarShadow | + +space_break >> push_indent_match >> ensure(space >> OuterVarShadow, pop_indent); + + FnArgsDef = '(' >> space >> -FnArgDefList >> -(space >> outer_var_shadow_def) >> white >> -(and_(',') >> unexpected_comma_error) >> ')'; FnArrow = expr("->") | "=>"; FunLit = pl::user(true_(), [](const item_t& item) { State* st = reinterpret_cast(item.user_data); @@ -1035,11 +1058,11 @@ YueParser::YueParser() { ) >> space >> FnArrow >> -(space >> Body); MacroName = '$' >> UnicodeName; - macro_args_def = '(' >> white >> -FnArgDefList >> white >> -(and_(',') >> unexpected_comma_error) >> ')'; + macro_args_def = '(' >> space >> -FnArgDefList >> white >> -(and_(',') >> unexpected_comma_error) >> ')'; MacroLit = -(macro_args_def >> space) >> "->" >> space >> Body; MacroFunc = MacroName >> (Invoke | InvokeArgs); Macro = key("macro") >> space >> ( - UnicodeName >> space >> '=' >> space >> (MacroLit | MacroFunc | expected_expression_error) | + UnicodeName >> space >> '=' >> space >> (MacroLit | MacroFunc | invalid_macro_definition_error) | invalid_macro_definition_error ); MacroInPlace = '$' >> space >> "->" >> space >> Body; diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 24ae490..b68742f 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -280,6 +280,8 @@ private: NONE_AST_RULE(fn_arg_def_lit_lines); NONE_AST_RULE(destruct_def); NONE_AST_RULE(macro_args_def); + NONE_AST_RULE(var_arg_def); + NONE_AST_RULE(outer_var_shadow_def); NONE_AST_RULE(chain_call); NONE_AST_RULE(chain_call_list); NONE_AST_RULE(chain_index_chain); -- cgit v1.2.3-55-g6feb