aboutsummaryrefslogtreecommitdiff
path: root/doc/docs/doc/advanced/macro.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/docs/doc/advanced/macro.md')
-rw-r--r--doc/docs/doc/advanced/macro.md275
1 files changed, 275 insertions, 0 deletions
diff --git a/doc/docs/doc/advanced/macro.md b/doc/docs/doc/advanced/macro.md
new file mode 100644
index 0000000..6d194c3
--- /dev/null
+++ b/doc/docs/doc/advanced/macro.md
@@ -0,0 +1,275 @@
1# Macro
2
3## Common Usage
4
5Macro function is used for evaluating a string in the compile time and insert the generated codes into final compilation.
6
7```yuescript
8macro PI2 = -> math.pi * 2
9area = $PI2 * 5
10
11macro HELLO = -> "'hello world'"
12print $HELLO
13
14macro config = (debugging) ->
15 global debugMode = debugging == "true"
16 ""
17
18macro asserts = (cond) ->
19 debugMode and "assert #{cond}" or ""
20
21macro assert = (cond) ->
22 debugMode and "assert #{cond}" or "#{cond}"
23
24$config true
25$asserts item ~= nil
26
27$config false
28value = $assert item
29
30-- the passed expressions are treated as strings
31macro and = (...) -> "#{ table.concat {...}, ' and ' }"
32if $and f1!, f2!, f3!
33 print "OK"
34```
35<YueDisplay>
36
37```yue
38macro PI2 = -> math.pi * 2
39area = $PI2 * 5
40
41macro HELLO = -> "'hello world'"
42print $HELLO
43
44macro config = (debugging) ->
45 global debugMode = debugging == "true"
46 ""
47
48macro asserts = (cond) ->
49 debugMode and "assert #{cond}" or ""
50
51macro assert = (cond) ->
52 debugMode and "assert #{cond}" or "#{cond}"
53
54$config true
55$asserts item ~= nil
56
57$config false
58value = $assert item
59
60-- the passed expressions are treated as strings
61macro and = (...) -> "#{ table.concat {...}, ' and ' }"
62if $and f1!, f2!, f3!
63 print "OK"
64```
65
66</YueDisplay>
67
68## Insert Raw Codes
69
70A macro function can either return a YueScript string or a config table containing Lua codes.
71```yuescript
72macro yueFunc = (var) -> "local #{var} = ->"
73$yueFunc funcA
74funcA = -> "fail to assign to the Yue macro defined variable"
75
76macro luaFunc = (var) -> {
77 code: "local function #{var}() end"
78 type: "lua"
79}
80$luaFunc funcB
81funcB = -> "fail to assign to the Lua macro defined variable"
82
83macro lua = (code) -> {
84 :code
85 type: "lua"
86}
87
88-- the raw string leading and ending symbols are auto trimed
89$lua[==[
90-- raw Lua codes insertion
91if cond then
92 print("output")
93end
94]==]
95```
96<YueDisplay>
97
98```yue
99macro yueFunc = (var) -> "local #{var} = ->"
100$yueFunc funcA
101funcA = -> "fail to assign to the Yue macro defined variable"
102
103macro luaFunc = (var) -> {
104 code: "local function #{var}() end"
105 type: "lua"
106}
107$luaFunc funcB
108funcB = -> "fail to assign to the Lua macro defined variable"
109
110macro lua = (code) -> {
111 :code
112 type: "lua"
113}
114
115-- the raw string leading and ending symbols are auto trimed
116$lua[==[
117-- raw Lua codes insertion
118if cond then
119 print("output")
120end
121]==]
122```
123
124</YueDisplay>
125
126## Export Macro
127
128Macro functions can be exported from a module and get imported in another module. You have to put export macro functions in a single file to be used, and only macro definition, macro importing and macro expansion in place can be put into the macro exporting module.
129```yuescript
130-- file: utils.yue
131export macro map = (items, action) -> "[#{action} for _ in *#{items}]"
132export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]"
133export macro foreach = (items, action) -> "for _ in *#{items}
134 #{action}"
135
136-- file main.yue
137import "utils" as {
138 $, -- symbol to import all macros
139 $foreach: $each -- rename macro $foreach to $each
140}
141[1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _
142```
143<YueDisplay>
144
145```yue
146-- file: utils.yue
147export macro map = (items, action) -> "[#{action} for _ in *#{items}]"
148export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]"
149export macro foreach = (items, action) -> "for _ in *#{items}
150 #{action}"
151
152-- file main.yue
153-- import function is not available in browser, try it in a real environment
154--[[
155import "utils" as {
156 $, -- symbol to import all macros
157 $foreach: $each -- rename macro $foreach to $each
158}
159[1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _
160]]
161```
162
163</YueDisplay>
164
165## Builtin Macro
166
167There are some builtin macros but you can override them by declaring macros with the same names.
168```yuescript
169print $FILE -- get string of current module name
170print $LINE -- get number 2
171```
172<YueDisplay>
173
174```yue
175print $FILE -- get string of current module name
176print $LINE -- get number 2
177```
178
179</YueDisplay>
180
181## Generating Macros with Macros
182
183In YueScript, macro functions allow you to generate code at compile time. By nesting macro functions, you can create more complex generation patterns. This feature enables you to define a macro function that generates another macro function, allowing for more dynamic code generation.
184
185```yuescript
186macro Enum = (...) ->
187 items = {...}
188 itemSet = {item, true for item in *items}
189 (item) ->
190 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
191 "\"#{item}\""
192
193macro BodyType = $Enum(
194 Static
195 Dynamic
196 Kinematic
197)
198
199print "Valid enum type:", $BodyType Static
200-- print "Compilation error with enum type:", $BodyType Unknown
201```
202
203<YueDisplay>
204
205```yue
206macro Enum = (...) ->
207 items = {...}
208 itemSet = {item, true for item in *items}
209 (item) ->
210 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
211 "\"#{item}\""
212
213macro BodyType = $Enum(
214 Static
215 Dynamic
216 Kinematic
217)
218
219print "Valid enum type:", $BodyType Static
220-- print "Compilation error with enum type:", $BodyType Unknown
221```
222
223</YueDisplay>
224
225## Argument Validation
226
227You can declare the expected AST node types in the argument list, and check whether the incoming macro arguments meet the expectations at compile time.
228
229```yuescript
230macro printNumAndStr = (num `Num, str `String) -> |
231 print(
232 #{num}
233 #{str}
234 )
235
236$printNumAndStr 123, "hello"
237```
238<YueDisplay>
239
240```yue
241macro printNumAndStr = (num `Num, str `String) -> |
242 print(
243 #{num}
244 #{str}
245 )
246
247$printNumAndStr 123, "hello"
248```
249
250</YueDisplay>
251
252If you need more flexible argument checking, you can use the built-in `$is_ast` macro function to manually check at the appropriate place.
253
254```yuescript
255macro printNumAndStr = (num, str) ->
256 error "expected Num as first argument" unless $is_ast Num, num
257 error "expected String as second argument" unless $is_ast String, str
258 "print(#{num}, #{str})"
259
260$printNumAndStr 123, "hello"
261```
262<YueDisplay>
263
264```yue
265macro printNumAndStr = (num, str) ->
266 error "expected Num as first argument" unless $is_ast Num, num
267 error "expected String as second argument" unless $is_ast String, str
268 "print(#{num}, #{str})"
269
270$printNumAndStr 123, "hello"
271```
272
273</YueDisplay>
274
275For more details about available AST nodes, please refer to the uppercased definitions in [yue_parser.cpp](https://github.com/IppClub/YueScript/blob/main/src/yuescript/yue_parser.cpp).