Macros

Declaration

MacroDecl = "macro" identifier "(" ParameterList ")" MacroBody "end" ;
MacroBody = { ( identifier | TemplateStmt ) ";" } ;

TemplateStmt      = LineTemplateStmt | BlockTemplateStmt ;
LineTemplateStmt  = "$" TemplateContent ;
BlockTemplateStmt = "!!" { TemplateContent } "!!" ;

TemplateContent is a bit more complex: it essentially is normal lapyst sourcecode but with one addition: everywhere a TemplateInterpolation can be placed.

TemplateInterpolation = "{{" identifier "}}" ;

A TemplateInterpolation itself is just used to inject a variable’s value inside the template.

macro declare_method(ident name, type ret)
    $ dec {{ret}} {{name}}();
end

macro make_method(ident name, type ret, expr value)
    !!
        def {{ret}} {{name}}()
            return {{value}}
        end
    !!
end

Types

NoteTODO: document this

@macro_context annotation

NoteTODO: maybe rework this a bit

This annotation can give your macro extra information where the macro itself can be used.

@macro_context{ in=[ :shape ] }
macro attr_reader(ident name)
    type = context.getField(name).getType();
    !!
        def {{type}} !{{name}}
            return self.{{name}}
        end
    !!
end

It’s only has the attribute in which accepts an array of symbols.

These symbols can be:

:shape
:function
:method
:namespace
:global
:constructor

The context

NoteTODO: expand more on the context

In each macro, the context variable holds the context in which the macro is currently being evaluated. With this, you have read access to all definitions / declarations in this context until the point of the macro call.

@macro_context{ in=[ :shape ] }
macro attr_reader(ident name)
    type = context.getField(name).getType();
end
1This line querys the current context (a shape) for an specific field. From this field it then retrieves the type of that field.
back to top