aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2026-01-15 17:07:11 +0800
committerLi Jin <dragon-fly@qq.com>2026-01-15 17:07:11 +0800
commitfced0c4f4101ad7c8d81432a0e8c45d38b72616c (patch)
treeed673461c7ef3c614cb5d56905c437f6a6b27454
parent4177d237e3ed642b2bba5bec13127a44d2b0524d (diff)
downloadyuescript-fced0c4f4101ad7c8d81432a0e8c45d38b72616c.tar.gz
yuescript-fced0c4f4101ad7c8d81432a0e8c45d38b72616c.tar.bz2
yuescript-fced0c4f4101ad7c8d81432a0e8c45d38b72616c.zip
Added `import global` syntax.
-rwxr-xr-xdoc/docs/doc/README.md37
-rwxr-xr-xdoc/docs/zh/doc/README.md37
-rw-r--r--spec/inputs/import_global.yue86
-rw-r--r--spec/outputs/codes_from_doc.lua142
-rw-r--r--spec/outputs/codes_from_doc_zh.lua142
-rw-r--r--spec/outputs/import_global.lua120
-rw-r--r--src/yuescript/yue_ast.cpp3
-rw-r--r--src/yuescript/yue_ast.h5
-rw-r--r--src/yuescript/yue_compiler.cpp78
-rw-r--r--src/yuescript/yue_parser.cpp16
-rw-r--r--src/yuescript/yue_parser.h1
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
929The 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. 929The 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
933You 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
935Names that are explicitly declared as globals in the same scope will not be imported, so you can safely assign to them.
936
937```moonscript
938do
939 import global
940 print "hello"
941 math.random 3
942 -- print = nil -- error: imported globals are const
943
944do
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>
953do
954 import global
955 print "hello"
956 math.random 3
957 -- print = nil -- error: imported globals are const
958
959do
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
933do 970do
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
936do
937 import global
938 print "hello"
939 math.random 3
940 -- print = nil -- 报错:自动导入的全局变量为常量
941
942do
943 -- 被显式声明为全局的变量不会被自动导入
944 import global
945 global FLAG
946 print FLAG
947 FLAG = 123
948```
949<YueDisplay>
950<pre>
951do
952 import global
953 print "hello"
954 math.random 3
955 -- print = nil -- 报错:自动导入的全局变量是常量
956
957do
958 -- 被显式声明为全局的变量不会被自动导入
959 import global
960 global FLAG
961 print FLAG
962 FLAG = 123
963</pre>
964</YueDisplay>
965
929```moonscript 966```moonscript
930-- 用作表解构 967-- 用作表解构
931do 968do
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
2do
3 import global
4 print "hello"
5 math.random 10
6
7do
8 import global
9 value = 1
10 value += 2
11 print value
12
13do
14 local print = (msg) ->
15 return msg
16 do
17 import global
18 print "local"
19 math.random 1
20
21do
22 import global
23 local tostring = (v) -> "local"
24 tostring "value"
25 print tostring 123
26
27do
28 func = (x, y) ->
29 import global
30 return type x, tostring y, print
31 func 1, 2
32
33do
34 import global
35 try
36 func "hello #{world}"
37 catch err
38 print err
39
40do
41 import global
42 global FLAG
43 print FLAG
44 FLAG = 123
45
46do
47 import global
48 global Foo = 10
49 print Foo
50 Foo += 2
51
52do
53 import global
54 global Bar, Baz
55 Bar = 1
56 Baz = 2
57 print Bar, Baz
58
59do
60 import global
61 global *
62 x = 3434
63 if y then
64 x = 10
65
66do
67 import global
68 global ^
69 foobar = "all #{lowercase}"
70 FooBar = "pascal case"
71 FOOBAR = "all #{Uppercase}"
72
73do
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
81do
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}
411do 411do
412 local math = math
413 local print = print
414 print("hello")
415 math.random(3)
416end
417do
418 local print = print
419 print(FLAG)
420 FLAG = 123
421end
422do
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)
739end)(fn(true)) 750end)(fn(true))
740local f
741f = 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
751end
752f(1, 2, 3)
753f("a", "b", "c", "d")
754f()
755local process
756process = 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
768end
769process(1, nil, 3, nil, 5)
770Rx.Observable.fromRange(1, 8):filter(function(x) 751Rx.Observable.fromRange(1, 8):filter(function(x)
771 return x % 2 == 0 752 return x % 2 == 0
772end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) 753end):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}
1002f2(arg1, arg2) 983f2(arg1, arg2)
984local f
985f = 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
995end
996f(1, 2, 3)
997f("a", "b", "c", "d")
998f()
999local process
1000process = 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
1012end
1013process(1, nil, 3, nil, 5)
1003f(function() 1014f(function()
1004 return print("hello") 1015 return print("hello")
1005end) 1016end)
@@ -2917,6 +2928,17 @@ local tb = {
2917 } 2928 }
2918} 2929}
2919do 2930do
2931 local math = math
2932 local print = print
2933 print("hello")
2934 math.random(3)
2935end
2936do
2937 local print = print
2938 print(FLAG)
2939 FLAG = 123
2940end
2941do
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)
3247end)(fn(true)) 3269end)(fn(true))
3248local f
3249f = 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
3259end
3260f(1, 2, 3)
3261f("a", "b", "c", "d")
3262f()
3263local process
3264process = 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
3276end
3277process(1, nil, 3, nil, 5)
3278Rx.Observable.fromRange(1, 8):filter(function(x) 3270Rx.Observable.fromRange(1, 8):filter(function(x)
3279 return x % 2 == 0 3271 return x % 2 == 0
3280end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) 3272end):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
3540end 3532end
3533local f
3534f = 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
3544end
3545f(1, 2, 3)
3546f("a", "b", "c", "d")
3547f()
3548local process
3549process = 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
3561end
3562process(1, nil, 3, nil, 5)
3541f(function() 3563f(function()
3542 return print("hello") 3564 return print("hello")
3543end) 3565end)
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}
411do 411do
412 local math = math
413 local print = print
414 print("hello")
415 math.random(3)
416end
417do
418 local print = print
419 print(FLAG)
420 FLAG = 123
421end
422do
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)
739end)(fn(true)) 750end)(fn(true))
740local f
741f = 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
751end
752f(1, 2, 3)
753f("a", "b", "c", "d")
754f()
755local process
756process = 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
768end
769process(1, nil, 3, nil, 5)
770Rx.Observable.fromRange(1, 8):filter(function(x) 751Rx.Observable.fromRange(1, 8):filter(function(x)
771 return x % 2 == 0 752 return x % 2 == 0
772end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) 753end):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}
996f2(arg1, arg2) 977f2(arg1, arg2)
978local f
979f = 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
989end
990f(1, 2, 3)
991f("a", "b", "c", "d")
992f()
993local process
994process = 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
1006end
1007process(1, nil, 3, nil, 5)
997f(function() 1008f(function()
998 return print("hello") 1009 return print("hello")
999end) 1010end)
@@ -2911,6 +2922,17 @@ local tb = {
2911 } 2922 }
2912} 2923}
2913do 2924do
2925 local math = math
2926 local print = print
2927 print("hello")
2928 math.random(3)
2929end
2930do
2931 local print = print
2932 print(FLAG)
2933 FLAG = 123
2934end
2935do
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)
3241end)(fn(true)) 3263end)(fn(true))
3242local f
3243f = 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
3253end
3254f(1, 2, 3)
3255f("a", "b", "c", "d")
3256f()
3257local process
3258process = 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
3270end
3271process(1, nil, 3, nil, 5)
3272Rx.Observable.fromRange(1, 8):filter(function(x) 3264Rx.Observable.fromRange(1, 8):filter(function(x)
3273 return x % 2 == 0 3265 return x % 2 == 0
3274end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) 3266end):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
3528end 3520end
3521local f
3522f = 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
3532end
3533f(1, 2, 3)
3534f("a", "b", "c", "d")
3535f()
3536local process
3537process = 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
3549end
3550process(1, nil, 3, nil, 5)
3529f(function() 3551f(function()
3530 return print("hello") 3552 return print("hello")
3531end) 3553end)
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 @@
1do
2 local math = math
3 local print = print
4 print("hello")
5 math.random(10)
6end
7do
8 local print = print
9 local value = 1
10 value = value + 2
11 print(value)
12end
13do
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
23end
24do
25 local print = print
26 local tostring
27 tostring = function(v)
28 return "local"
29 end
30 tostring("value")
31 print(tostring(123))
32end
33do
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)
42end
43do
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)
54end
55do
56 local print = print
57 print(FLAG)
58 FLAG = 123
59end
60do
61 local print = print
62 Foo = 10
63 print(Foo)
64 Foo = Foo + 2
65end
66do
67 local print = print
68 Bar = 1
69 Baz = 2
70 print(Bar, Baz)
71end
72do
73 local y = y
74 x = 3434
75 if y then
76 x = 10
77 end
78end
79do
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)
86end
87do
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)
114end
115do
116 local X = X
117 X:func(1, 2, 3)
118 X.tag = "abc"
119 return X
120end
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}
329std::string ImportAllGlobal_t::to_string(void*) const {
330 return "global"s;
331}
329std::string Import_t::to_string(void* ud) const { 332std::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)
234AST_END(ImportAs) 234AST_END(ImportAs)
235 235
236AST_LEAF(ImportAllGlobal)
237AST_END(ImportAllGlobal)
238
236AST_NODE(ImportGlobal) 239AST_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)
241AST_END(ImportGlobal) 244AST_END(ImportGlobal)
242 245
243AST_NODE(Import) 246AST_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)
246AST_END(Import) 249AST_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
81const std::string_view version = "0.30.4"sv; 81const std::string_view version = "0.31.0"sv;
82const std::string_view extension = "yue"sv; 82const std::string_view extension = "yue"sv;
83 83
84class CompileError : public std::logic_error { 84class 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);