Makros
Häufige Verwendung
Abschnitt betitelt „Häufige Verwendung“Makrofunktionen werden verwendet, um zur Compile-Zeit einen String auszuwerten und den generierten Code in die finale Kompilierung einzufügen.
macro PI2 = -> math.pi * 2area = $PI2 * 5
macro HELLO = -> "'Hallo Welt'"print $HELLO
macro config = (debugging) -> global debugMode = debugging == "true" ""
macro asserts = (cond) -> debugMode and "assert #{cond}" or ""
macro assert = (cond) -> debugMode and "assert #{cond}" or "#{cond}"
$config true$asserts item ~= nil
$config falsevalue = $assert item
-- übergebene Ausdrücke werden als Strings behandeltmacro and = (...) -> "#{ table.concat {...}, ' and ' }"if $and f1!, f2!, f3! print "OK"macro PI2 = -> math.pi * 2area = $PI2 * 5
macro HELLO = -> "'Hallo Welt'"print $HELLO
macro config = (debugging) -> global debugMode = debugging == "true" ""
macro asserts = (cond) -> debugMode and "assert #{cond}" or ""
macro assert = (cond) -> debugMode and "assert #{cond}" or "#{cond}"
$config true$asserts item ~= nil
$config falsevalue = $assert item
-- übergebene Ausdrücke werden als Strings behandeltmacro and = (...) -> "#{ table.concat {...}, ' and ' }"if $and f1!, f2!, f3! print "OK"Rohcode einfügen
Abschnitt betitelt „Rohcode einfügen“Eine Makrofunktion kann entweder einen YueScript-String oder eine Konfigurationstabelle mit Lua-Code zurückgeben.
macro yueFunc = (var) -> "local #{var} = ->"$yueFunc funcAfuncA = -> "Zuweisung an die vom Yue-Makro definierte Variable schlägt fehl"
macro luaFunc = (var) -> { code: "local function #{var}() end" type: "lua"}$luaFunc funcBfuncB = -> "Zuweisung an die vom Lua-Makro definierte Variable schlägt fehl"
macro lua = (code) -> { :code type: "lua"}
-- führende und abschließende Symbole des Raw-Strings werden automatisch getrimmt$lua[==[-- Einfügen von rohem Lua-Codeif cond then print("Ausgabe")end]==]macro yueFunc = (var) -> "local #{var} = ->"$yueFunc funcAfuncA = -> "Zuweisung an die vom Yue-Makro definierte Variable schlägt fehl"
macro luaFunc = (var) -> { code: "local function #{var}() end" type: "lua"}$luaFunc funcBfuncB = -> "Zuweisung an die vom Lua-Makro definierte Variable schlägt fehl"
macro lua = (code) -> { :code type: "lua"}
-- führende und abschließende Symbole des Raw-Strings werden automatisch getrimmt$lua[==[-- Einfügen von rohem Lua-Codeif cond then print("Ausgabe")end]==]Makros exportieren
Abschnitt betitelt „Makros exportieren“Makrofunktionen können aus einem Modul exportiert und in ein anderes Modul importiert werden. Exportierte Makros müssen in einer einzelnen Datei liegen, und im Export-Modul dürfen nur Makrodefinitionen, Makro-Imports und Makro-Expansionen stehen.
-- Datei: utils.yueexport macro map = (items, action) -> "[#{action} for _ in *#{items}]"export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]"export macro foreach = (items, action) -> "for _ in *#{items} #{action}"
-- Datei main.yueimport "utils" as { $, -- Symbol zum Importieren aller Makros $foreach: $each -- Makro $foreach in $each umbenennen}[1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _-- Datei: utils.yueexport macro map = (items, action) -> "[#{action} for _ in *#{items}]"export macro filter = (items, action) -> "[_ for _ in *#{items} when #{action}]"export macro foreach = (items, action) -> "for _ in *#{items} #{action}"
-- Datei main.yue-- Import-Funktion im Browser nicht verfügbar, in echter Umgebung testen--[[import "utils" as { $, -- Symbol zum Importieren aller Makros $foreach: $each -- Makro $foreach in $each umbenennen}[1, 2, 3] |> $map(_ * 2) |> $filter(_ > 4) |> $each print _]]Eingebaute Makros
Abschnitt betitelt „Eingebaute Makros“Es gibt einige eingebaute Makros, aber du kannst sie überschreiben, indem du Makros mit denselben Namen deklarierst.
print $FILE -- String des aktuellen Modulnamensprint $LINE -- gibt 2 ausprint $FILE -- String des aktuellen Modulnamensprint $LINE -- gibt 2 ausMakros mit Makros erzeugen
Abschnitt betitelt „Makros mit Makros erzeugen“In YueScript erlauben Makrofunktionen Codegenerierung zur Compile-Zeit. Durch das Verschachteln von Makrofunktionen kannst du komplexere Generierungsmuster erzeugen. Damit kannst du eine Makrofunktion definieren, die eine andere Makrofunktion erzeugt.
macro Enum = (...) -> items = {...} itemSet = {item, true for item in *items} (item) -> error "erhalten: \"#{item}\", erwartet eines von #{table.concat items, ', '}" unless itemSet[item] "\"#{item}\""
macro BodyType = $Enum( Static Dynamic Kinematic)
print "Gültiger Enum-Typ:", $BodyType Static-- print "Kompilierungsfehler bei Enum-Typ:", $BodyType Unknownmacro Enum = (...) -> items = {...} itemSet = {item, true for item in *items} (item) -> error "erhalten: \"#{item}\", erwartet eines von #{table.concat items, ', '}" unless itemSet[item] "\"#{item}\""
macro BodyType = $Enum( Static Dynamic Kinematic)
print "Gültiger Enum-Typ:", $BodyType Static-- print "Kompilierungsfehler bei Enum-Typ:", $BodyType UnknownMehrzeiligen Code erzeugen
Abschnitt betitelt „Mehrzeiligen Code erzeugen“Wenn ein Makro mehrzeiligen Yue-Code zurückgibt, ist eine mehrzeilige Zeichenkette in Anführungszeichen nicht zu empfehlen. Verwende stattdessen bevorzugt -> |.
Eine Zeichenkette in Anführungszeichen behält den Text wörtlich bei, während ein YAML-Mehrzeilen-String die gemeinsame führende Einrückung entfernt. Dadurch bleiben erzeugte Yue-Blöcke in der Regel stabiler, besonders wenn der erzeugte Code Kommentare oder verschachtelte Blöcke enthält.
macro default_conf = (conf) -> " -- useful; only set once#{conf}.identity = 'LOVE'#{conf}.version = \"11.5\" "
love.conf = (t) -> $default_conf tmacro default_conf = (conf) -> " -- useful; only set once#{conf}.identity = 'LOVE'#{conf}.version = \"11.5\" "
love.conf = (t) -> $default_conf tmacro default_conf = (conf) -> | -- useful; only set once #{conf}.identity = 'LOVE' #{conf}.version = "11.5"
love.conf = (t) -> $default_conf tmacro default_conf = (conf) -> | -- useful; only set once #{conf}.identity = 'LOVE' #{conf}.version = "11.5"
love.conf = (t) -> $default_conf tArgument-Validierung
Abschnitt betitelt „Argument-Validierung“Du kannst erwartete AST-Knotentypen in der Argumentliste deklarieren und zur Compile-Zeit prüfen, ob die übergebenen Makroargumente den Erwartungen entsprechen.
macro printNumAndStr = (num `Num, str `String) -> | print( #{num} #{str} )
$printNumAndStr 123, "hallo"macro printNumAndStr = (num `Num, str `String) -> | print( #{num} #{str} )
$printNumAndStr 123, "hallo"Wenn du flexiblere Argumentprüfungen brauchst, kannst du das eingebaute Makro $is_ast verwenden, um manuell an der passenden Stelle zu prüfen.
macro printNumAndStr = (num, str) -> error "als erstes Argument Num erwartet" unless $is_ast Num, num error "als zweites Argument String erwartet" unless $is_ast String, str "print(#{num}, #{str})"
$printNumAndStr 123, "hallo"macro printNumAndStr = (num, str) -> error "als erstes Argument Num erwartet" unless $is_ast Num, num error "als zweites Argument String erwartet" unless $is_ast String, str "print(#{num}, #{str})"
$printNumAndStr 123, "hallo"Weitere Details zu verfügbaren AST-Knoten findest du in den großgeschriebenen Definitionen in yue_parser.cpp.
Annotation-Anweisungen
Abschnitt betitelt „Annotation-Anweisungen“Annotation-Anweisungen wenden ein Makro auf die direkt folgende Anweisung an.
Das entspricht einem Makroaufruf, bei dem der Quelltext der folgenden Anweisung als letztes Argument zusätzlich übergeben wird.
macro ShowName = (code) -> | print "#{code\match '^[%w_]*'}"
$[ShowName]myFunc = ->
returnmacro ShowName = (code) -> | print "#{code\match '^[%w_]*'}"
$[ShowName]myFunc = ->
returnWenn das Annotationsmakro eine Konfigurationstabelle zurückgibt, steuert das optionale Feld before, ob das Ergebnis vor oder nach der annotierten Anweisung eingefügt wird.
macro Tag = (tag, code) -> tableName = code\match "^[%w_]+" return type: "text" before: tag == "before" code: "-- #{tag}:#{tableName}"
$[Tag before]tableA = {}
$[Tag after]tableB = {}
returnmacro Tag = (tag, code) -> tableName = code\match "^[%w_]+" return type: "text" before: tag == "before" code: "-- #{tag}:#{tableName}"
$[Tag before]tableA = {}
$[Tag after]tableB = {}
returnDa die folgende Anweisung als zusätzliches Makroargument übergeben wird, lassen sich mit Annotationen auch direkt Registrierungszeilen aus Klassendeklarationen erzeugen. Du kannst dabei dieselben AST-Argumentprüfungen wie bei normalen Makros verwenden.
macro Register = (registry, code`ClassDecl) -> className = code\match "^class%s+(%w+)" return | #{registry}["#{className}"] = #{className}
registry = {}
$[Register(registry)]class Worker run: => "ok"
returnmacro Register = (registry, code`ClassDecl) -> className = code\match "^class%s+(%w+)" return | #{registry}["#{className}"] = #{className}
registry = {}
$[Register(registry)]class Worker run: => "ok"
returnAnnotationen können auch Wrapper-Code um Funktionen herum einfügen:
macro ValidateNumberArgs = (code) -> funcName = code\match "^(%w+)%s*=" return | local __orig_#{funcName} = #{funcName} #{funcName} = (...) -> for i = 1, select "#", ... assert type(select i, ...) == "number", "expected number for arg \#{i}" __orig_#{funcName} ...
$[ValidateNumberArgs]add = (a, b) -> a + bmacro ValidateNumberArgs = (code) -> funcName = code\match "^(%w+)%s*=" return | local __orig_#{funcName} = #{funcName} #{funcName} = (...) -> for i = 1, select "#", ... assert type(select i, ...) == "number", "expected number for arg \#{i}" __orig_#{funcName} ...
$[ValidateNumberArgs]add = (a, b) -> a + bAuf eine Annotation muss immer eine Anweisung folgen, und sie kann nicht auf eine return-Anweisung angewendet werden. Wenn die annotierte Anweisung am Ende eines Blocks steht und du die rohe AST-Form der Anweisung brauchst, füge ein explizites return danach ein, damit sie nicht in einen implizit zurückgegebenen Ausdruck eingebettet wird.