From 43dde2fff316051d03968e8efd313f19b53112fc Mon Sep 17 00:00:00 2001 From: Li Jin Date: Fri, 21 Nov 2025 12:21:04 +0800 Subject: Updated syntax. * Added error check for mixed use of tabs and spaces. * Supported SimpleTable destructuring for ForEach syntax. --- spec/inputs/destructure.yue | 10 +++++++++ spec/inputs/funcs.yue | 4 ++-- spec/inputs/string.yue | 4 ++-- spec/inputs/unicode/funcs.yue | 2 +- spec/inputs/unicode/vararg.yue | 4 ++-- spec/inputs/vararg.yue | 4 ++-- spec/inputs/with.yue | 4 ++-- spec/outputs/destructure.lua | 20 ++++++++++++++++++ spec/outputs/string.lua | 2 +- src/yuescript/yue_ast.h | 2 +- src/yuescript/yue_compiler.cpp | 26 +++++++++++++----------- src/yuescript/yue_parser.cpp | 46 ++++++++++++++++++++++++++++-------------- src/yuescript/yue_parser.h | 1 + 13 files changed, 89 insertions(+), 40 deletions(-) diff --git a/spec/inputs/destructure.yue b/spec/inputs/destructure.yue index b6250d0..179056c 100644 --- a/spec/inputs/destructure.yue +++ b/spec/inputs/destructure.yue @@ -278,5 +278,15 @@ do do {a, :abc, b, :def, ...sub, d, e} = tb +do + for {:a, :b} in *items + print a, b + + for :a, :b in *items + print a, b + + for :body in pairs data + print body if body + nil diff --git a/spec/inputs/funcs.yue b/spec/inputs/funcs.yue index 6b1669b..d19c2d1 100644 --- a/spec/inputs/funcs.yue +++ b/spec/inputs/funcs.yue @@ -98,7 +98,7 @@ f( x = (a, b) -> - print "what" + print "what" y = (a="hi", @@ -211,7 +211,7 @@ do print "kv:", k, v print "rest count:", select "#", ... macro gen = (fname) -> | - #{fname} = ({:a, :b = 0}) -> print a, b + #{fname} = ({:a, :b = 0}) -> print a, b $gen foo t1 = (:a, x) -> print a, x t2 = (:a) -> print a diff --git a/spec/inputs/string.yue b/spec/inputs/string.yue index 1f0fba8..611205d 100644 --- a/spec/inputs/string.yue +++ b/spec/inputs/string.yue @@ -100,8 +100,8 @@ do next: 123 str = | list: - - "one" - - "two" + - "one" + - "two" str = | -- comment content text diff --git a/spec/inputs/unicode/funcs.yue b/spec/inputs/unicode/funcs.yue index c563356..cb35500 100644 --- a/spec/inputs/unicode/funcs.yue +++ b/spec/inputs/unicode/funcs.yue @@ -98,7 +98,7 @@ _无效变量 = -> 真名 if 某物 变量x = (参数a, 参数b) -> - 打印 "什么" + 打印 "什么" 变量y = (参数a="hi", diff --git a/spec/inputs/unicode/vararg.yue b/spec/inputs/unicode/vararg.yue index e59e114..b508fbb 100644 --- a/spec/inputs/unicode/vararg.yue +++ b/spec/inputs/unicode/vararg.yue @@ -55,12 +55,12 @@ _ = -> 列表 = {1, 2, 3, 4, 5} 函数名 = (确定) -> - 确定, table.unpack 列表 + 确定, table.unpack 列表 确定, ... = 函数名 true 打印 确定, ... 多参数函数 = -> - 10, nil, 20, nil, 30 + 10, nil, 20, nil, 30 ... = 多参数函数! 打印 select "#", ... diff --git a/spec/inputs/vararg.yue b/spec/inputs/vararg.yue index 941cd97..6100250 100644 --- a/spec/inputs/vararg.yue +++ b/spec/inputs/vararg.yue @@ -55,12 +55,12 @@ join = (...) -> _ = -> list = {1, 2, 3, 4, 5} fn = (ok) -> - ok, table.unpack list + ok, table.unpack list ok, ... = fn true print ok, ... fn_many_args = -> - 10, nil, 20, nil, 30 + 10, nil, 20, nil, 30 ... = fn_many_args! print select "#", ... diff --git a/spec/inputs/with.yue b/spec/inputs/with.yue index 2256833..19ed2a7 100644 --- a/spec/inputs/with.yue +++ b/spec/inputs/with.yue @@ -167,7 +167,7 @@ do do a = for i = 1, 100 - with? x := tb[i] - break x if .id := 1 + with? x := tb[i] + break x if .id := 1 nil diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua index ba216b5..4e19aca 100644 --- a/spec/outputs/destructure.lua +++ b/spec/outputs/destructure.lua @@ -711,4 +711,24 @@ do return _accum_0 end)(), _obj_0[#_obj_0 - 1], _obj_0[#_obj_0] end +do + local _list_0 = items + for _index_0 = 1, #_list_0 do + local _des_0 = _list_0[_index_0] + local a, b = _des_0.a, _des_0.b + print(a, b) + end + local _list_1 = items + for _index_0 = 1, #_list_1 do + local _des_0 = _list_1[_index_0] + local a, b = _des_0.a, _des_0.b + print(a, b) + end + for _des_0 in pairs(data) do + local body = _des_0.body + if body then + print(body) + end + end +end return nil diff --git a/spec/outputs/string.lua b/spec/outputs/string.lua index b536e6d..bdfd676 100644 --- a/spec/outputs/string.lua +++ b/spec/outputs/string.lua @@ -52,7 +52,7 @@ do str = "user: " .. tostring(name) .. "\nid: " .. tostring(id) str = "path: \"C:\\\\Program Files\\\\App\"\ndesc: 'single \"quote\" test'" str = "key: value \nnext: 123 " - str = "list:\n - \"one\"\n - \"two\"" + str = "list:\n\t- \"one\"\n\t- \"two\"" str = "-- comment\ncontent text\n-- comment" str = tostring(1 + 2) .. '\n' .. tostring(2 + 3) .. '\n' .. tostring("a" .. "b") local obj = { diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 0008fd6..5f04fa0 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h @@ -848,7 +848,7 @@ AST_NODE(Macro) AST_END(Macro) AST_NODE(NameOrDestructure) - ast_sel item; + ast_sel item; AST_MEMBER(NameOrDestructure, &item) AST_END(NameOrDestructure) diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index d6db3fc..55ab4ec 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.29.8"sv; +const std::string_view version = "0.29.9"sv; const std::string_view extension = "yue"sv; class CompileError : public std::logic_error { @@ -8427,13 +8427,8 @@ private: varConstAfter = vars.back(); } break; - case id(): { - auto desVar = getUnusedName("_des_"sv); - destructPairs.emplace_back(item, toAst(desVar, x)); - vars.push_back(desVar); - varAfter.push_back(desVar); - break; - } + case id(): + case id(): case id(): { auto desVar = getUnusedName("_des_"sv); destructPairs.emplace_back(item, toAst(desVar, x)); @@ -8642,11 +8637,18 @@ private: if (!destructPairs.empty()) { temp.clear(); for (auto& pair : destructPairs) { - auto sValue = x->new_ptr(); - sValue->value.set(pair.first); - auto exp = newExp(sValue, x); auto expList = x->new_ptr(); - expList->exprs.push_back(exp); + if (ast_is(pair.first)) { + auto value = x->new_ptr(); + value->item.set(pair.first); + auto exp = newExp(value, x); + expList->exprs.push_back(exp); + } else { + auto sValue = x->new_ptr(); + sValue->value.set(pair.first); + auto exp = newExp(sValue, x); + expList->exprs.push_back(exp); + } auto assign = x->new_ptr(); assign->values.push_back(pair.second); auto assignment = x->new_ptr(); diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index fccb6fb..cbba115 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -232,27 +232,43 @@ YueParser::YueParser() { KeyName = SelfItem | Name | UnicodeName; VarArg = "..."; - check_indent = pl::user(plain_space, [](const item_t& item) { + auto getIndent = [](const item_t& item) -> int { + if (item.begin->m_it == item.end->m_it) return 0; + State* st = reinterpret_cast(item.user_data); + bool useTab = false; + if (st->useTab) { + useTab = st->useTab.value(); + } else { + useTab = *item.begin->m_it == '\t'; + st->useTab = useTab; + } int indent = 0; - for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) { - switch (*i) { - case ' ': indent++; break; - case '\t': indent += 4; break; + if (useTab) { + for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) { + switch (*i) { + case '\t': indent += 4; break; + default: throw ParserError("can not mix the use of tabs and spaces as indents"sv, item.begin); break; + } + } + } else { + for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) { + switch (*i) { + case ' ': indent++; break; + default: throw ParserError("can not mix the use of tabs and spaces as indents"sv, item.begin); break; + } } } + return indent; + }; + + check_indent = pl::user(plain_space, [getIndent](const item_t& item) { State* st = reinterpret_cast(item.user_data); - return st->indents.top() == indent; + return st->indents.top() == getIndent(item); }); check_indent_match = and_(check_indent); - advance = pl::user(plain_space, [](const item_t& item) { - int indent = 0; - for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) { - switch (*i) { - case ' ': indent++; break; - case '\t': indent += 4; break; - } - } + advance = pl::user(plain_space, [getIndent](const item_t& item) { + int indent = getIndent(item); State* st = reinterpret_cast(item.user_data); int top = st->indents.top(); if (top != -1 && indent > top) { @@ -921,7 +937,7 @@ YueParser::YueParser() { MacroInPlace = '$' >> space >> "->" >> space >> Body; NameList = Seperator >> Variable >> *(space >> ',' >> space >> Variable); - NameOrDestructure = Variable | TableLit | Comprehension; + NameOrDestructure = Variable | TableLit | Comprehension | SimpleTable; AssignableNameList = Seperator >> NameOrDestructure >> *(space >> ',' >> space >> NameOrDestructure); FnArrowBack = '<' >> set("-="); diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 4c546b1..d5c37e2 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -119,6 +119,7 @@ protected: int expLevel = 0; size_t stringOpen = 0; std::string buffer; + std::optional useTab; std::stack indents; std::vector noDoStack; std::vector noChainBlockStack; -- cgit v1.2.3-55-g6feb