From 5604bbbb80bfcedb4a9085b90864e221f8104b33 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Wed, 28 May 2025 18:20:16 +0800 Subject: Added `try!` syntax. --- doc/docs/doc/README.md | 65 ++++++-- doc/docs/zh/doc/README.md | 41 +++++ spec/inputs/try_catch.yue | 122 +++++++++++++- spec/outputs/5.1/try_catch.lua | 265 +++++++++++++++++++++++++++++- spec/outputs/assign.lua | 6 +- spec/outputs/codes_from_doc.lua | 100 ++++++++++++ spec/outputs/codes_from_doc_zh.lua | 100 ++++++++++++ spec/outputs/try_catch.lua | 266 ++++++++++++++++++++++++++++++- spec/outputs/unicode/assign.lua | 6 +- spec/outputs/unicode/macro.lua | 46 +++--- spec/outputs/unicode/multiline_chain.lua | 6 +- spec/outputs/unicode/syntax.lua | 6 +- spec/outputs/unicode/vararg.lua | 28 +--- spec/outputs/upvalue_func.lua | 48 +++--- spec/outputs/vararg.lua | 28 +--- src/yuescript/yue_ast.cpp | 10 +- src/yuescript/yue_ast.h | 6 +- src/yuescript/yue_compiler.cpp | 155 +++++++++++++----- src/yuescript/yue_compiler.h | 1 + src/yuescript/yue_parser.cpp | 25 +-- src/yuescript/yue_parser.h | 13 +- src/yuescript/yuescript.cpp | 15 +- 22 files changed, 1169 insertions(+), 189 deletions(-) diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md index a970baa..1d9c8ad 100755 --- a/doc/docs/doc/README.md +++ b/doc/docs/doc/README.md @@ -1243,7 +1243,7 @@ If the destructuring statement is complicated, feel free to spread it out over a -It’s common to extract values from at table and assign them the local variables that have the same name as the key. In order to avoid repetition we can use the **:** prefix operator: +It's common to extract values from at table and assign them the local variables that have the same name as the key. In order to avoid repetition we can use the **:** prefix operator: ```moonscript {:concat, :insert} = table @@ -1516,6 +1516,47 @@ catch err +### Try! + +`try!` is a more concise error handling syntax that omit the boolean status from the `try` statement, and it will return the result from the try block when success, otherwise return nil instead of error object. + +```moonscript +a, b, c = try! func! + +-- with nil coalescing operator +a = (try! func!) ?? "default" + +-- as function argument +f try! func! + +-- with catch block +f try! + print 123 + func! +catch e + print e + e +``` + +
+a, b, c = try! func!
+
+-- with nil coalescing operator
+a = (try! func!) ?? "default"
+
+-- as function argument
+f try! func!
+
+-- with catch block
+f try!
+  print 123
+  func!
+catch e
+  print e
+  e
+
+
+ ## Attributes Syntax support for Lua 5.4 attributes. And you can still use both the `const` and `close` declaration and get constant check and scoped callback working when targeting Lua versions below 5.4. @@ -2417,7 +2458,7 @@ print func_b! -- prints table object -This is done to avoid the needless creation of tables for functions that don’t need to return the results of the loop. +This is done to avoid the needless creation of tables for functions that don't need to return the results of the loop. ## Repeat Loop @@ -2746,7 +2787,7 @@ next_number = switch b -We can use the then keyword to write a switch’s when block on a single line. No extra keyword is needed to write the else block on a single line. +We can use the then keyword to write a switch's when block on a single line. No extra keyword is needed to write the else block on a single line. ```moonscript msg = switch math.random(1, 5) @@ -2792,7 +2833,7 @@ else -It is worth noting the order of the case comparison expression. The case’s expression is on the left hand side. This can be useful if the case’s expression wants to overwrite how the comparison is done by defining an eq metamethod. +It is worth noting the order of the case comparison expression. The case's expression is on the left hand side. This can be useful if the case's expression wants to overwrite how the comparison is done by defining an eq metamethod. ### Table Matching @@ -3079,7 +3120,7 @@ class BackPack extends Inventory Here we extend our Inventory class, and limit the amount of items it can carry. -In this example, we don’t define a constructor on the subclass, so the parent class' constructor is called when we make a new instance. If we did define a constructor then we can use the super method to call the parent constructor. +In this example, we don't define a constructor on the subclass, so the parent class' constructor is called when we make a new instance. If we did define a constructor then we can use the super method to call the parent constructor. Whenever a class inherits from another, it sends a message to the parent class by calling the method __inherited on the parent class if it exists. The function receives two arguments, the class that is being inherited and the child class. @@ -3166,13 +3207,13 @@ print BackPack.size -- prints 10 The class object is what we create when we use a class statement. The class object is stored in a variable of the same name of the class. -The class object can be called like a function in order to create new instances. That’s how we created instances of classes in the examples above. +The class object can be called like a function in order to create new instances. That's how we created instances of classes in the examples above. A class is made up of two tables. The class table itself, and the base table. The base is used as the metatable for all the instances. All properties listed in the class declaration are placed in the base. -The class object’s metatable reads properties from the base if they don’t exist in the class object. This means we can access functions and properties directly from the class. +The class object's metatable reads properties from the base if they don't exist in the class object. This means we can access functions and properties directly from the class. -It is important to note that assigning to the class object does not assign into the base, so it’s not a valid way to add new methods to instances. Instead the base must explicitly be changed. See the __base field below. +It is important to note that assigning to the class object does not assign into the base, so it's not a valid way to add new methods to instances. Instead the base must explicitly be changed. See the __base field below. The class object has a couple special properties: @@ -3245,7 +3286,7 @@ print Counter.count -- prints 2 -The calling semantics of @@ are similar to @. Calling a @@ name will pass the class in as the first argument using Lua’s colon syntax. +The calling semantics of @@ are similar to @. Calling a @@ name will pass the class in as the first argument using Lua's colon syntax. ```moonscript @@hello 1,2,3,4 @@ -3260,7 +3301,7 @@ The calling semantics of @@ are similar to @. Calling a @@ name will pass the cl In the body of a class declaration, we can have normal expressions in addition to key/value pairs. In this context, self is equal to the class object. -Here is an alternative way to create a class variable compared to what’s described above: +Here is an alternative way to create a class variable compared to what's described above: ```moonscript class Things @@ -3593,7 +3634,7 @@ print var -- nil here -YueScript’s **do** can also be used an expression . Allowing you to combine multiple lines into one. The result of the do expression is the last statement in its body. +YueScript's **do** can also be used an expression . Allowing you to combine multiple lines into one. The result of the do expression is the last statement in its body. ```moonscript counter = do @@ -3719,7 +3760,7 @@ print i -- will print 0 -In my_func, we've overwritten the value of i mistakenly. In this example it is quite obvious, but consider a large, or foreign code base where it isn’t clear what names have already been declared. +In my_func, we've overwritten the value of i mistakenly. In this example it is quite obvious, but consider a large, or foreign code base where it isn't clear what names have already been declared. It would be helpful to say which variables from the enclosing scope we intend on change, in order to prevent us from changing others by accident. diff --git a/doc/docs/zh/doc/README.md b/doc/docs/zh/doc/README.md index 2d4af18..0fa1fed 100755 --- a/doc/docs/zh/doc/README.md +++ b/doc/docs/zh/doc/README.md @@ -1514,6 +1514,47 @@ catch err +### 错误处理简化 + +`try!` 是 `try` 的简化语法,它不再返回 `try` 语句的布尔状态,并在成功时直接返回 `try` 代码块的结果,失败时返回 `nil` 值而非错误对象。 + +```moonscript +a, b, c = try! func! + +-- 与空值合并运算符一起使用 +a = (try! func!) ?? "default" + +-- 作为函数参数 +f try! func! + +-- 带 catch 块的 try! +f try! + print 123 + func! +catch e + print e + e +``` + +
+a, b, c = try! func!
+
+-- 与空值合并运算符一起使用
+a = (try! func!) ?? "default"
+
+-- 作为函数参数
+f try! func!
+
+-- 带 catch 块的 try!
+f try!
+  print 123
+  func!
+catch e
+  print e
+  e
+
+
+ ## 属性 月之脚本现在提供了Lua 5.4新增的叫做属性的语法支持。在月之脚本编译到的Lua目标版本低于5.4时,你仍然可以同时使用`const`和`close`的属性声明语法,并获得常量检查和作用域回调的功能。 diff --git a/spec/inputs/try_catch.yue b/spec/inputs/try_catch.yue index 4e05bc6..f2583b7 100644 --- a/spec/inputs/try_catch.yue +++ b/spec/inputs/try_catch.yue @@ -62,6 +62,126 @@ f = -> do <- x local tb, a, b, c - f = -> try tb.f a, b, c + f1 = -> try tb.f a, b, c + + do + f1 = -> do + ok, ... = try func! + ... + + do + local func + a, b, c = try! func! + + do + a, b, c = try! func! + + do + a = (try! func!) ?? "default" + + do + f try! func! + + do + f try! + print 123 + func! + catch e + print e + e nil + +do + try + func 1, 2, 3 + catch err + print err + + try func 1, 2, 3 + catch err + print err + + try + print "trying" + func 1, 2, 3 + + do + success, result = try + func 1, 2, 3 + catch err + print err + + success, result = try func 1, 2, 3 + + tb = {} + + try tb.func + try tb.func! + try tb.func() + try (tb.func!) + try (tb\func(1, 2, 3)) + + try tb.func 1 + try tb.func(1) + + if (try func 1 + catch err + print err) + print "OK" + + if try (func 1) + catch err + print err + print "OK" + + do + if success, result := try func "abc", 123 + print result + + success, result = try func "abc", 123 + catch err + print err + + print result if success, result := try func "abc", 123 + catch err + print err + + do + try + func 1, 2, 3 + + try func 1, 2, 3 + + do + <- x + local tb, a, b, c + f1 = -> try tb.f a, b, c + + do + f1 = -> do + ok, ... = try func! + ... + + do + local func + a, b, c = try! func! + + do + a, b, c = try! func! + + do + a = (try! func!) ?? "default" + + do + f try! func! + + do + f try! + print 123 + func! + catch e + print e + e + +nil diff --git a/spec/outputs/5.1/try_catch.lua b/spec/outputs/5.1/try_catch.lua index efd92c6..d2b58bc 100644 --- a/spec/outputs/5.1/try_catch.lua +++ b/spec/outputs/5.1/try_catch.lua @@ -22,6 +22,43 @@ end local _anon_func_7 = function(a, b, c, tb) return tb.f(a, b, c) end +local _anon_func_8 = function(_arg_0, ...) + local ok = _arg_0 + return ... +end +local _anon_func_10 = function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end +end +local _anon_func_9 = function(func, pcall) + return _anon_func_10(pcall(func)) +end +local _anon_func_12 = function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end +end +local _anon_func_11 = function(func, pcall) + return _anon_func_12(pcall(func)) +end +local _anon_func_14 = function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end +end +local _anon_func_13 = function(func, print, xpcall) + return _anon_func_14(xpcall(function() + print(123) + return func() + end, function(e) + print(e) + return e + end)) +end local f f = function() xpcall(function() @@ -104,10 +141,236 @@ f = function() do x(function() local tb, a, b, c - f = function() + local f1 + f1 = function() return pcall(_anon_func_7, a, b, c, tb) end end) end + do + local f1 + f1 = function() + do + return _anon_func_8(pcall(function() + return func() + end)) + end + end + end + do + local func + local a, b, c + local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(func) + if _ok_0 then + a, b, c = _ret_0, _ret_1, _ret_2 + end + end + do + local a, b, c + local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() + return func() + end) + if _ok_0 then + a, b, c = _ret_0, _ret_1, _ret_2 + end + end + do + local a + local _exp_0 = (_anon_func_9(func, pcall)) + if _exp_0 ~= nil then + a = _exp_0 + else + a = "default" + end + end + do + f(_anon_func_11(func, pcall)) + end + do + f(_anon_func_13(func, print, xpcall)) + end return nil end +local _anon_func_15 = function(a, b, c, tb) + return tb.f(a, b, c) +end +local _anon_func_16 = function(_arg_0, ...) + local ok = _arg_0 + return ... +end +do + xpcall(function() + return func(1, 2, 3) + end, function(err) + return print(err) + end) + xpcall(function() + return func(1, 2, 3) + end, function(err) + return print(err) + end) + pcall(function() + print("trying") + return func(1, 2, 3) + end) + do + local success, result = xpcall(function() + return func(1, 2, 3) + end, function(err) + return print(err) + end) + success, result = pcall(function() + return func(1, 2, 3) + end) + end + local tb = { } + pcall(function() + return tb.func + end) + pcall(function() + return tb.func() + end) + pcall(function() + return tb.func() + end) + pcall(function() + return (tb.func()) + end) + pcall(function() + return (tb:func(1, 2, 3)) + end) + pcall(function() + return tb.func(1) + end) + pcall(function() + return tb.func(1) + end) + if (xpcall(function() + return func(1) + end, function(err) + return print(err) + end)) then + print("OK") + end + if xpcall(function() + return (func(1)) + end, function(err) + return print(err) + end) then + print("OK") + end + do + do + local success, result = pcall(function() + return func("abc", 123) + end) + if success then + print(result) + end + end + local success, result = xpcall(function() + return func("abc", 123) + end, function(err) + return print(err) + end) + success, result = xpcall(function() + return func("abc", 123) + end, function(err) + return print(err) + end) + if success then + print(result) + end + end + do + pcall(function() + return func(1, 2, 3) + end) + pcall(function() + return func(1, 2, 3) + end) + end + do + x(function() + local tb, a, b, c + local f1 + f1 = function() + return pcall(_anon_func_15, a, b, c, tb) + end + end) + end + do + local f1 + f1 = function() + do + return _anon_func_16(pcall(function() + return func() + end)) + end + end + end + do + local func + local a, b, c + local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(func) + if _ok_0 then + a, b, c = _ret_0, _ret_1, _ret_2 + end + end + do + local a, b, c + local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() + return func() + end) + if _ok_0 then + a, b, c = _ret_0, _ret_1, _ret_2 + end + end + do + local a + local _exp_0 = ((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(pcall(function() + return func() + end)) + end)()) + if _exp_0 ~= nil then + a = _exp_0 + else + a = "default" + end + end + do + f((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(pcall(function() + return func() + end)) + end)()) + end + do + f((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(xpcall(function() + print(123) + return func() + end, function(e) + print(e) + return e + end)) + end)()) + end +end +return nil diff --git a/spec/outputs/assign.lua b/spec/outputs/assign.lua index 162c5a8..89c5f8a 100644 --- a/spec/outputs/assign.lua +++ b/spec/outputs/assign.lua @@ -43,10 +43,8 @@ do end end local _anon_func_0 = function(print) - do - print(123) - return { } - end + print(123) + return { } end return _(function() setmetatable(a, _anon_func_0(print)) diff --git a/spec/outputs/codes_from_doc.lua b/spec/outputs/codes_from_doc.lua index 55be7df..cce0516 100644 --- a/spec/outputs/codes_from_doc.lua +++ b/spec/outputs/codes_from_doc.lua @@ -688,6 +688,56 @@ end) if success then print(result) end +local a, b, c +do + local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() + return func() + end) + if _ok_0 then + a, b, c = _ret_0, _ret_1, _ret_2 + end +end +do + local _exp_0 = ((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(pcall(function() + return func() + end)) + end)()) + if _exp_0 ~= nil then + a = _exp_0 + else + a = "default" + end +end +f((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(pcall(function() + return func() + end)) +end)()) +f((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(xpcall(function() + print(123) + return func() + end, function(e) + print(e) + return e + end)) +end)()) local a = 123 local _ = setmetatable({ }, { __close = function() @@ -2909,6 +2959,56 @@ end) if success then print(result) end +local a, b, c +do + local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() + return func() + end) + if _ok_0 then + a, b, c = _ret_0, _ret_1, _ret_2 + end +end +do + local _exp_0 = ((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(pcall(function() + return func() + end)) + end)()) + if _exp_0 ~= nil then + a = _exp_0 + else + a = "default" + end +end +f((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(pcall(function() + return func() + end)) +end)()) +f((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(xpcall(function() + print(123) + return func() + end, function(e) + print(e) + return e + end)) +end)()) local a = 123 local _ = setmetatable({ }, { __close = function() diff --git a/spec/outputs/codes_from_doc_zh.lua b/spec/outputs/codes_from_doc_zh.lua index 399f8c1..e267709 100644 --- a/spec/outputs/codes_from_doc_zh.lua +++ b/spec/outputs/codes_from_doc_zh.lua @@ -688,6 +688,56 @@ end) if success then print(result) end +local a, b, c +do + local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() + return func() + end) + if _ok_0 then + a, b, c = _ret_0, _ret_1, _ret_2 + end +end +do + local _exp_0 = ((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(pcall(function() + return func() + end)) + end)()) + if _exp_0 ~= nil then + a = _exp_0 + else + a = "default" + end +end +f((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(pcall(function() + return func() + end)) +end)()) +f((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(xpcall(function() + print(123) + return func() + end, function(e) + print(e) + return e + end)) +end)()) local a = 123 local _ = setmetatable({ }, { __close = function() @@ -2903,6 +2953,56 @@ end) if success then print(result) end +local a, b, c +do + local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() + return func() + end) + if _ok_0 then + a, b, c = _ret_0, _ret_1, _ret_2 + end +end +do + local _exp_0 = ((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(pcall(function() + return func() + end)) + end)()) + if _exp_0 ~= nil then + a = _exp_0 + else + a = "default" + end +end +f((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(pcall(function() + return func() + end)) +end)()) +f((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(xpcall(function() + print(123) + return func() + end, function(e) + print(e) + return e + end)) +end)()) local a = 123 local _ = setmetatable({ }, { __close = function() diff --git a/spec/outputs/try_catch.lua b/spec/outputs/try_catch.lua index efd92c6..edb2341 100644 --- a/spec/outputs/try_catch.lua +++ b/spec/outputs/try_catch.lua @@ -22,6 +22,44 @@ end local _anon_func_7 = function(a, b, c, tb) return tb.f(a, b, c) end +local _anon_func_8 = function(_arg_0, ...) + local ok = _arg_0 + return ... +end +local _anon_func_10 = function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end +end +local _anon_func_9 = function(func, pcall) + return _anon_func_10(pcall(func)) +end +local _anon_func_12 = function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end +end +local _anon_func_11 = function(func, pcall) + return _anon_func_12(pcall(func)) +end +local _anon_func_14 = function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end +end +local _anon_func_15 = function(func, print) + print(123) + return func() +end +local _anon_func_13 = function(func, print, xpcall) + return _anon_func_14(xpcall(_anon_func_15, function(e) + print(e) + return e + end, func, print)) +end local f f = function() xpcall(function() @@ -104,10 +142,236 @@ f = function() do x(function() local tb, a, b, c - f = function() + local f1 + f1 = function() return pcall(_anon_func_7, a, b, c, tb) end end) end + do + local f1 + f1 = function() + do + return _anon_func_8(pcall(function() + return func() + end)) + end + end + end + do + local func + local a, b, c + local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(func) + if _ok_0 then + a, b, c = _ret_0, _ret_1, _ret_2 + end + end + do + local a, b, c + local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() + return func() + end) + if _ok_0 then + a, b, c = _ret_0, _ret_1, _ret_2 + end + end + do + local a + local _exp_0 = (_anon_func_9(func, pcall)) + if _exp_0 ~= nil then + a = _exp_0 + else + a = "default" + end + end + do + f(_anon_func_11(func, pcall)) + end + do + f(_anon_func_13(func, print, xpcall)) + end return nil end +local _anon_func_16 = function(a, b, c, tb) + return tb.f(a, b, c) +end +local _anon_func_17 = function(_arg_0, ...) + local ok = _arg_0 + return ... +end +do + xpcall(function() + return func(1, 2, 3) + end, function(err) + return print(err) + end) + xpcall(function() + return func(1, 2, 3) + end, function(err) + return print(err) + end) + pcall(function() + print("trying") + return func(1, 2, 3) + end) + do + local success, result = xpcall(function() + return func(1, 2, 3) + end, function(err) + return print(err) + end) + success, result = pcall(function() + return func(1, 2, 3) + end) + end + local tb = { } + pcall(function() + return tb.func + end) + pcall(function() + return tb.func() + end) + pcall(function() + return tb.func() + end) + pcall(function() + return (tb.func()) + end) + pcall(function() + return (tb:func(1, 2, 3)) + end) + pcall(function() + return tb.func(1) + end) + pcall(function() + return tb.func(1) + end) + if (xpcall(function() + return func(1) + end, function(err) + return print(err) + end)) then + print("OK") + end + if xpcall(function() + return (func(1)) + end, function(err) + return print(err) + end) then + print("OK") + end + do + do + local success, result = pcall(function() + return func("abc", 123) + end) + if success then + print(result) + end + end + local success, result = xpcall(function() + return func("abc", 123) + end, function(err) + return print(err) + end) + success, result = xpcall(function() + return func("abc", 123) + end, function(err) + return print(err) + end) + if success then + print(result) + end + end + do + pcall(function() + return func(1, 2, 3) + end) + pcall(function() + return func(1, 2, 3) + end) + end + do + x(function() + local tb, a, b, c + local f1 + f1 = function() + return pcall(_anon_func_16, a, b, c, tb) + end + end) + end + do + local f1 + f1 = function() + do + return _anon_func_17(pcall(function() + return func() + end)) + end + end + end + do + local func + local a, b, c + local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(func) + if _ok_0 then + a, b, c = _ret_0, _ret_1, _ret_2 + end + end + do + local a, b, c + local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() + return func() + end) + if _ok_0 then + a, b, c = _ret_0, _ret_1, _ret_2 + end + end + do + local a + local _exp_0 = ((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(pcall(function() + return func() + end)) + end)()) + if _exp_0 ~= nil then + a = _exp_0 + else + a = "default" + end + end + do + f((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(pcall(function() + return func() + end)) + end)()) + end + do + f((function() + return (function(_arg_0, ...) + local _ok_0 = _arg_0 + if _ok_0 then + return ... + end + end)(xpcall(function() + print(123) + return func() + end, function(e) + print(e) + return e + end)) + end)()) + end +end +return nil diff --git a/spec/outputs/unicode/assign.lua b/spec/outputs/unicode/assign.lua index d4ad56a..e00d016 100644 --- a/spec/outputs/unicode/assign.lua +++ b/spec/outputs/unicode/assign.lua @@ -43,10 +43,8 @@ do end end local _anon_func_0 = function(_u6253_u5370) - do - _u6253_u5370(123) - return { } - end + _u6253_u5370(123) + return { } end return __u65e0_u6548_u53d8_u91cf(function() setmetatable(a_u53d8_u91cf, _anon_func_0(_u6253_u5370)) diff --git a/spec/outputs/unicode/macro.lua b/spec/outputs/unicode/macro.lua index 3b9327a..b4e78cd 100644 --- a/spec/outputs/unicode/macro.lua +++ b/spec/outputs/unicode/macro.lua @@ -216,17 +216,15 @@ do end local _ = require('下划线') local _anon_func_0 = function(_) - do - local _call_0 = (_({ - 1, - 2, - 3, - 4, - -2, - 3 - })) - return _call_0["链"](_call_0) - end + local _call_0 = (_({ + 1, + 2, + 3, + 4, + -2, + 3 + })) + return _call_0["链"](_call_0) end local _call_0 = ((function() local _call_0 = ((function() @@ -241,17 +239,15 @@ local _call_0 = ((function() end)()) local _u7ed3_u679ca = _call_0["取值"](_call_0) local _anon_func_1 = function(_) - do - local _call_1 = (_({ - 1, - 2, - 3, - 4, - -2, - 3 - })) - return _call_1["链"](_call_1) - end + local _call_1 = (_({ + 1, + 2, + 3, + 4, + -2, + 3 + })) + return _call_1["链"](_call_1) end do local _call_1 = ((function() @@ -270,10 +266,8 @@ do end) end local _anon_func_2 = function(_u539f_u70b9) - do - local _call_1 = _u539f_u70b9["变换"]["根节点"]["游戏对象"] - return _call_1["父节点"](_call_1) - end + local _call_1 = _u539f_u70b9["变换"]["根节点"]["游戏对象"] + return _call_1["父节点"](_call_1) end local _call_1 = ((function() local _call_1 = ((function() diff --git a/spec/outputs/unicode/multiline_chain.lua b/spec/outputs/unicode/multiline_chain.lua index c1da13f..61e7057 100644 --- a/spec/outputs/unicode/multiline_chain.lua +++ b/spec/outputs/unicode/multiline_chain.lua @@ -59,10 +59,8 @@ _u51fd_u6570 = function() return _accum_0 end local _anon_func_0 = function(_u53d8_u91cfa) - do - local _call_1 = _u53d8_u91cfa - return (_call_1["变量b"](_call_1, 123))["变量c"]("abc") - end + local _call_1 = _u53d8_u91cfa + return (_call_1["变量b"](_call_1, 123))["变量c"]("abc") end local _u51fd_u65701 _u51fd_u65701 = function() diff --git a/spec/outputs/unicode/syntax.lua b/spec/outputs/unicode/syntax.lua index 1984f40..a13302b 100644 --- a/spec/outputs/unicode/syntax.lua +++ b/spec/outputs/unicode/syntax.lua @@ -286,10 +286,8 @@ _ = 5 - _u4ec0_u4e48(_u65e0_u804a) _u4ec0_u4e48(_u65e0_u804a - 5) _u53d8_u91cfx = _u4f60_u597d - _u4e16_u754c - _u67d0_u7269 local _anon_func_0 = function(_u4ec0_u4e48) - do - local _call_8 = _u4ec0_u4e48 - return _call_8["酷"](_call_8, 100) - end + local _call_8 = _u4ec0_u4e48 + return _call_8["酷"](_call_8, 100) end (function(_u67d0_u7269) if _u67d0_u7269 == nil then diff --git a/spec/outputs/unicode/vararg.lua b/spec/outputs/unicode/vararg.lua index b837006..fc894ff 100644 --- a/spec/outputs/unicode/vararg.lua +++ b/spec/outputs/unicode/vararg.lua @@ -125,14 +125,10 @@ local _anon_func_11 = function(_u9879_u76ee, ...) return _tbl_0 end local _anon_func_12 = function(_u51fd_u6570) - do - return _u51fd_u6570() - end + return _u51fd_u6570() end local _anon_func_13 = function(_u51fd_u6570, ...) - do - return _u51fd_u6570(...) - end + return _u51fd_u6570(...) end local _anon_func_14 = function(_u51fd_u6570) local _accum_0 = { } @@ -195,15 +191,11 @@ local _anon_func_23 = function(_u51fd_u6570, ...) return nil end local _anon_func_24 = function(_u6253_u5370, select, ...) - do - _u6253_u5370(select("#", ...)) - return _u6253_u5370(...) - end + _u6253_u5370(select("#", ...)) + return _u6253_u5370(...) end local _anon_func_25 = function(_u6253_u5370, ...) - do - return _u6253_u5370(...) - end + return _u6253_u5370(...) end local _anon_func_26 = function(_u53d8_u91cfx, _u8868, _u88682) if 1 == _u53d8_u91cfx then @@ -214,9 +206,7 @@ local _anon_func_26 = function(_u53d8_u91cfx, _u8868, _u88682) end end local _anon_func_27 = function(_u6253_u5370, ...) - do - return _u6253_u5370(...) - end + return _u6253_u5370(...) end local _anon_func_28 = function(_u6761_u4ef6) if _u6761_u4ef6 then @@ -224,10 +214,8 @@ local _anon_func_28 = function(_u6761_u4ef6) end end local _anon_func_29 = function(_u6253_u5370, _arg_0, ...) - do - local _u8868 = _arg_0 - return _u6253_u5370(...) - end + local _u8868 = _arg_0 + return _u6253_u5370(...) end local _u8fde_u63a5 _u8fde_u63a5 = function(...) diff --git a/spec/outputs/upvalue_func.lua b/spec/outputs/upvalue_func.lua index 3181adf..3e088be 100644 --- a/spec/outputs/upvalue_func.lua +++ b/spec/outputs/upvalue_func.lua @@ -214,10 +214,8 @@ local _anon_func_1 = function(valueB) end end local _anon_func_2 = function(print, select, _arg_0, ...) - do - local ok = _arg_0 - return print(select(3, ...)) - end + local ok = _arg_0 + return print(select(3, ...)) end local _anon_func_3 = function(tb) if tb ~= nil then @@ -242,11 +240,9 @@ local _anon_func_5 = function(getmetatable, tb) return _obj_0[1 + 1](_obj_0, "abc") end local _anon_func_6 = function(tb) - do - local _call_0 = tb - local _call_1 = _call_0["end"](_call_0) - return _call_1["🤣"](_call_1, 123) - end + local _call_0 = tb + local _call_1 = _call_0["end"](_call_0) + return _call_1["🤣"](_call_1, 123) end local _anon_func_7 = function(itemA, listA) for _index_0 = 1, #listA do @@ -354,17 +350,13 @@ local _anon_func_16 = function(pairs, tb, tostring) return _tbl_0 end local _anon_func_17 = function(print) - do - print(123) - return "abc" - end + print(123) + return "abc" end local _anon_func_18 = function(print, select, _arg_0, ...) - do - local success = _arg_0 - if success then - return print(select('#', ...)) - end + local success = _arg_0 + if success then + return print(select('#', ...)) end end local _anon_func_19 = function(cond, i) @@ -459,11 +451,9 @@ local _anon_func_25 = function(itemA, listA) return false end local _anon_func_24 = function(itemA, listA, tb) - do - local _call_0 = tb - local _call_1 = _call_0["end"](_call_0) - return _call_1["🤣"](_call_1, 123 and (#listA > 0 and _anon_func_25(itemA, listA))) - end + local _call_0 = tb + local _call_1 = _call_0["end"](_call_0) + return _call_1["🤣"](_call_1, 123 and (#listA > 0 and _anon_func_25(itemA, listA))) end GameEngine:onEvent("SomeEvent", function() return func(value + (_anon_func_21(cond)) + (_anon_func_22(valueB)) > _anon_func_23(tb) + _anon_func_24(itemA, listA, tb)) @@ -503,13 +493,11 @@ local _anon_func_27 = function(char) return nil end local _anon_func_28 = function(os, _arg_0, ...) - do - local ok = _arg_0 - if ok then - return ... - else - return os.exit(1) - end + local ok = _arg_0 + if ok then + return ... + else + return os.exit(1) end end local _anon_func_29 = function(debug_env_after, debug_env_before, env, func) diff --git a/spec/outputs/vararg.lua b/spec/outputs/vararg.lua index dabba44..254aa6a 100644 --- a/spec/outputs/vararg.lua +++ b/spec/outputs/vararg.lua @@ -125,14 +125,10 @@ local _anon_func_11 = function(items, ...) return _tbl_0 end local _anon_func_12 = function(func) - do - return func() - end + return func() end local _anon_func_13 = function(func, ...) - do - return func(...) - end + return func(...) end local _anon_func_14 = function(func) local _accum_0 = { } @@ -195,15 +191,11 @@ local _anon_func_23 = function(func, ...) return nil end local _anon_func_24 = function(print, select, ...) - do - print(select("#", ...)) - return print(...) - end + print(select("#", ...)) + return print(...) end local _anon_func_25 = function(print, ...) - do - return print(...) - end + return print(...) end local _anon_func_26 = function(tb, tb2, x) if 1 == x then @@ -214,9 +206,7 @@ local _anon_func_26 = function(tb, tb2, x) end end local _anon_func_27 = function(print, ...) - do - return print(...) - end + return print(...) end local _anon_func_28 = function(cond) if cond then @@ -224,10 +214,8 @@ local _anon_func_28 = function(cond) end end local _anon_func_29 = function(print, _arg_0, ...) - do - local tb = _arg_0 - return print(...) - end + local tb = _arg_0 + return print(...) end local join join = function(...) diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp index 9d68161..be10859 100644 --- a/src/yuescript/yue_ast.cpp +++ b/src/yuescript/yue_ast.cpp @@ -609,13 +609,19 @@ std::string CatchBlock_t::to_string(void* ud) const { info->popScope(); return line + '\n' + blockStr; } +std::string Omit_t::to_string(void*) const { + return "!"s; +} std::string Try_t::to_string(void* ud) const { auto info = reinterpret_cast(ud); str_list temp; + temp.emplace_back("try"s); + if (omit) { + temp.back() += '!'; + } if (func.is()) { - temp.emplace_back("try "s + func->to_string(ud)); + temp.back() += (" "s + func->to_string(ud)); } else { - temp.emplace_back("try"s); info->pushScope(); temp.emplace_back(func->to_string(ud)); if (temp.back().empty()) { diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index d3e6368..393f374 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h @@ -383,10 +383,14 @@ AST_NODE(CatchBlock) AST_MEMBER(CatchBlock, &err, &block) AST_END(CatchBlock) +AST_LEAF(Omit) +AST_END(Omit) + AST_NODE(Try) + ast_ptr omit; ast_sel func; ast_ptr catchBlock; - AST_MEMBER(Try, &func, &catchBlock) + AST_MEMBER(Try, &omit, &func, &catchBlock) AST_END(Try) AST_NODE(Comprehension) diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 2312025..35745f2 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.28.5"sv; +const std::string_view version = "0.28.6"sv; const std::string_view extension = "yue"sv; class CompileError : public std::logic_error { @@ -165,12 +165,12 @@ public: double compileTime = 0.0; if (config.profiling) { auto start = std::chrono::high_resolution_clock::now(); - _info = _parser.parse(codes); + _info = _parser.parse(codes, config.lax); auto stop = std::chrono::high_resolution_clock::now(); std::chrono::duration diff = stop - start; parseTime = diff.count(); } else { - _info = _parser.parse(codes); + _info = _parser.parse(codes, config.lax); } std::unique_ptr globals; std::unique_ptr options; @@ -1258,7 +1258,7 @@ private: template ast_ptr toAst(std::string_view codes, ast_node* parent) { - auto res = _parser.parse(std::string(codes)); + auto res = _parser.parse(std::string(codes), false); if (res.error) { throw CompileError(res.error.value().msg, parent); } @@ -2330,6 +2330,17 @@ private: out.back().insert(0, preDefine); return false; } + case id(): { + auto tryNode = static_cast(value); + if (tryNode->omit) { + auto assignList = assignment->expList.get(); + std::string preDefine = getPreDefineLine(assignment); + transformTry(tryNode, out, ExpUsage::Assignment, assignList); + out.back().insert(0, preDefine); + return false; + } + break; + } case id(): { auto switchNode = static_cast(value); auto assignList = assignment->expList.get(); @@ -4272,12 +4283,22 @@ private: std::optional> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) { if (checkUpValueFuncAvailable(exp)) { + auto block = exp->new_ptr(); + if (auto sVal = simpleSingleValueFrom(exp)) { + if (auto doNode = sVal->value.as()) { + if (auto blk = doNode->body->content.as()) { + block->statements.dup(blk->statements); + } else { + block->statements.push_back(doNode->body->content.to()); + } + return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite); + } + } auto returnNode = exp->new_ptr(); returnNode->explicitReturn = false; auto returnList = exp->new_ptr(); returnList->exprs.push_back(exp); returnNode->valueList.set(returnList); - auto block = exp->new_ptr(); auto stmt = exp->new_ptr(); stmt->content.set(returnNode); block->statements.push_back(stmt); @@ -4799,11 +4820,7 @@ private: auto newBody = x->new_ptr(); newBody->content.set(followingBlock); { - auto doNode = x->new_ptr(); - doNode->body.set(newBody); - auto simpleValue = x->new_ptr(); - simpleValue->value.set(doNode); - if (auto result = upValueFuncFromExp(newExp(simpleValue, x), &argNames, true)) { + if (auto result = upValueFuncFromBlock(followingBlock.get(), &argNames, false, true)) { auto [funcName, args] = std::move(*result); str_list finalArgs; for (const auto& arg : args) { @@ -4811,9 +4828,13 @@ private: finalArgs.push_back(arg); } } - newBlock->statements.push_back(toAst(funcName + ' ' + join(finalArgs, ","sv), x)); + newBlock->statements.push_back(toAst(funcName + ' ' + (finalArgs.empty() ? "nil"s : join(finalArgs, ","sv)), x)); auto sVal = singleValueFrom(static_cast(newBlock->statements.back())->content.to()->expList); - ast_to(sVal->item.to()->items.back())->args.dup(newInvoke->args); + auto invokArgs = ast_to(sVal->item.to()->items.back()); + if (finalArgs.empty()) { + invokArgs->args.clear(); + } + invokArgs->args.dup(newInvoke->args); transformBlock(newBlock, out, usage, assignList, isRoot); return; } @@ -5093,36 +5114,45 @@ private: if (!nodes.empty()) { str_list temp; for (auto node : nodes) { - currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None; - transformStatement(static_cast(node), temp); - if (isRoot && !_rootDefs.empty()) { - auto last = std::move(temp.back()); - temp.pop_back(); - temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); - _rootDefs.clear(); - temp.push_back(std::move(last)); - } - if (!temp.empty() && _parser.startWith(temp.back())) { - auto rit = ++temp.rbegin(); - if (rit != temp.rend() && !rit->empty()) { - auto index = std::string::npos; - if (_config.reserveLineNumber) { - index = rit->rfind(" -- "sv); - } else { - index = rit->find_last_not_of('\n'); - if (index != std::string::npos) index++; - } - if (index != std::string::npos) { - auto ending = rit->substr(0, index); - auto ind = ending.find_last_of(" \t\n"sv); - if (ind != std::string::npos) { - ending = ending.substr(ind + 1); + auto transformNode = [&]() { + currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None; + transformStatement(static_cast(node), temp); + if (isRoot && !_rootDefs.empty()) { + auto last = std::move(temp.back()); + temp.pop_back(); + temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); + _rootDefs.clear(); + temp.push_back(std::move(last)); + } + if (!temp.empty() && _parser.startWith(temp.back())) { + auto rit = ++temp.rbegin(); + if (rit != temp.rend() && !rit->empty()) { + auto index = std::string::npos; + if (_config.reserveLineNumber) { + index = rit->rfind(" -- "sv); + } else { + index = rit->find_last_not_of('\n'); + if (index != std::string::npos) index++; } - if (LuaKeywords.find(ending) == LuaKeywords.end()) { - rit->insert(index, ";"sv); + if (index != std::string::npos) { + auto ending = rit->substr(0, index); + auto ind = ending.find_last_of(" \t\n"sv); + if (ind != std::string::npos) { + ending = ending.substr(ind + 1); + } + if (LuaKeywords.find(ending) == LuaKeywords.end()) { + rit->insert(index, ";"sv); + } } } } + }; + if (_config.lax) { + try { + transformNode(); + } catch (const CompileError&) { } + } else { + transformNode(); } } out.push_back(join(temp)); @@ -6193,7 +6223,7 @@ private: case id(): case id(): if (_withVars.empty()) { - throw CompileError("short dot/colon and indexing syntax must be called within a with block"sv, x); + throw CompileError("short dot/colon/indexing syntax must be called within a with block"sv, x); } else { temp.push_back(_withVars.top()); } @@ -6714,14 +6744,14 @@ private: } else { if (!codes.empty()) { if (isBlock) { - info = _parser.parse(codes); + info = _parser.parse(codes, false); if (info.error) { throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x); } } else { - info = _parser.parse(codes); + info = _parser.parse(codes, false); if (!info.node && allowBlockMacroReturn) { - info = _parser.parse(codes); + info = _parser.parse(codes, false); if (info.error) { throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x); } @@ -10023,8 +10053,47 @@ private: out.push_back(join(temp)); } - void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage) { + void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { auto x = tryNode; + if (tryNode->omit && usage == ExpUsage::Assignment) { + str_list rets; + pushScope(); + auto okVar = getUnusedName("_ok_"sv); + for (size_t i = 0; i < assignList->exprs.size(); i++) { + auto retVar = getUnusedName("_ret_"sv); + rets.emplace_back(retVar); + addToScope(retVar); + } + popScope(); + auto varList = join(rets, ","sv); + auto ifNode = toAst("if "s + okVar + ',' + varList + ":=try nil then "s + varList, x); + auto exp = ast_to(ifNode->nodes.front())->assignment->assign->values.front(); + auto sVal = simpleSingleValueFrom(exp); + auto newTry = sVal->value.to(); + newTry->func.set(tryNode->func); + newTry->catchBlock.set(tryNode->catchBlock); + auto assignment = x->new_ptr(); + assignment->expList.set(assignList); + auto assign = x->new_ptr(); + assign->values.push_back(ifNode); + assignment->action.set(assign); + transformAssignment(assignment, out); + return; + } + if (tryNode->omit && usage != ExpUsage::Common) { + auto okVar = getUnusedName("_ok_"sv); + auto code = "do\n\t"s + okVar + ", ... = try nil\n\t... if "s + okVar; + auto doNode = toAst(code, x); + auto block = doNode->body->content.to(); + auto asmt = static_cast(block->statements.front())->content.to(); + auto assign = asmt->action.to(); + auto sVal = simpleSingleValueFrom(assign->values.back()); + auto newTry = sVal->value.to(); + newTry->func.set(tryNode->func); + newTry->catchBlock.set(tryNode->catchBlock); + transformDo(doNode, out, usage); + return; + } ast_ptr errHandler; if (tryNode->catchBlock) { auto catchBlock = tryNode->catchBlock.get(); diff --git a/src/yuescript/yue_compiler.h b/src/yuescript/yue_compiler.h index d352636..aff5978 100644 --- a/src/yuescript/yue_compiler.h +++ b/src/yuescript/yue_compiler.h @@ -31,6 +31,7 @@ struct YueConfig { bool reserveLineNumber = true; bool useSpaceOverTab = false; bool reserveComment = false; + bool lax = false; // internal options bool exporting = false; bool profiling = false; diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index e5bdc26..2b0aea8 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -332,7 +332,7 @@ YueParser::YueParser() { Exp; import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item); import_tab_line = ( - push_indent_match >> (space >> import_tab_list >> pop_indent | pop_indent) + push_indent_match >> ensure(space >> import_tab_list, pop_indent) ) | space; import_tab_lines = space_break >> import_tab_line >> *(-(space >> ',') >> space_break >> import_tab_line) >> -(space >> ','); import_tab_key_value = key_value | ':' >> MacroName | MacroNamePair | ImportAllMacro; @@ -501,8 +501,9 @@ YueParser::YueParser() { return true; }); + Omit = expr('!'); CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> Variable >> space >> in_block; - Try = key("try") >> space >> (in_block | Exp) >> -CatchBlock; + Try = key("try") >> -Omit >> space >> (in_block | Exp) >> -CatchBlock; list_value = and_( @@ -667,7 +668,7 @@ YueParser::YueParser() { fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp); fn_args_lit_line = ( - push_indent_match >> (space >> fn_args_value_list >> pop_indent | pop_indent) + push_indent_match >> ensure(space >> fn_args_value_list, pop_indent) ) | ( space ); @@ -875,7 +876,7 @@ YueParser::YueParser() { fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef); fn_arg_def_lit_line = ( - push_indent_match >> (space >> fn_arg_def_list >> pop_indent | pop_indent) + push_indent_match >> ensure(space >> fn_arg_def_list, pop_indent) ) | ( space ); @@ -1030,11 +1031,16 @@ YueParser::YueParser() { empty_line_break | advance_match >> ensure(space >> (indentation_error | Statement), pop_indent) ); - Block = Seperator >> line >> *(+line_break >> line); + Block = Seperator >> (pl::user(true_(), [](const item_t& item) { + State* st = reinterpret_cast(item.user_data); + return st->lax; + }) >> lax_line >> *(+line_break >> lax_line) | line >> *(+line_break >> line)); shebang = "#!" >> *(not_(stop) >> any_char); BlockEnd = Block >> white >> stop; File = -shebang >> -Block >> white >> stop; + + lax_line = advance_match >> ensure(*(not_(stop) >> any()), pop_indent) | line >> and_(stop) | check_indent_match >> *(not_(stop) >> any()); } // clang-format on @@ -1064,7 +1070,7 @@ bool YueParser::startWith(std::string_view codes, rule& r) { return true; } -ParseInfo YueParser::parse(std::string_view codes, rule& r) { +ParseInfo YueParser::parse(std::string_view codes, rule& r, bool lax) { ParseInfo res; if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { codes = codes.substr(3); @@ -1082,6 +1088,7 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) { error_list errors; try { State state; + state.lax = lax; res.node.set(::yue::parse(*(res.codes), r, errors, &state)); if (state.exportCount > 0) { int index = 0; @@ -1119,10 +1126,10 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) { return res; } -ParseInfo YueParser::parse(std::string_view astName, std::string_view codes) { +ParseInfo YueParser::parse(std::string_view astName, std::string_view codes, bool lax) { auto it = _rules.find(astName); if (it != _rules.end()) { - return parse(codes, *it->second); + return parse(codes, *it->second, lax); } return {}; } @@ -1131,7 +1138,7 @@ bool YueParser::match(std::string_view astName, std::string_view codes) { auto it = _rules.find(astName); if (it != _rules.end()) { auto rEnd = rule(*it->second >> eof()); - return parse(codes, rEnd).node; + return parse(codes, rEnd, false).node; } return false; } diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 773bdbe..99f3d45 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -74,16 +74,16 @@ extern std::unordered_set Keywords; class YueParser { public: template - ParseInfo parse(std::string_view codes) { - return parse(codes, getRule()); + ParseInfo parse(std::string_view codes, bool lax) { + return parse(codes, getRule(), lax); } - ParseInfo parse(std::string_view astName, std::string_view codes); + ParseInfo parse(std::string_view astName, std::string_view codes, bool lax); template bool match(std::string_view codes) { auto rEnd = rule(getRule() >> eof()); - return parse(codes, rEnd).node; + return parse(codes, rEnd, false).node; } bool match(std::string_view astName, std::string_view codes); @@ -102,13 +102,14 @@ public: protected: YueParser(); - ParseInfo parse(std::string_view codes, rule& r); + ParseInfo parse(std::string_view codes, rule& r, bool lax); bool startWith(std::string_view codes, rule& r); struct State { State() { indents.push(0); } + bool lax = false; bool exportDefault = false; bool exportMacro = false; bool exportMetatable = false; @@ -287,6 +288,7 @@ private: NONE_AST_RULE(yue_line_comment); NONE_AST_RULE(line); NONE_AST_RULE(shebang); + NONE_AST_RULE(lax_line); AST_RULE(Num); AST_RULE(Name); @@ -345,6 +347,7 @@ private: AST_RULE(ForEach); AST_RULE(Do); AST_RULE(CatchBlock); + AST_RULE(Omit); AST_RULE(Try); AST_RULE(Comprehension); AST_RULE(CompValue); diff --git a/src/yuescript/yuescript.cpp b/src/yuescript/yuescript.cpp index 7e8e8b7..aa19b70 100644 --- a/src/yuescript/yuescript.cpp +++ b/src/yuescript/yuescript.cpp @@ -93,6 +93,12 @@ static void get_config(lua_State* L, yue::YueConfig& config) { config.useSpaceOverTab = lua_toboolean(L, -1) != 0; } lua_pop(L, 1); + lua_pushliteral(L, "lax"); + lua_gettable(L, -2); + if (lua_isboolean(L, -1) != 0) { + config.lax = lua_toboolean(L, -1) != 0; + } + lua_pop(L, 1); lua_pushliteral(L, "options"); lua_gettable(L, -2); if (lua_istable(L, -1) != 0) { @@ -180,7 +186,7 @@ static int yueformat(lua_State* L) { tabSize = static_cast(luaL_checkinteger(L, 2)); } std::string_view codes(input, len); - auto info = yue::YueParser::shared().parse(codes); + auto info = yue::YueParser::shared().parse(codes, false); if (info.error) { const auto& error = info.error.value(); if (!info.codes) { @@ -282,8 +288,13 @@ static int yuetoast(lua_State* L) { ruleName = {name, nameSize}; } } + bool lax = false; + if (!lua_isnoneornil(L, 4)) { + luaL_checktype(L, 4, LUA_TBOOLEAN); + lax = lua_toboolean(L, 4) != 0; + } auto& yueParser = yue::YueParser::shared(); - auto info = ruleName.empty() ? yueParser.parse({input, size}) : yueParser.parse(ruleName, {input, size}); + auto info = ruleName.empty() ? yueParser.parse({input, size}, lax) : yueParser.parse(ruleName, {input, size}, lax); if (!info.error) { lua_createtable(L, 0, 0); int tableIndex = lua_gettop(L); -- cgit v1.2.3-55-g6feb