aboutsummaryrefslogtreecommitdiff
path: root/spec/inputs
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2026-04-23 17:04:06 +0800
committerLi Jin <dragon-fly@qq.com>2026-04-23 17:04:06 +0800
commitacb80dec2706359027c0461073aded3420eaec56 (patch)
treede4e3393e6af6911f1e292fa2a4677e788062f04 /spec/inputs
parent7805872d0a1705fa2fc296b6c37a40f675a39591 (diff)
downloadyuescript-acb80dec2706359027c0461073aded3420eaec56.tar.gz
yuescript-acb80dec2706359027c0461073aded3420eaec56.tar.bz2
yuescript-acb80dec2706359027c0461073aded3420eaec56.zip
Add annotation statements and expand annotation tests
Diffstat (limited to 'spec/inputs')
-rw-r--r--spec/inputs/annotation.yue27
-rw-r--r--spec/inputs/annotation_before.yue16
-rw-r--r--spec/inputs/test/annotation_spec.yue160
-rw-r--r--spec/inputs/test/format_spec.yue4
4 files changed, 206 insertions, 1 deletions
diff --git a/spec/inputs/annotation.yue b/spec/inputs/annotation.yue
new file mode 100644
index 0000000..2124ad3
--- /dev/null
+++ b/spec/inputs/annotation.yue
@@ -0,0 +1,27 @@
1macro ClsDef = (code`ClassDecl) ->
2 className = code\match "^class%s+(%w+)"
3 lines = table.concat [item\gsub "%-%-%-", "---@" for item in code\gmatch "(%-%-%-.-)\n"], "\n"
4 return
5 type: "text"
6 before: false
7 code: |
8 ---@class #{className}
9 #{lines}
10 ---@class #{className}Class
11 ---@operator call:#{className}
12 ---@cast #{className} #{className}Class
13
14$[ClsDef]
15class A
16 ---field x number
17 ---field y number
18 new: (@x = 0, @y = 0) =>
19 ---field setAdd fun(self: A, x: number, y: number): number Set fields and add number values.
20 setAdd: (@x, @y) => @x + @y
21
22a = A!
23res = a::setAdd 1, 2
24print(a.x, a.y, a.y, res)
25
26return
27
diff --git a/spec/inputs/annotation_before.yue b/spec/inputs/annotation_before.yue
new file mode 100644
index 0000000..9b11aad
--- /dev/null
+++ b/spec/inputs/annotation_before.yue
@@ -0,0 +1,16 @@
1macro Tag = (tag, code`ClassDecl) ->
2 className = code\match "^class%s+(%w+)"
3 return
4 type: "text"
5 before: tag == "before"
6 code: "-- #{tag}:#{className}"
7
8$[Tag("before")]
9class B
10 getTag: => "before"
11
12$[Tag("after")]
13class C
14 getTag: => "after"
15
16return B!\getTag!, C!\getTag!
diff --git a/spec/inputs/test/annotation_spec.yue b/spec/inputs/test/annotation_spec.yue
new file mode 100644
index 0000000..3cd1d5a
--- /dev/null
+++ b/spec/inputs/test/annotation_spec.yue
@@ -0,0 +1,160 @@
1import to_lua from require "yue"
2
3compile_and_run = (code, config = {}) ->
4 lua_code, err = to_lua code, config
5 assert.is_nil err
6 assert.is_not_nil lua_code
7 chunk, load_err = load lua_code
8 assert.is_nil load_err
9 assert.is_not_nil chunk
10 chunk!
11
12describe "annotation", ->
13 it "should append generated text after annotated class by default", ->
14 code = [[
15macro ClsDef = (code`ClassDecl) ->
16 className = code\match "^class%s+(%w+)"
17 return
18 type: "text"
19 before: false
20 code: "-- after:" .. className
21
22$[ClsDef]
23class A
24 getName: => "A"
25
26return
27]]
28 result, err = to_lua code
29 assert.is_nil err
30 assert.is_not_nil result
31 assert.is_true result\find("__name = \"A\"") != nil
32 assert.is_true result\find("%-%- after:A") != nil
33 assert.is_true result\find("__name = \"A\"") < result\find("%-%- after:A")
34
35 it "should place generated text before the annotated statement when before is true", ->
36 code = [[
37macro Before = (code`ClassDecl) ->
38 className = code\match "^class%s+(%w+)"
39 return
40 type: "text"
41 before: true
42 code: "-- before:" .. className
43
44$[Before]
45class B
46 getName: => "B"
47
48return
49]]
50 result, err = to_lua code
51 assert.is_nil err
52 assert.is_not_nil result
53 assert.is_true result\find("%-%- before:B") != nil
54 assert.is_true result\find("local B") != nil
55 assert.is_true result\find("%-%- before:B") < result\find("local B")
56
57 it "should support annotation invocation arguments", ->
58 code = [[
59macro Tag = (tag, code`ClassDecl) ->
60 className = code\match "^class%s+(%w+)"
61 return
62 type: "text"
63 before: false
64 code: "-- " .. tag .. ":" .. className
65
66$[Tag("entity")]
67class C
68 getName: => "C"
69
70return
71]]
72 result, err = to_lua code
73 assert.is_nil err
74 assert.is_not_nil result
75 assert.is_true result\find("%-%- \"entity\":C") != nil
76
77 it "should report an error when annotation is not followed by a statement", ->
78 code = [[
79macro Invalid = (code) -> ""
80$[Invalid]
81]]
82 result, err = to_lua code
83 assert.is_nil result
84 assert.is_true err\match("annotation must be followed by a statement") != nil
85
86 it "should wrap annotated function to validate numeric arguments", ->
87 code = [[
88macro ValidateNumberArgs = (code) ->
89 funcName = code\match "^(%w+)%s*="
90 return
91 type: "text"
92 before: false
93 code: table.concat {
94 "local __orig_#{funcName} = #{funcName}"
95 "#{funcName} = function(a, b)"
96 "\tassert(type(a) == \"number\", \"expected number for a\")"
97 "\tassert(type(b) == \"number\", \"expected number for b\")"
98 "\treturn __orig_#{funcName}(a, b)"
99 "end"
100 }, "\n"
101
102$[ValidateNumberArgs]
103add = (a, b) -> a + b
104
105ok, value = pcall -> add 3, 4
106bad_ok, bad_err = pcall -> add "3", 4
107return ok, value, bad_ok, bad_err
108]]
109 ok, value, bad_ok, bad_err = compile_and_run code
110 assert.is_true ok
111 assert.same value, 7
112 assert.is_false bad_ok
113 assert.is_true bad_err\match("expected number for a") != nil
114
115 it "should wrap annotated function to validate return value", ->
116 code = [[
117macro ValidateNumberReturn = (code) ->
118 funcName = code\match "^(%w+)%s*="
119 return
120 type: "text"
121 before: false
122 code: table.concat {
123 "local __orig_#{funcName} = #{funcName}"
124 "#{funcName} = function(...)"
125 "\tlocal result = __orig_#{funcName}(...)"
126 "\tassert(type(result) == \"number\", \"expected numeric return\")"
127 "\treturn result"
128 "end"
129 }, "\n"
130
131$[ValidateNumberReturn]
132toText = (value) -> tostring value
133
134ok, err = pcall -> toText 42
135return ok, err
136]]
137 ok, err = compile_and_run code
138 assert.is_false ok
139 assert.is_true err\match("expected numeric return") != nil
140
141 it "should use annotation arguments to register annotated classes", ->
142 code = [[
143macro Register = (registry, code`ClassDecl) ->
144 className = code\match "^class%s+(%w+)"
145 return
146 type: "text"
147 before: false
148 code: "#{registry}[\"#{className}\"] = #{className}"
149
150registry = {}
151
152$[Register(registry)]
153class Worker
154 run: => "ok"
155
156return registry.Worker != nil, registry.Worker!\run!
157]]
158 exists, result = compile_and_run code
159 assert.is_true exists
160 assert.same result, "ok"
diff --git a/spec/inputs/test/format_spec.yue b/spec/inputs/test/format_spec.yue
index 310b610..a76a5dd 100644
--- a/spec/inputs/test/format_spec.yue
+++ b/spec/inputs/test/format_spec.yue
@@ -26,6 +26,8 @@ files = [
26 "spec/inputs/export_default.yue" 26 "spec/inputs/export_default.yue"
27 "spec/inputs/with_scope_shadow.yue" 27 "spec/inputs/with_scope_shadow.yue"
28 "spec/inputs/assign.yue" 28 "spec/inputs/assign.yue"
29 "spec/inputs/annotation.yue"
30 "spec/inputs/annotation_before.yue"
29 "spec/inputs/literals.yue" 31 "spec/inputs/literals.yue"
30 "spec/inputs/luarocks_upload.yue" 32 "spec/inputs/luarocks_upload.yue"
31 "spec/inputs/comprehension_nested.yue" 33 "spec/inputs/comprehension_nested.yue"
@@ -64,6 +66,7 @@ files = [
64 "spec/inputs/test/continue_spec.yue" 66 "spec/inputs/test/continue_spec.yue"
65 "spec/inputs/test/varargs_assignment_spec.yue" 67 "spec/inputs/test/varargs_assignment_spec.yue"
66 "spec/inputs/test/advanced_macro_spec.yue" 68 "spec/inputs/test/advanced_macro_spec.yue"
69 "spec/inputs/test/annotation_spec.yue"
67 "spec/inputs/test/pipe_spec.yue" 70 "spec/inputs/test/pipe_spec.yue"
68 "spec/inputs/test/export_spec.yue" 71 "spec/inputs/test/export_spec.yue"
69 "spec/inputs/test/existential_spec.yue" 72 "spec/inputs/test/existential_spec.yue"
@@ -192,4 +195,3 @@ for file in *files
192 assert.is_not_nil ast 195 assert.is_not_nil ast
193 rewriteLineCol ast 196 rewriteLineCol ast
194 assert.same original_ast, ast 197 assert.same original_ast, ast
195