This module contains some functions to help writing macros.
Throws a StopCompilationException to stop the compilation process.
Note that this exception just stop the process and does not print anything on stderr. You should deal with error messages yourself.
See gololang.Messages for instance to display console messages.
Expands to the fully qualified name of the function in which this macro is called.
Can be used for instance to define variable scopes in macro.
Generate a name in the current name space.
Useful if a macro generates calls to functions defined in the same module. Instead of relying on the module to be imported, one wants to use a fully qualified function name. This macro generate such a name without hard coding the current module name in the written macro.
For instance, instead of writing:
module MyModule
function myFunction = -> null
macro = -> gololang.ir.DSL.call("MyModule.myFunction")
we can write:
module MyModule
function myFunction = -> null
macro = -> gololang.ir.DSL.call(&gololang.macros.Utils.thisModule("myFunction")
Utility to extract the last argument of a varargs function.
Useful when creating a macro used as a decorator that can take multiple arguments.
Such a macro can be used as
@myMacro(answer=42, ping="pong")
function myFunction = ...
It will be defined as
macro foo = |args...| {
let arguments, element = extractLastArgument(args)
####...
return element
}
In this example, arguments will be an array of NamedArguments, and element
will contain the GoloFunction.
args: an array containing the argumentsSee also parseArguments
Generates a new unique name using an internal SymbolGenerator.
See also SymbolGenerator
Generates a new unique name using an internal SymbolGenerator with the given name as prefix.
See also SymbolGenerator
Converts a IR node into the corresponding runtime value.
This only works for literal values, classes, enums or arrays of theses values. Otherwise the node itself is returned.
Mangles the given name to ensure hygiene.
If the argument is a LocalReference or a ReferenceLookup, a new object with
the same type, but with a mangled name, is returned.
See also SymbolGenerator
Converts a NamedArgument collection into a map whose keys are the names of the
named arguments, and values the associated values.
Given a macro defined as:
macro foo = |args...| {
let arguments = namedArgsToMap(args)
#### ...
}
When called as &foo(a=42, b="hello"), the arguments variable will contains
map[["a", constant(42)], ["b", constant("hello")]]
The elements of the collection that are not NamedArgument are ignored.
See also parseArguments
Same as parseArguments(args, false)
Converts a collection of expressions and named arguments into a triple
containing a list of the expressions and a map extracted from named arguments
like by namedArgsToMap.
If extractLast is true or null, also extract the last argument as by
extractLastArgument. If extractLast is a type, the last argument is extracted only if it
has the corresponding type.
macro myMacro = |args...| {
let positional, named, last = parseArguments(args, true)
#### ...
}
@myMacro(answer=42, "foo", foo="bar")
function plop = -> "daplop"
In the myMacro macro, positional will be array[constant("foo")], named
will be map[["answer", constant(42)], ["foo", constant("bar")]] and last will
be the plop function IR node.
Decorator to help define macros on top-level elements.
Macros applied on top-level elements may often return a ToplevelElements to
inject several top-level elements into the module, without using side effects.
When stacking such macros, for instance with the decorator notation, each macro
must be prepared to receive a ToplevelElements containing various kinds of
elements, instead of the decorated one.
For instance, a macro can work on a struct and inject several tooling
functions and augmentations, such as:
macro myMacro = |structure| -> toplevels(
structure,
`function("workOn" + structure: name())
: withParameters("s"): body(...),
`augment(structure): with(...)
)
Suppose that a macro otherMacro has a similar behavior. It is thus not possible to
stack these two macro, as in:
@otherMacro
@myMacro
struct Foo = {x}
since here, the otherMacro will not receive a Struct, but the
ToplevelElements returned by myMacro.
This decorator adapt the macro to deal with ToplevelElements, applying it to
each contained element if its type match the given one, and returning the
element unchanged otherwise.
In the previous example, we can use it on the two macros as:
@!toplevel(Struct.class)
macro myMacro = |structure| -> toplevels(
structure,
`function("workOn" + structure: name())
: withParameters(s): body(...),
`augment(structure: packageAndClass()): with(...)
)
The myMacro will be applied to its argument if its a struct, don't change
any other type, and if its argument is a ToplevelElements, it will be applied
to any contained element. The macro can therefore be stacked on the top of other
macros whatever their returned type.
To apply the macro on any type, just use GoloElement.class as a filter.
Moreover, the decorator makes the macro varargs. It can therefore be called on several structures at once, like:
&myMacro {
struct Foo = {x}
struct Bar = {a, b}
}
This decorator should be banged.
type: the type of the nodes on which the macro must be applied.Wrap the given object in a ToplevelElements.
If the argument is an array or a collection of more than 1 element, it is wrapped in a ToplevelElements.
Otherwise, the element is returned unchanged.