From 6db82a69096a48c8b348217b0db6e06b297218ca Mon Sep 17 00:00:00 2001 From: Li Jin <dragon-fly@qq.com> Date: Wed, 9 Nov 2022 11:30:17 +0800 Subject: refactor and update readme and changelog. --- CHANGELOG.md | 51 ++++++++++++++++++++++++ doc/docs/doc/README.md | 89 +++++++++++++++++++++++++++++++++++++----- src/yuescript/yue_compiler.cpp | 9 +++-- src/yuescript/yue_parser.cpp | 18 +++++---- 4 files changed, 148 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33c038b..dedd8e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,57 @@ The implementation for the original Moonscript language 0.5.0 can be found in the `0.5.0` branch of Yuescript. The Moonscript with fixes and new features is in the main branch of Yuescript. Here are the changelogs for each Yuescript version. +## v0.15.12 + +### Added Features + +* yue.to_ast(): Reserve comment nodes followed by a statement in AST structures. +* Added `while` clause line decorator. + ```moonscript + reader\parse_line! until reader\eof! + ``` + compiles to: + ```lua + while not reader:eof() do + reader:parse_line() + end + ``` +* Supported underscores in number literal. `1_000_000`, `0xFF_EF_06` +* Refactored some error messages with details instead of just "syntax error". +* Added chaining assignment. `a = b = c = 0` + +### Fixed Issues + +* Change metable accessing operator to `<>` instead of postfix `#`. + ```moonscript + <>: mt = tb + mt = tb.<> + a = <>: mt, value: 1 + b = :<add>, value: 2 + close _ = <close>: -> print "out of scope" + ``` + compiles to: + ```lua + local mt = getmetatable(tb) + mt = getmetatable(tb) + local a = setmetatable({ + value = 1 + }, mt) + local b = setmetatable({ + value = 2 + }, { + __add = add + }) + local _ <close> = setmetatable({ }, { + __close = function() + return print("out of scope") + end + }) + ``` +* Refactor `continue` keyword implementation with goto statement when targeting Lua version 5.2 and higher. +* Skip utf-8 bom in parser. +* Fixed classes don't inherits metamethods properly. + ## v0.14.5 ### Added Features diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md index f23a407..df9002d 100755 --- a/doc/docs/doc/README.md +++ b/doc/docs/doc/README.md @@ -671,13 +671,14 @@ tb = ### Import -The import statement is a syntax sugar for requiring a module or help extracting items from an imported module. +The import statement is a syntax sugar for requiring a module or help extracting items from an imported module. The imported items are const by default. ```moonscript --- used as table destructure +-- used as table destructuring do - import C, Ct, Cmt from require "lpeg" import insert, concat from table + -- report error when assigning to insert, concat + import C, Ct, Cmt from require "lpeg" -- shortcut for requring a module do @@ -686,7 +687,7 @@ do import "d-a-s-h-e-s" import "module.part" --- requring module with aliasing or table destruction +-- requring module with aliasing or table destructuring do import "player" as PlayerModule import "lpeg" as :C, :Ct, :Cmt @@ -694,10 +695,11 @@ do ``` <YueDisplay> <pre> --- used as table destruction +-- used as table destructuring do - import C, Ct, Cmt from require "lpeg" import insert, concat from table + -- report error when assigning to insert, concat + import C, Ct, Cmt from require "lpeg" -- shortcut for requring a module do @@ -706,7 +708,7 @@ do import "d-a-s-h-e-s" import "module.part" --- requring module with aliasing or table destruction +-- requring module with aliasing or table destructuring do import "player" as PlayerModule import "lpeg" as :C, :Ct, :Cmt @@ -843,6 +845,20 @@ arg or= "default value" </pre> </YueDisplay> +### Chaining Assignment + +You can do chaining assignment to assign multiple items to hold the same value. +```moonscript +a = b = c = d = e = 0 +x = y = z = f! +``` +<YueDisplay> +<pre> +a = b = c = d = e = 0 +x = y = z = f! +</pre> +</YueDisplay> + ### Explicit Locals ```moonscript do @@ -1114,7 +1130,7 @@ else </pre> </YueDisplay> -If assignment with extra return values. +If assignment with multiple return values. Only the first value is getting checked, other values are scoped. ```moonscript if success, result = pcall -> "get result without problems" print result -- variable result is scoped @@ -1246,7 +1262,7 @@ catch err ## Attributes -The syntax support for Lua 5.4 attributes. +Syntax support for Lua 5.4 attributes. But you can use still use `const` declaration and get constant check functioning when targeting Lua versions below 5.4. ```moonscript const a = 123 @@ -1284,6 +1300,22 @@ print "I am #{math.random! * 100}% sure." </pre> </YueDisplay> +### Number Literals + +You can use underscores in a number literal to increase readability. + +```moonscript +integer = 1_000_000 +hex = 0xEF_BB_BF +``` +<YueDisplay> + +<pre> +integer = 1_000_000 +hex = 0xEF_BB_BF +</pre> +</YueDisplay> + ## Function Literals All functions are created using a function expression. A simple function is denoted using the arrow: **->**. @@ -2302,6 +2334,21 @@ print "item: ", item for item in *items </pre> </YueDisplay> +And with while loops: + +```moonscript +game\update! while game\isRunning! + +reader\parse_line! until reader\eof! +``` +<YueDisplay> +<pre> +game\update! while game\isRunning! + +reader\parse_line! until reader\eof! +</pre> +</YueDisplay> + ## Switch The switch statement is shorthand for writing a series of if statements that check against the same value. Note that the value is only evaluated once. Like if statements, switches can have an else block to handle no matches. Comparison is done with the == operator. @@ -2975,6 +3022,30 @@ with str = "Hello" </pre> </YueDisplay> +Accessing special keys with `[]` in a `with` statement. + +```moonscript +with tb + [1] = 1 + print [2] + with [abc] + [3] = [2]\func! + ["key-name"] = value + [] = "abc" -- appending to "tb" +``` +<YueDisplay> +<pre> +with tb + [1] = 1 + print [2] + with [abc] + [3] = [2]\func! + ["key-name"] = value + [] = "abc" -- appending to "tb" +</pre> +</YueDisplay> + + ## Do When used as a statement, do works just like it does in Lua. diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 4072974..f5436d1 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -59,7 +59,7 @@ namespace yue { typedef std::list<std::string> str_list; -const std::string_view version = "0.15.11"sv; +const std::string_view version = "0.15.12"sv; const std::string_view extension = "yue"sv; class YueCompilerImpl { @@ -3769,7 +3769,7 @@ private: if (!_enableReturn.top()) { ast_node* target = returnNode->valueList.get(); if (!target) target = returnNode; - throw std::logic_error(_info.errorMessage("illegal return statement here"sv, target)); + throw std::logic_error(_info.errorMessage("can not mix use of return and export statements in module scope"sv, target)); } if (auto valueList = returnNode->valueList.as<ExpListLow_t>()) { if (valueList->exprs.size() == 1) { @@ -8008,8 +8008,11 @@ private: void transformChainAssign(ChainAssign_t* chainAssign, str_list& out) { auto x = chainAssign; - str_list temp; auto value = chainAssign->assign->values.front(); + if (chainAssign->assign->values.size() != 1) { + throw std::logic_error(_info.errorMessage("only one right value expected"sv, value)); + } + str_list temp; bool constVal = false; if (auto simpleVal = simpleSingleValueFrom(value)) { constVal = ast_is<const_value_t, Num_t>(simpleVal->value); diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index b1f29a9..c8b974f 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -532,17 +532,21 @@ YueParser::YueParser() { return true; }) >> (pl::user(Space >> export_default >> Exp, [](const item_t& item) { State* st = reinterpret_cast<State*>(item.user_data); - bool isValid = !st->exportDefault && st->exportCount == 1; + if (st->exportDefault) { + throw ParserError("export default has already been declared", *item.begin, *item.end); + } + if (st->exportCount > 1) { + throw ParserError("there are items already been exported", *item.begin, *item.end); + } st->exportDefault = true; - return isValid; + return true; }) | (not_(Space >> export_default) >> pl::user(true_(), [](const item_t& item) { State* st = reinterpret_cast<State*>(item.user_data); if (st->exportDefault && st->exportCount > 1) { - return false; - } else { - return true; + throw ParserError("can not export more items when export default has been declared", *item.begin, *item.end); } + return true; }) >> ExpList >> -Assign) | Space >> pl::user(Macro, [](const item_t& item) { State* st = reinterpret_cast<State*>(item.user_data); @@ -631,7 +635,7 @@ YueParser::YueParser() { ) | arg_table_block; leading_spaces_error = pl::user(+space_one >> expr('(') >> Exp >> +(sym(',') >> Exp) >> sym(')'), [](const item_t& item) { - throw ParserError("write invoke arguments in parentheses without leading spaces or leading spaces without parentheses", *item.begin, *item.end); + throw ParserError("write invoke arguments in parentheses without leading spaces or just leading spaces without parentheses", *item.begin, *item.end); return false; }); @@ -707,7 +711,7 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) { res.codes = std::make_unique<input>(); *(res.codes) = _converter.from_bytes(&codes.front(), &codes.back() + 1); } catch (const std::range_error&) { - res.error = "Invalid text encoding."sv; + res.error = "invalid text encoding"sv; return res; } error_list errors; -- cgit v1.2.3-55-g6feb