Skip to content

Commit

Permalink
add macros generating macros feature.
Browse files Browse the repository at this point in the history
  • Loading branch information
pigpigyyy committed Aug 5, 2024
1 parent f8cd122 commit 94edfbc
Show file tree
Hide file tree
Showing 12 changed files with 225 additions and 29 deletions.
42 changes: 42 additions & 0 deletions doc/docs/doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,48 @@ print $LINE -- get number 2
</pre>
</YueDisplay>

### Generating Macros with Macros

In 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.

```moonscript
macro Enum = (...) ->
items = {...}
itemSet = {item, true for item in *items}
(item) ->
error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
"\"#{item}\""
macro BodyType = $Enum(
Static
Dynamic
Kinematic
)
print "Valid enum type:", $BodyType Static
-- print "Compilation error with enum type:", $BodyType Unknown
```

<YueDisplay>
<pre>
macro Enum = (...) ->
items = {...}
itemSet = {item, true for item in *items}
(item) ->
error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
"\"#{item}\""

macro BodyType = $Enum(
Static
Dynamic
Kinematic
)

print "Valid enum type:", $BodyType Static
-- print "Compilation error with enum type:", $BodyType Unknown
</pre>
</YueDisplay>

## Operator

All of Lua's binary and unary operators are available. Additionally **!=** is as an alias for **~=**, and either **\\** or **::** can be used to write a chaining function call like `tb\func!` or `tb::func!`. And Yuescipt offers some other special operators to write more expressive codes.
Expand Down
41 changes: 41 additions & 0 deletions doc/docs/zh/doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,47 @@ print $LINE -- 获取当前代码行数:2
</pre>
</YueDisplay>

### 用宏生成宏

在月之脚本中,宏函数允许你在编译时生成代码。通过嵌套的宏函数,你可以创建更复杂的生成模式。这个特性允许你定义一个宏函数,用它来生成另一个宏函数,从而实现更加动态的代码生成。

```moonscript
macro Enum = (...) ->
items = {...}
itemSet = {item, true for item in *items}
(item) ->
error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
"\"#{item}\""
macro BodyType = $Enum(
Static
Dynamic
Kinematic
)
print "有效的枚举类型:", $BodyType Static
-- print "编译报错的枚举类型:", $BodyType Unknown
```
<YueDisplay>
<pre>
macro Enum = (...) ->
items = {...}
itemSet = {item, true for item in *items}
(item) ->
error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
"\"#{item}\""

macro BodyType = $Enum(
Static
Dynamic
Kinematic
)

print "有效的枚举类型:", $BodyType Static
-- print "编译报错的枚举类型:", $BodyType Unknown
</pre>
</YueDisplay>

## 操作符

