diff options
| author | Li Jin <dragon-fly@qq.com> | 2026-01-15 17:07:11 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2026-01-15 17:07:11 +0800 |
| commit | fced0c4f4101ad7c8d81432a0e8c45d38b72616c (patch) | |
| tree | ed673461c7ef3c614cb5d56905c437f6a6b27454 | |
| parent | 4177d237e3ed642b2bba5bec13127a44d2b0524d (diff) | |
| download | yuescript-fced0c4f4101ad7c8d81432a0e8c45d38b72616c.tar.gz yuescript-fced0c4f4101ad7c8d81432a0e8c45d38b72616c.tar.bz2 yuescript-fced0c4f4101ad7c8d81432a0e8c45d38b72616c.zip | |
Added `import global` syntax.
| -rwxr-xr-x | doc/docs/doc/README.md | 37 | ||||
| -rwxr-xr-x | doc/docs/zh/doc/README.md | 37 | ||||
| -rw-r--r-- | spec/inputs/import_global.yue | 86 | ||||
| -rw-r--r-- | spec/outputs/codes_from_doc.lua | 142 | ||||
| -rw-r--r-- | spec/outputs/codes_from_doc_zh.lua | 142 | ||||
| -rw-r--r-- | spec/outputs/import_global.lua | 120 | ||||
| -rw-r--r-- | src/yuescript/yue_ast.cpp | 3 | ||||
| -rw-r--r-- | src/yuescript/yue_ast.h | 5 | ||||
| -rw-r--r-- | src/yuescript/yue_compiler.cpp | 78 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.cpp | 16 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.h | 1 |
11 files changed, 527 insertions, 140 deletions
diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md index 5308ebc..bda82a6 100755 --- a/doc/docs/doc/README.md +++ b/doc/docs/doc/README.md | |||
| @@ -928,6 +928,43 @@ tb = | |||
| 928 | 928 | ||
| 929 | 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. | 929 | 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. |
| 930 | 930 | ||
| 931 | #### Import Global | ||
| 932 | |||
| 933 | You can place `import global` at the top of a block to automatically import all names that have not been explicitly declared or assigned in the current scope as globals. These implicit imports are treated as local consts that reference the corresponding globals at the position of the statement. | ||
| 934 | |||
| 935 | Names that are explicitly declared as globals in the same scope will not be imported, so you can safely assign to them. | ||
| 936 | |||
| 937 | ```moonscript | ||
| 938 | do | ||
| 939 | import global | ||
| 940 | print "hello" | ||
| 941 | math.random 3 | ||
| 942 | -- print = nil -- error: imported globals are const | ||
| 943 | |||
| 944 | do | ||
| 945 | -- explicit global variable will not be imported | ||
| 946 | import global | ||
| 947 | global FLAG | ||
| 948 | print FLAG | ||
| 949 | FLAG = 123 | ||
| 950 | ``` | ||
| 951 | <YueDisplay> | ||
| 952 | <pre> | ||
| 953 | do | ||
| 954 | import global | ||
| 955 | print "hello" | ||
| 956 | math.random 3 | ||
| 957 | -- print = nil -- error: imported globals are const | ||
| 958 | |||
| 959 | do | ||
| 960 | -- explicit global variable will not be imported | ||
| 961 | import global | ||
| 962 | global FLAG | ||
| 963 | print FLAG | ||
| 964 | FLAG = 123 | ||
| 965 | </pre> | ||
| 966 | </YueDisplay> | ||
| 967 | |||
| 931 | ```moonscript | 968 | ```moonscript |
| 932 | -- used as table destructuring | 969 | -- used as table destructuring |
| 933 | do | 970 | do |
diff --git a/doc/docs/zh/doc/README.md b/doc/docs/zh/doc/README.md index de5dff1..d316657 100755 --- a/doc/docs/zh/doc/README.md +++ b/doc/docs/zh/doc/README.md | |||
| @@ -926,6 +926,43 @@ tb = | |||
| 926 | 926 | ||
| 927 | 导入语句是一个语法糖,用于需要引入一个模块或者从已导入的模块中提取子项目。从模块导入的变量默认为不可修改的常量。 | 927 | 导入语句是一个语法糖,用于需要引入一个模块或者从已导入的模块中提取子项目。从模块导入的变量默认为不可修改的常量。 |
| 928 | 928 | ||
| 929 | #### 导入全局变量 | ||
| 930 | |||
| 931 | 在代码块顶部写 `import global`,会将当前作用域中尚未显式声明或赋值过的变量名,自动导入为本地常量,并在该语句的位置绑定到同名的全局变量。 | ||
| 932 | |||
| 933 | 但是在同一作用域中被显式声明为全局的变量不会被自动导入,因此可以继续进行赋值操作。 | ||
| 934 | |||
| 935 | ```moonscript | ||
| 936 | do | ||
| 937 | import global | ||
| 938 | print "hello" | ||
| 939 | math.random 3 | ||
| 940 | -- print = nil -- 报错:自动导入的全局变量为常量 | ||
| 941 | |||
| 942 | do | ||
| 943 | -- 被显式声明为全局的变量不会被自动导入 | ||
| 944 | import global | ||
| 945 | global FLAG | ||
| 946 | print FLAG | ||
| 947 | FLAG = 123 | ||
| 948 | ``` | ||
| 949 | <YueDisplay> | ||
| 950 | <pre> | ||
| 951 | do | ||
| 952 | import global | ||
| 953 | print "hello" | ||
| 954 | math.random 3 | ||
| 955 | -- print = nil -- 报错:自动导入的全局变量是常量 | ||
| 956 | |||
| 957 | do | ||
| 958 | -- 被显式声明为全局的变量不会被自动导入 | ||
| 959 | import global | ||
| 960 | global FLAG | ||
| 961 | print FLAG | ||
| 962 | FLAG = 123 | ||
| 963 | </pre> | ||
| 964 | </YueDisplay> | ||
| 965 | |||
| 929 | ```moonscript | 966 | ```moonscript |
| 930 | -- 用作表解构 | 967 | -- 用作表解构 |
| 931 | do | 968 | do |
diff --git a/spec/inputs/import_global.yue b/spec/inputs/import_global.yue new file mode 100644 index 0000000..30a274e --- /dev/null +++ b/spec/inputs/import_global.yue | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | |||
| 2 | do | ||
| 3 | import global | ||
| 4 | print "hello" | ||
| 5 | math.random 10 | ||
| 6 | |||
| 7 | do | ||
| 8 | import global | ||
| 9 | value = 1 | ||
| 10 | value += 2 | ||
| 11 | print value | ||
| 12 | |||
| 13 | do | ||
| 14 | local print = (msg) -> | ||
| 15 | return msg | ||
| 16 | do | ||
| 17 | import global | ||
| 18 | print "local" | ||
| 19 | math.random 1 | ||
| 20 | |||
| 21 | do | ||
| 22 | import global | ||
| 23 | local tostring = (v) -> "local" | ||
| 24 | tostring "value" | ||
| 25 | print tostring 123 | ||
| 26 | |||
| 27 | do | ||
| 28 | func = (x, y) -> | ||
| 29 | import global | ||
| 30 | return type x, tostring y, print | ||
| 31 | func 1, 2 | ||
| 32 | |||
| 33 | do | ||
| 34 | import global | ||
| 35 | try | ||
| 36 | func "hello #{world}" | ||
| 37 | catch err | ||
| 38 | print err | ||
| 39 | |||
| 40 | do | ||
| 41 | import global | ||
| 42 | global FLAG | ||
| 43 | print FLAG | ||
| 44 | FLAG = 123 | ||
| 45 | |||
| 46 | do | ||
| 47 | import global | ||
| 48 | global Foo = 10 | ||
| 49 | print Foo | ||
| 50 | Foo += 2 | ||
| 51 | |||
| 52 | do | ||
| 53 | import global | ||
| 54 | global Bar, Baz | ||
| 55 | Bar = 1 | ||
| 56 | Baz = 2 | ||
| 57 | print Bar, Baz | ||
| 58 | |||
| 59 | do | ||
| 60 | import global | ||
| 61 | global * | ||
| 62 | x = 3434 | ||
| 63 | if y then | ||
| 64 | x = 10 | ||
| 65 | |||
| 66 | do | ||
| 67 | import global | ||
| 68 | global ^ | ||
| 69 | foobar = "all #{lowercase}" | ||
| 70 | FooBar = "pascal case" | ||
| 71 | FOOBAR = "all #{Uppercase}" | ||
| 72 | |||
| 73 | do | ||
| 74 | import global | ||
| 75 | global const class A | ||
| 76 | global const Flag = 1 | ||
| 77 | global const const, x, y = "const", 1, 2 | ||
| 78 | global const math, table | ||
| 79 | print math, table | ||
| 80 | |||
| 81 | do | ||
| 82 | import global | ||
| 83 | with X | ||
| 84 | \func 1, 2, 3 | ||
| 85 | .tag = "abc" | ||
| 86 | |||
diff --git a/spec/outputs/codes_from_doc.lua b/spec/outputs/codes_from_doc.lua index de5abdd..02f36d1 100644 --- a/spec/outputs/codes_from_doc.lua +++ b/spec/outputs/codes_from_doc.lua | |||
| @@ -409,6 +409,17 @@ local tb = { | |||
| 409 | } | 409 | } |
| 410 | } | 410 | } |
| 411 | do | 411 | do |
| 412 | local math = math | ||
| 413 | local print = print | ||
| 414 | print("hello") | ||
| 415 | math.random(3) | ||
| 416 | end | ||
| 417 | do | ||
| 418 | local print = print | ||
| 419 | print(FLAG) | ||
| 420 | FLAG = 123 | ||
| 421 | end | ||
| 422 | do | ||
| 412 | local insert, concat = table.insert, table.concat | 423 | local insert, concat = table.insert, table.concat |
| 413 | local C, Ct, Cmt | 424 | local C, Ct, Cmt |
| 414 | do | 425 | do |
| @@ -737,36 +748,6 @@ end | |||
| 737 | local first = select(1, ...) | 748 | local first = select(1, ...) |
| 738 | return print(ok, count, first) | 749 | return print(ok, count, first) |
| 739 | end)(fn(true)) | 750 | end)(fn(true)) |
| 740 | local f | ||
| 741 | f = function(...) | ||
| 742 | local t = { | ||
| 743 | n = select("#", ...), | ||
| 744 | ... | ||
| 745 | } | ||
| 746 | print("argument count:", t.n) | ||
| 747 | print("table length:", #t) | ||
| 748 | for i = 1, t.n do | ||
| 749 | print(t[i]) | ||
| 750 | end | ||
| 751 | end | ||
| 752 | f(1, 2, 3) | ||
| 753 | f("a", "b", "c", "d") | ||
| 754 | f() | ||
| 755 | local process | ||
| 756 | process = function(...) | ||
| 757 | local args = { | ||
| 758 | n = select("#", ...), | ||
| 759 | ... | ||
| 760 | } | ||
| 761 | local sum = 0 | ||
| 762 | for i = 1, args.n do | ||
| 763 | if args[i] ~= nil and type(args[i]) == "number" then | ||
| 764 | sum = sum + args[i] | ||
| 765 | end | ||
| 766 | end | ||
| 767 | return sum | ||
| 768 | end | ||
| 769 | process(1, nil, 3, nil, 5) | ||
| 770 | Rx.Observable.fromRange(1, 8):filter(function(x) | 751 | Rx.Observable.fromRange(1, 8):filter(function(x) |
| 771 | return x % 2 == 0 | 752 | return x % 2 == 0 |
| 772 | end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) | 753 | end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) |
| @@ -1000,6 +981,36 @@ local arg1 = { | |||
| 1000 | a = 0 | 981 | a = 0 |
| 1001 | } | 982 | } |
| 1002 | f2(arg1, arg2) | 983 | f2(arg1, arg2) |
| 984 | local f | ||
| 985 | f = function(...) | ||
| 986 | local t = { | ||
| 987 | n = select("#", ...), | ||
| 988 | ... | ||
| 989 | } | ||
| 990 | print("argument count:", t.n) | ||
| 991 | print("table length:", #t) | ||
| 992 | for i = 1, t.n do | ||
| 993 | print(t[i]) | ||
| 994 | end | ||
| 995 | end | ||
| 996 | f(1, 2, 3) | ||
| 997 | f("a", "b", "c", "d") | ||
| 998 | f() | ||
| 999 | local process | ||
| 1000 | process = function(...) | ||
| 1001 | local args = { | ||
| 1002 | n = select("#", ...), | ||
| 1003 | ... | ||
| 1004 | } | ||
| 1005 | local sum = 0 | ||
| 1006 | for i = 1, args.n do | ||
| 1007 | if args[i] ~= nil and type(args[i]) == "number" then | ||
| 1008 | sum = sum + args[i] | ||
| 1009 | end | ||
| 1010 | end | ||
| 1011 | return sum | ||
| 1012 | end | ||
| 1013 | process(1, nil, 3, nil, 5) | ||
| 1003 | f(function() | 1014 | f(function() |
| 1004 | return print("hello") | 1015 | return print("hello") |
| 1005 | end) | 1016 | end) |
| @@ -2917,6 +2928,17 @@ local tb = { | |||
| 2917 | } | 2928 | } |
| 2918 | } | 2929 | } |
| 2919 | do | 2930 | do |
| 2931 | local math = math | ||
| 2932 | local print = print | ||
| 2933 | print("hello") | ||
| 2934 | math.random(3) | ||
| 2935 | end | ||
| 2936 | do | ||
| 2937 | local print = print | ||
| 2938 | print(FLAG) | ||
| 2939 | FLAG = 123 | ||
| 2940 | end | ||
| 2941 | do | ||
| 2920 | local insert, concat = table.insert, table.concat | 2942 | local insert, concat = table.insert, table.concat |
| 2921 | local C, Ct, Cmt | 2943 | local C, Ct, Cmt |
| 2922 | do | 2944 | do |
| @@ -3245,36 +3267,6 @@ end | |||
| 3245 | local first = select(1, ...) | 3267 | local first = select(1, ...) |
| 3246 | return print(ok, count, first) | 3268 | return print(ok, count, first) |
| 3247 | end)(fn(true)) | 3269 | end)(fn(true)) |
| 3248 | local f | ||
| 3249 | f = function(...) | ||
| 3250 | local t = { | ||
| 3251 | n = select("#", ...), | ||
| 3252 | ... | ||
| 3253 | } | ||
| 3254 | print("argument count:", t.n) | ||
| 3255 | print("table length:", #t) | ||
| 3256 | for i = 1, t.n do | ||
| 3257 | print(t[i]) | ||
| 3258 | end | ||
| 3259 | end | ||
| 3260 | f(1, 2, 3) | ||
| 3261 | f("a", "b", "c", "d") | ||
| 3262 | f() | ||
| 3263 | local process | ||
| 3264 | process = function(...) | ||
| 3265 | local args = { | ||
| 3266 | n = select("#", ...), | ||
| 3267 | ... | ||
| 3268 | } | ||
| 3269 | local sum = 0 | ||
| 3270 | for i = 1, args.n do | ||
| 3271 | if args[i] ~= nil and type(args[i]) == "number" then | ||
| 3272 | sum = sum + args[i] | ||
| 3273 | end | ||
| 3274 | end | ||
| 3275 | return sum | ||
| 3276 | end | ||
| 3277 | process(1, nil, 3, nil, 5) | ||
| 3278 | Rx.Observable.fromRange(1, 8):filter(function(x) | 3270 | Rx.Observable.fromRange(1, 8):filter(function(x) |
| 3279 | return x % 2 == 0 | 3271 | return x % 2 == 0 |
| 3280 | end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) | 3272 | end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) |
| @@ -3538,6 +3530,36 @@ findFirstEven = function(list) | |||
| 3538 | end | 3530 | end |
| 3539 | return nil | 3531 | return nil |
| 3540 | end | 3532 | end |
| 3533 | local f | ||
| 3534 | f = function(...) | ||
| 3535 | local t = { | ||
| 3536 | n = select("#", ...), | ||
| 3537 | ... | ||
| 3538 | } | ||
| 3539 | print("argument count:", t.n) | ||
| 3540 | print("table length:", #t) | ||
| 3541 | for i = 1, t.n do | ||
| 3542 | print(t[i]) | ||
| 3543 | end | ||
| 3544 | end | ||
| 3545 | f(1, 2, 3) | ||
| 3546 | f("a", "b", "c", "d") | ||
| 3547 | f() | ||
| 3548 | local process | ||
| 3549 | process = function(...) | ||
| 3550 | local args = { | ||
| 3551 | n = select("#", ...), | ||
| 3552 | ... | ||
| 3553 | } | ||
| 3554 | local sum = 0 | ||
| 3555 | for i = 1, args.n do | ||
| 3556 | if args[i] ~= nil and type(args[i]) == "number" then | ||
| 3557 | sum = sum + args[i] | ||
| 3558 | end | ||
| 3559 | end | ||
| 3560 | return sum | ||
| 3561 | end | ||
| 3562 | process(1, nil, 3, nil, 5) | ||
| 3541 | f(function() | 3563 | f(function() |
| 3542 | return print("hello") | 3564 | return print("hello") |
| 3543 | end) | 3565 | end) |
diff --git a/spec/outputs/codes_from_doc_zh.lua b/spec/outputs/codes_from_doc_zh.lua index 6a6c38c..87944e0 100644 --- a/spec/outputs/codes_from_doc_zh.lua +++ b/spec/outputs/codes_from_doc_zh.lua | |||
| @@ -409,6 +409,17 @@ local tb = { | |||
| 409 | } | 409 | } |
| 410 | } | 410 | } |
| 411 | do | 411 | do |
| 412 | local math = math | ||
| 413 | local print = print | ||
| 414 | print("hello") | ||
| 415 | math.random(3) | ||
| 416 | end | ||
| 417 | do | ||
| 418 | local print = print | ||
| 419 | print(FLAG) | ||
| 420 | FLAG = 123 | ||
| 421 | end | ||
| 422 | do | ||
| 412 | local insert, concat = table.insert, table.concat | 423 | local insert, concat = table.insert, table.concat |
| 413 | local C, Ct, Cmt | 424 | local C, Ct, Cmt |
| 414 | do | 425 | do |
| @@ -737,36 +748,6 @@ end | |||
| 737 | local first = select(1, ...) | 748 | local first = select(1, ...) |
| 738 | return print(ok, count, first) | 749 | return print(ok, count, first) |
| 739 | end)(fn(true)) | 750 | end)(fn(true)) |
| 740 | local f | ||
| 741 | f = function(...) | ||
| 742 | local t = { | ||
| 743 | n = select("#", ...), | ||
| 744 | ... | ||
| 745 | } | ||
| 746 | print("参数个数:", t.n) | ||
| 747 | print("表长度:", #t) | ||
| 748 | for i = 1, t.n do | ||
| 749 | print(t[i]) | ||
| 750 | end | ||
| 751 | end | ||
| 752 | f(1, 2, 3) | ||
| 753 | f("a", "b", "c", "d") | ||
| 754 | f() | ||
| 755 | local process | ||
| 756 | process = function(...) | ||
| 757 | local args = { | ||
| 758 | n = select("#", ...), | ||
| 759 | ... | ||
| 760 | } | ||
| 761 | local sum = 0 | ||
| 762 | for i = 1, args.n do | ||
| 763 | if args[i] ~= nil and type(args[i]) == "number" then | ||
| 764 | sum = sum + args[i] | ||
| 765 | end | ||
| 766 | end | ||
| 767 | return sum | ||
| 768 | end | ||
| 769 | process(1, nil, 3, nil, 5) | ||
| 770 | Rx.Observable.fromRange(1, 8):filter(function(x) | 751 | Rx.Observable.fromRange(1, 8):filter(function(x) |
| 771 | return x % 2 == 0 | 752 | return x % 2 == 0 |
| 772 | end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) | 753 | end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) |
| @@ -994,6 +975,36 @@ local arg1 = { | |||
| 994 | a = 0 | 975 | a = 0 |
| 995 | } | 976 | } |
| 996 | f2(arg1, arg2) | 977 | f2(arg1, arg2) |
| 978 | local f | ||
| 979 | f = function(...) | ||
| 980 | local t = { | ||
| 981 | n = select("#", ...), | ||
| 982 | ... | ||
| 983 | } | ||
| 984 | print("参数个数:", t.n) | ||
| 985 | print("表长度:", #t) | ||
| 986 | for i = 1, t.n do | ||
| 987 | print(t[i]) | ||
| 988 | end | ||
| 989 | end | ||
| 990 | f(1, 2, 3) | ||
| 991 | f("a", "b", "c", "d") | ||
| 992 | f() | ||
| 993 | local process | ||
| 994 | process = function(...) | ||
| 995 | local args = { | ||
| 996 | n = select("#", ...), | ||
| 997 | ... | ||
| 998 | } | ||
| 999 | local sum = 0 | ||
| 1000 | for i = 1, args.n do | ||
| 1001 | if args[i] ~= nil and type(args[i]) == "number" then | ||
| 1002 | sum = sum + args[i] | ||
| 1003 | end | ||
| 1004 | end | ||
| 1005 | return sum | ||
| 1006 | end | ||
| 1007 | process(1, nil, 3, nil, 5) | ||
| 997 | f(function() | 1008 | f(function() |
| 998 | return print("hello") | 1009 | return print("hello") |
| 999 | end) | 1010 | end) |
| @@ -2911,6 +2922,17 @@ local tb = { | |||
| 2911 | } | 2922 | } |
| 2912 | } | 2923 | } |
| 2913 | do | 2924 | do |
| 2925 | local math = math | ||
| 2926 | local print = print | ||
| 2927 | print("hello") | ||
| 2928 | math.random(3) | ||
| 2929 | end | ||
| 2930 | do | ||
| 2931 | local print = print | ||
| 2932 | print(FLAG) | ||
| 2933 | FLAG = 123 | ||
| 2934 | end | ||
| 2935 | do | ||
| 2914 | local insert, concat = table.insert, table.concat | 2936 | local insert, concat = table.insert, table.concat |
| 2915 | local C, Ct, Cmt | 2937 | local C, Ct, Cmt |
| 2916 | do | 2938 | do |
| @@ -3239,36 +3261,6 @@ end | |||
| 3239 | local first = select(1, ...) | 3261 | local first = select(1, ...) |
| 3240 | return print(ok, count, first) | 3262 | return print(ok, count, first) |
| 3241 | end)(fn(true)) | 3263 | end)(fn(true)) |
| 3242 | local f | ||
| 3243 | f = function(...) | ||
| 3244 | local t = { | ||
| 3245 | n = select("#", ...), | ||
| 3246 | ... | ||
| 3247 | } | ||
| 3248 | print("参数个数:", t.n) | ||
| 3249 | print("表长度:", #t) | ||
| 3250 | for i = 1, t.n do | ||
| 3251 | print(t[i]) | ||
| 3252 | end | ||
| 3253 | end | ||
| 3254 | f(1, 2, 3) | ||
| 3255 | f("a", "b", "c", "d") | ||
| 3256 | f() | ||
| 3257 | local process | ||
| 3258 | process = function(...) | ||
| 3259 | local args = { | ||
| 3260 | n = select("#", ...), | ||
| 3261 | ... | ||
| 3262 | } | ||
| 3263 | local sum = 0 | ||
| 3264 | for i = 1, args.n do | ||
| 3265 | if args[i] ~= nil and type(args[i]) == "number" then | ||
| 3266 | sum = sum + args[i] | ||
| 3267 | end | ||
| 3268 | end | ||
| 3269 | return sum | ||
| 3270 | end | ||
| 3271 | process(1, nil, 3, nil, 5) | ||
| 3272 | Rx.Observable.fromRange(1, 8):filter(function(x) | 3264 | Rx.Observable.fromRange(1, 8):filter(function(x) |
| 3273 | return x % 2 == 0 | 3265 | return x % 2 == 0 |
| 3274 | end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) | 3266 | end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) |
| @@ -3526,6 +3518,36 @@ findFirstEven = function(list) | |||
| 3526 | end | 3518 | end |
| 3527 | return nil | 3519 | return nil |
| 3528 | end | 3520 | end |
| 3521 | local f | ||
| 3522 | f = function(...) | ||
| 3523 | local t = { | ||
| 3524 | n = select("#", ...), | ||
| 3525 | ... | ||
| 3526 | } | ||
| 3527 | print("参数个数:", t.n) | ||
| 3528 | print("表长度:", #t) | ||
| 3529 | for i = 1, t.n do | ||
| 3530 | print(t[i]) | ||
| 3531 | end | ||
| 3532 | end | ||
| 3533 | f(1, 2, 3) | ||
| 3534 | f("a", "b", "c", "d") | ||
| 3535 | f() | ||
| 3536 | local process | ||
| 3537 | process = function(...) | ||
| 3538 | local args = { | ||
| 3539 | n = select("#", ...), | ||
| 3540 | ... | ||
| 3541 | } | ||
| 3542 | local sum = 0 | ||
| 3543 | for i = 1, args.n do | ||
| 3544 | if args[i] ~= nil and type(args[i]) == "number" then | ||
| 3545 | sum = sum + args[i] | ||
| 3546 | end | ||
| 3547 | end | ||
| 3548 | return sum | ||
| 3549 | end | ||
| 3550 | process(1, nil, 3, nil, 5) | ||
| 3529 | f(function() | 3551 | f(function() |
| 3530 | return print("hello") | 3552 | return print("hello") |
| 3531 | end) | 3553 | end) |
diff --git a/spec/outputs/import_global.lua b/spec/outputs/import_global.lua new file mode 100644 index 0000000..08a90e2 --- /dev/null +++ b/spec/outputs/import_global.lua | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | do | ||
| 2 | local math = math | ||
| 3 | local print = print | ||
| 4 | print("hello") | ||
| 5 | math.random(10) | ||
| 6 | end | ||
| 7 | do | ||
| 8 | local print = print | ||
| 9 | local value = 1 | ||
| 10 | value = value + 2 | ||
| 11 | print(value) | ||
| 12 | end | ||
| 13 | do | ||
| 14 | local print | ||
| 15 | print = function(msg) | ||
| 16 | return msg | ||
| 17 | end | ||
| 18 | do | ||
| 19 | local math = math | ||
| 20 | print("local") | ||
| 21 | math.random(1) | ||
| 22 | end | ||
| 23 | end | ||
| 24 | do | ||
| 25 | local print = print | ||
| 26 | local tostring | ||
| 27 | tostring = function(v) | ||
| 28 | return "local" | ||
| 29 | end | ||
| 30 | tostring("value") | ||
| 31 | print(tostring(123)) | ||
| 32 | end | ||
| 33 | do | ||
| 34 | local func | ||
| 35 | func = function(x, y) | ||
| 36 | local tostring = tostring | ||
| 37 | local print = print | ||
| 38 | local type = type | ||
| 39 | return type(x, tostring(y, print)) | ||
| 40 | end | ||
| 41 | func(1, 2) | ||
| 42 | end | ||
| 43 | do | ||
| 44 | local print = print | ||
| 45 | local tostring = tostring | ||
| 46 | local func = func | ||
| 47 | local world = world | ||
| 48 | local xpcall = xpcall | ||
| 49 | xpcall(function() | ||
| 50 | return func("hello " .. tostring(world)) | ||
| 51 | end, function(err) | ||
| 52 | return print(err) | ||
| 53 | end) | ||
| 54 | end | ||
| 55 | do | ||
| 56 | local print = print | ||
| 57 | print(FLAG) | ||
| 58 | FLAG = 123 | ||
| 59 | end | ||
| 60 | do | ||
| 61 | local print = print | ||
| 62 | Foo = 10 | ||
| 63 | print(Foo) | ||
| 64 | Foo = Foo + 2 | ||
| 65 | end | ||
| 66 | do | ||
| 67 | local print = print | ||
| 68 | Bar = 1 | ||
| 69 | Baz = 2 | ||
| 70 | print(Bar, Baz) | ||
| 71 | end | ||
| 72 | do | ||
| 73 | local y = y | ||
| 74 | x = 3434 | ||
| 75 | if y then | ||
| 76 | x = 10 | ||
| 77 | end | ||
| 78 | end | ||
| 79 | do | ||
| 80 | local tostring = tostring | ||
| 81 | local Uppercase = Uppercase | ||
| 82 | local lowercase = lowercase | ||
| 83 | local foobar = "all " .. tostring(lowercase) | ||
| 84 | FooBar = "pascal case" | ||
| 85 | FOOBAR = "all " .. tostring(Uppercase) | ||
| 86 | end | ||
| 87 | do | ||
| 88 | local print = print | ||
| 89 | local setmetatable = setmetatable | ||
| 90 | do | ||
| 91 | local _class_0 | ||
| 92 | local _base_0 = { } | ||
| 93 | if _base_0.__index == nil then | ||
| 94 | _base_0.__index = _base_0 | ||
| 95 | end | ||
| 96 | _class_0 = setmetatable({ | ||
| 97 | __init = function() end, | ||
| 98 | __base = _base_0, | ||
| 99 | __name = "A" | ||
| 100 | }, { | ||
| 101 | __index = _base_0, | ||
| 102 | __call = function(cls, ...) | ||
| 103 | local _self_0 = setmetatable({ }, _base_0) | ||
| 104 | cls.__init(_self_0, ...) | ||
| 105 | return _self_0 | ||
| 106 | end | ||
| 107 | }) | ||
| 108 | _base_0.__class = _class_0 | ||
| 109 | A = _class_0 | ||
| 110 | end | ||
| 111 | Flag = 1 | ||
| 112 | const, x, y = "const", 1, 2 | ||
| 113 | print(math, table) | ||
| 114 | end | ||
| 115 | do | ||
| 116 | local X = X | ||
| 117 | X:func(1, 2, 3) | ||
| 118 | X.tag = "abc" | ||
| 119 | return X | ||
| 120 | end | ||
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 { | |||
| 326 | } | 326 | } |
| 327 | return item; | 327 | return item; |
| 328 | } | 328 | } |
| 329 | std::string ImportAllGlobal_t::to_string(void*) const { | ||
| 330 | return "global"s; | ||
| 331 | } | ||
| 329 | std::string Import_t::to_string(void* ud) const { | 332 | std::string Import_t::to_string(void* ud) const { |
| 330 | if (ast_is<FromImport_t>(content)) { | 333 | if (ast_is<FromImport_t>(content)) { |
| 331 | return content->to_string(ud); | 334 | 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) | |||
| 233 | AST_MEMBER(ImportAs, &literal, &target) | 233 | AST_MEMBER(ImportAs, &literal, &target) |
| 234 | AST_END(ImportAs) | 234 | AST_END(ImportAs) |
| 235 | 235 | ||
| 236 | AST_LEAF(ImportAllGlobal) | ||
| 237 | AST_END(ImportAllGlobal) | ||
| 238 | |||
| 236 | AST_NODE(ImportGlobal) | 239 | AST_NODE(ImportGlobal) |
| 237 | ast_ptr<true, Seperator_t> sep; | 240 | ast_ptr<true, Seperator_t> sep; |
| 238 | ast_list<true, UnicodeName_t> segs; | 241 | ast_list<true, UnicodeName_t> segs; |
| @@ -241,7 +244,7 @@ AST_NODE(ImportGlobal) | |||
| 241 | AST_END(ImportGlobal) | 244 | AST_END(ImportGlobal) |
| 242 | 245 | ||
| 243 | AST_NODE(Import) | 246 | AST_NODE(Import) |
| 244 | ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t, ImportGlobal_t> content; | 247 | ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t, ImportGlobal_t, ImportAllGlobal_t> content; |
| 245 | AST_MEMBER(Import, &content) | 248 | AST_MEMBER(Import, &content) |
| 246 | AST_END(Import) | 249 | AST_END(Import) |
| 247 | 250 | ||
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<std::string> Metamethods = { | |||
| 78 | "close"s // Lua 5.4 | 78 | "close"s // Lua 5.4 |
| 79 | }; | 79 | }; |
| 80 | 80 | ||
| 81 | const std::string_view version = "0.30.4"sv; | 81 | const std::string_view version = "0.31.0"sv; |
| 82 | const std::string_view extension = "yue"sv; | 82 | const std::string_view extension = "yue"sv; |
| 83 | 83 | ||
| 84 | class CompileError : public std::logic_error { | 84 | class CompileError : public std::logic_error { |
| @@ -434,6 +434,14 @@ private: | |||
| 434 | Global = 2, | 434 | Global = 2, |
| 435 | GlobalConst = 3 | 435 | GlobalConst = 3 |
| 436 | }; | 436 | }; |
| 437 | struct Scope; | ||
| 438 | struct ImportedGlobal { | ||
| 439 | std::string* globalCodeLine = nullptr; | ||
| 440 | Scope* importingScope = nullptr; | ||
| 441 | std::string indent; | ||
| 442 | std::string nl; | ||
| 443 | std::unordered_set<std::string> globals; | ||
| 444 | }; | ||
| 437 | struct Scope { | 445 | struct Scope { |
| 438 | GlobalMode mode = GlobalMode::None; | 446 | GlobalMode mode = GlobalMode::None; |
| 439 | bool lastStatement = false; | 447 | bool lastStatement = false; |
| @@ -442,8 +450,10 @@ private: | |||
| 442 | #endif | 450 | #endif |
| 443 | std::unique_ptr<std::unordered_map<std::string, VarType>> vars; | 451 | std::unique_ptr<std::unordered_map<std::string, VarType>> vars; |
| 444 | std::unique_ptr<std::unordered_set<std::string>> allows; | 452 | std::unique_ptr<std::unordered_set<std::string>> allows; |
| 453 | std::unique_ptr<ImportedGlobal> importedGlobal; | ||
| 445 | }; | 454 | }; |
| 446 | std::list<Scope> _scopes; | 455 | std::list<Scope> _scopes; |
| 456 | ImportedGlobal* _importedGlobal = nullptr; | ||
| 447 | static const std::string Empty; | 457 | static const std::string Empty; |
| 448 | 458 | ||
| 449 | enum class MemType { | 459 | enum class MemType { |
| @@ -1612,7 +1622,12 @@ private: | |||
| 1612 | 1622 | ||
| 1613 | std::string globalVar(std::string_view var, ast_node* x, AccessType accessType) { | 1623 | std::string globalVar(std::string_view var, ast_node* x, AccessType accessType) { |
| 1614 | std::string str(var); | 1624 | std::string str(var); |
| 1615 | if (_config.lintGlobalVariable) { | 1625 | if (_importedGlobal) { |
| 1626 | if (_importedGlobal->globals.find(str) == _importedGlobal->globals.end() && !isSolidDefined(str)) { | ||
| 1627 | _importedGlobal->globals.insert(str); | ||
| 1628 | _importedGlobal->importingScope->vars->insert_or_assign(str, VarType::LocalConst); | ||
| 1629 | } | ||
| 1630 | } else if (_config.lintGlobalVariable) { | ||
| 1616 | if (!isLocal(str)) { | 1631 | if (!isLocal(str)) { |
| 1617 | auto key = str + ':' + std::to_string(x->m_begin.m_line) + ':' + std::to_string(x->m_begin.m_col); | 1632 | auto key = str + ':' + std::to_string(x->m_begin.m_line) + ':' + std::to_string(x->m_begin.m_col); |
| 1618 | if (_globals.find(key) == _globals.end()) { | 1633 | if (_globals.find(key) == _globals.end()) { |
| @@ -4617,13 +4632,21 @@ private: | |||
| 4617 | switch (item->get_id()) { | 4632 | switch (item->get_id()) { |
| 4618 | case id<Variable_t>(): { | 4633 | case id<Variable_t>(): { |
| 4619 | transformVariable(static_cast<Variable_t*>(item), out); | 4634 | transformVariable(static_cast<Variable_t*>(item), out); |
| 4620 | if (_config.lintGlobalVariable && accessType != AccessType::None && !isLocal(out.back())) { | 4635 | if (accessType != AccessType::None) { |
| 4621 | auto key = out.back() + ':' + std::to_string(item->m_begin.m_line) + ':' + std::to_string(item->m_begin.m_col); | 4636 | if (_importedGlobal) { |
| 4622 | if (_globals.find(key) == _globals.end()) { | 4637 | const auto& str = out.back(); |
| 4623 | if (accessType == AccessType::Read && _funcLevel > 1) { | 4638 | if (_importedGlobal->globals.find(str) == _importedGlobal->globals.end() && !isSolidDefined(str)) { |
| 4624 | accessType = AccessType::Capture; | 4639 | _importedGlobal->globals.insert(str); |
| 4640 | _importedGlobal->importingScope->vars->insert_or_assign(str, VarType::LocalConst); | ||
| 4641 | } | ||
| 4642 | } else if (_config.lintGlobalVariable && !isLocal(out.back())) { | ||
| 4643 | auto key = out.back() + ':' + std::to_string(item->m_begin.m_line) + ':' + std::to_string(item->m_begin.m_col); | ||
| 4644 | if (_globals.find(key) == _globals.end()) { | ||
| 4645 | if (accessType == AccessType::Read && _funcLevel > 1) { | ||
| 4646 | accessType = AccessType::Capture; | ||
| 4647 | } | ||
| 4648 | _globals[key] = {out.back(), item->m_begin.m_line, item->m_begin.m_col, accessType, isSolidDefined(out.back())}; | ||
| 4625 | } | 4649 | } |
| 4626 | _globals[key] = {out.back(), item->m_begin.m_line, item->m_begin.m_col, accessType, isSolidDefined(out.back())}; | ||
| 4627 | } | 4650 | } |
| 4628 | } | 4651 | } |
| 4629 | break; | 4652 | break; |
| @@ -5299,7 +5322,23 @@ private: | |||
| 5299 | } | 5322 | } |
| 5300 | auto transformNode = [&]() { | 5323 | auto transformNode = [&]() { |
| 5301 | currentScope().lastStatement = (node == lastStmt) && currentScope().mode == GlobalMode::None; | 5324 | currentScope().lastStatement = (node == lastStmt) && currentScope().mode == GlobalMode::None; |
| 5302 | transformStatement(static_cast<Statement_t*>(node), temp); | 5325 | auto stmt = static_cast<Statement_t*>(node); |
| 5326 | if (auto importNode = stmt->content.as<Import_t>(); | ||
| 5327 | importNode && importNode->content.is<ImportAllGlobal_t>()) { | ||
| 5328 | if (_importedGlobal) { | ||
| 5329 | throw CompileError("import global redeclared in same scope"sv, importNode); | ||
| 5330 | } else { | ||
| 5331 | auto& scope = currentScope(); | ||
| 5332 | scope.importedGlobal = std::make_unique<ImportedGlobal>(); | ||
| 5333 | _importedGlobal = scope.importedGlobal.get(); | ||
| 5334 | _importedGlobal->importingScope = &scope; | ||
| 5335 | _importedGlobal->indent = indent(); | ||
| 5336 | _importedGlobal->nl = nl(stmt); | ||
| 5337 | _importedGlobal->globalCodeLine = &temp.emplace_back(); | ||
| 5338 | } | ||
| 5339 | } else { | ||
| 5340 | transformStatement(stmt, temp); | ||
| 5341 | } | ||
| 5303 | if (isRoot && !_rootDefs.empty()) { | 5342 | if (isRoot && !_rootDefs.empty()) { |
| 5304 | auto last = std::move(temp.back()); | 5343 | auto last = std::move(temp.back()); |
| 5305 | temp.pop_back(); | 5344 | temp.pop_back(); |
| @@ -5338,6 +5377,14 @@ private: | |||
| 5338 | transformNode(); | 5377 | transformNode(); |
| 5339 | } | 5378 | } |
| 5340 | } | 5379 | } |
| 5380 | if (auto importedGlobal = currentScope().importedGlobal.get()) { | ||
| 5381 | str_list globalCodes; | ||
| 5382 | for (const auto& global : importedGlobal->globals) { | ||
| 5383 | globalCodes.emplace_back(importedGlobal->indent + "local "s + global + " = "s + global + importedGlobal->nl); | ||
| 5384 | } | ||
| 5385 | *importedGlobal->globalCodeLine = join(globalCodes); | ||
| 5386 | _importedGlobal = nullptr; | ||
| 5387 | } | ||
| 5341 | out.push_back(join(temp)); | 5388 | out.push_back(join(temp)); |
| 5342 | } else { | 5389 | } else { |
| 5343 | out.push_back(Empty); | 5390 | out.push_back(Empty); |
| @@ -9313,7 +9360,12 @@ private: | |||
| 9313 | } else { | 9360 | } else { |
| 9314 | out.push_back(name + " = "s + name); | 9361 | out.push_back(name + " = "s + name); |
| 9315 | } | 9362 | } |
| 9316 | if (_config.lintGlobalVariable && !isLocal(name)) { | 9363 | if (_importedGlobal) { |
| 9364 | if (_importedGlobal->globals.find(name) == _importedGlobal->globals.end() && !isSolidDefined(name)) { | ||
| 9365 | _importedGlobal->globals.insert(name); | ||
| 9366 | _importedGlobal->importingScope->vars->insert_or_assign(name, VarType::LocalConst); | ||
| 9367 | } | ||
| 9368 | } else if (_config.lintGlobalVariable && !isLocal(name)) { | ||
| 9317 | auto key = name + ':' + std::to_string(pair->name->m_begin.m_line) + ':' + std::to_string(pair->name->m_begin.m_col); | 9369 | auto key = name + ':' + std::to_string(pair->name->m_begin.m_line) + ':' + std::to_string(pair->name->m_begin.m_col); |
| 9318 | if (_globals.find(key) == _globals.end()) { | 9370 | if (_globals.find(key) == _globals.end()) { |
| 9319 | _globals[key] = {name, pair->name->m_begin.m_line, pair->name->m_begin.m_col, _funcLevel > 1 ? AccessType::Capture : AccessType::Read, isSolidDefined(name)}; | 9371 | _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: | |||
| 10348 | } | 10400 | } |
| 10349 | assignment->action.set(assign); | 10401 | assignment->action.set(assign); |
| 10350 | transformAssignment(assignment, out); | 10402 | transformAssignment(assignment, out); |
| 10351 | for (const auto& name : varNames) { | 10403 | if (global->constAttrib) { |
| 10352 | markVarGlobalConst(name); | 10404 | for (const auto& name : varNames) { |
| 10405 | markVarGlobalConst(name); | ||
| 10406 | } | ||
| 10353 | } | 10407 | } |
| 10354 | } else { | 10408 | } else { |
| 10355 | for (auto name : values->nameList->names.objects()) { | 10409 | 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() { | |||
| 464 | 464 | ||
| 465 | ImportGlobal = Seperator >> UnicodeName >> *('.' >> UnicodeName) >> space >> not_(',' | key("from")) >> -(key("as") >> space >> must_variable); | 465 | ImportGlobal = Seperator >> UnicodeName >> *('.' >> UnicodeName) >> space >> not_(',' | key("from")) >> -(key("as") >> space >> must_variable); |
| 466 | 466 | ||
| 467 | Import = key("import") >> space >> (ImportGlobal | ImportAs | ImportFrom | invalid_import_syntax_error) | FromImport; | 467 | ImportAllGlobal = key("global"); |
| 468 | |||
| 469 | Import = key("import") >> space >> (ImportAllGlobal | ImportGlobal | ImportAs | ImportFrom | invalid_import_syntax_error) | FromImport; | ||
| 468 | 470 | ||
| 469 | Label = "::" >> (and_(LuaKeyword >> "::") >> keyword_as_label_error | UnicodeName >> "::"); | 471 | Label = "::" >> (and_(LuaKeyword >> "::") >> keyword_as_label_error | UnicodeName >> "::"); |
| 470 | 472 | ||
| @@ -982,7 +984,7 @@ YueParser::YueParser() { | |||
| 982 | return true; | 984 | return true; |
| 983 | }) | | 985 | }) | |
| 984 | invalid_export_syntax_error | 986 | invalid_export_syntax_error |
| 985 | ) >> not_(space >> StatementAppendix); | 987 | ); |
| 986 | 988 | ||
| 987 | VariablePair = ':' >> Variable; | 989 | VariablePair = ':' >> Variable; |
| 988 | 990 | ||
| @@ -1125,14 +1127,14 @@ YueParser::YueParser() { | |||
| 1125 | StatementAppendix = (IfLine | WhileLine | CompFor) >> space; | 1127 | StatementAppendix = (IfLine | WhileLine | CompFor) >> space; |
| 1126 | Statement = | 1128 | Statement = |
| 1127 | ( | 1129 | ( |
| 1128 | Import | While | Repeat | For | | 1130 | Import | Export | Global | Macro | MacroInPlace | Label |
| 1129 | Return | Local | Global | Export | Macro | | 1131 | ) | ( |
| 1130 | MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending | | 1132 | Local | While | Repeat | For | Return | |
| 1133 | BreakLoop | Goto | ShortTabAppending | | ||
| 1131 | LocalAttrib | Backcall | PipeBody | ExpListAssign | ChainAssign | | 1134 | LocalAttrib | Backcall | PipeBody | ExpListAssign | ChainAssign | |
| 1132 | StatementAppendix >> empty_block_error | | 1135 | StatementAppendix >> empty_block_error | |
| 1133 | and_(key("else") | key("elseif") | key("when")) >> dangling_clause_error | 1136 | and_(key("else") | key("elseif") | key("when")) >> dangling_clause_error |
| 1134 | ) >> space >> | 1137 | ) >> space >> -StatementAppendix; |
| 1135 | -StatementAppendix; | ||
| 1136 | 1138 | ||
| 1137 | StatementSep = white >> (set("('\"") | "[[" | "[="); | 1139 | StatementSep = white >> (set("('\"") | "[[" | "[="); |
| 1138 | 1140 | ||
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: | |||
| 352 | AST_RULE(ImportTabLit); | 352 | AST_RULE(ImportTabLit); |
| 353 | AST_RULE(ImportAs); | 353 | AST_RULE(ImportAs); |
| 354 | AST_RULE(ImportGlobal); | 354 | AST_RULE(ImportGlobal); |
| 355 | AST_RULE(ImportAllGlobal); | ||
| 355 | AST_RULE(Import); | 356 | AST_RULE(Import); |
| 356 | AST_RULE(Label); | 357 | AST_RULE(Label); |
| 357 | AST_RULE(Goto); | 358 | AST_RULE(Goto); |