Lua的所有二元和一元操作符在月之脚本中都是可用的。此外,**!=** 符号是 **~=** 的别名,而 **\\****::** 均可用于编写链式函数调用,如写作 `tb\func!``tb::func!`。此外月之脚本还提供了一些其他特殊的操作符,以编写更具表达力的代码。
Expand Down
33 changes: 33 additions & 0 deletions spec/inputs/macro.yue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,39 @@ import "macro_export" as {

import "macro_todo" as $

macro WindowFlag = $enum(
NoNav
NoDecoration
NoTitleBar
NoResize
NoMove
NoScrollbar
NoScrollWithMouse
NoCollapse
AlwaysAutoResize
NoSavedSettings
NoInputs
MenuBar
HorizontalScrollbar
NoFocusOnAppearing
NoBringToFrontOnFocus
AlwaysVerticalScrollbar
AlwaysHorizontalScrollbar
NoNavInputs
NoNavFocus
UnsavedDocument
)

print $WindowFlag AlwaysAutoResize
print $WindowFlag(
NoNav
NoDecoration
NoTitleBar
NoResize
NoMove
NoScrollbar
)

$asserts item == nil

$myconfig false
Expand Down
18 changes: 18 additions & 0 deletions spec/inputs/macro_export.yue
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,24 @@ do
_dst_.#{field} = _src_.#{field}
"}"

export macro enum = (...) ->
items = {...}
items = [item\gsub('"', '') for item in *items]
itemSet = {item, true for item in *items}
(...) ->
count = select "#", ...
if 1 < count
result = "["
for i = 1, count
item = select i, ...
error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
result ..= "\"#{item}\","
result .. "]"
else
item = select 1, ...
error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
"\"#{item}\""

$ ->
global debugMode = true
global debugMacro = true
Expand Down
2 changes: 2 additions & 0 deletions spec/outputs/codes_from_doc.lua
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ if cond then
end
print("yuescript")
print(3)
print("Valid enum type:", "Static")
if tb ~= nil then
tb:func()
end
Expand Down Expand Up @@ -2068,6 +2069,7 @@ if cond then
end
print("yuescript")
print(3)
print("Valid enum type:", "Static")
if tb ~= nil then
tb:func()
end
Expand Down
2 changes: 2 additions & 0 deletions spec/outputs/codes_from_doc_zh.lua
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ if cond then
end
print("yuescript")
print(3)
print("有效的枚举类型:", "Static")
if tb ~= nil then
tb:func()
end
Expand Down Expand Up @@ -2062,6 +2063,7 @@ if cond then
end
print("yuescript")
print(3)
print("有效的枚举类型:", "Static")
if tb ~= nil then
tb:func()
end
Expand Down
11 changes: 10 additions & 1 deletion spec/outputs/macro.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
print("AlwaysAutoResize")
print({
"NoNav",
"NoDecoration",
"NoTitleBar",
"NoResize",
"NoMove",
"NoScrollbar"
})
do
assert(item == nil)
end
Expand Down Expand Up @@ -285,7 +294,7 @@ print((setmetatable({
return 998
end
}))
print("current line: " .. tostring(268))
print("current line: " .. tostring(301))
do
-- TODO
end
Expand Down
5 changes: 4 additions & 1 deletion src/yuescript/yue_ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1362,8 +1362,11 @@ std::string MacroLit_t::to_string(void* ud) const {
}
return line;
}
std::string MacroFunc_t::to_string(void* ud) const {
return name->to_string(ud) + invoke->to_string(ud);
}
std::string Macro_t::to_string(void* ud) const {
return "macro "s + name->to_string(ud) + " = "s + macroLit->to_string(ud);
return "macro "s + name->to_string(ud) + " = "s + decl->to_string(ud);
}
std::string MacroInPlace_t::to_string(void* ud) const {
auto info = reinterpret_cast<YueFormat*>(ud);
Expand Down
10 changes: 8 additions & 2 deletions src/yuescript/yue_ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -774,15 +774,21 @@ AST_NODE(MacroLit)
AST_MEMBER(MacroLit, &argsDef, &body)
AST_END(MacroLit, "macro_lit"sv)

AST_NODE(MacroFunc)
ast_ptr<true, MacroName_t> name;
ast_sel<true, Invoke_t, InvokeArgs_t> invoke;
AST_MEMBER(MacroFunc, &name, &invoke)
AST_END(MacroFunc, "macro_func"sv)

AST_NODE(MacroInPlace)
ast_ptr<true, Body_t> body;
AST_MEMBER(MacroInPlace, &body)
AST_END(MacroInPlace, "macro_in_place"sv)

AST_NODE(Macro)
ast_ptr<true, UnicodeName_t> name;
ast_ptr<true, MacroLit_t> macroLit;
AST_MEMBER(Macro, &name, &macroLit)
ast_sel<true, MacroLit_t, MacroFunc_t> decl;
AST_MEMBER(Macro, &name, &decl)
AST_END(Macro, "macro"sv)

AST_NODE(NameOrDestructure)
Expand Down
Loading

0 comments on commit 94edfbc

Please sign in to comment.