API Reference
Syntax Types
Convenient types for storing analysis results of a given Julia Expr
, or for creating certain Julia objects easily. These types define some common syntax one would manipulate in Julia meta programming.
Expronicon.JLFunction
— Typemutable struct JLFunction <: JLExpr
JLFunction(;kw...)
Type describes a Julia function declaration expression.
Fields and Keyword Arguments
All the following fields are valid as keyword arguments kw
in the constructor, and can be access via <object>.<field>
.
The only required keyword argument for the constructor is name
, the rest are all optional.
head
: optional, function head, can be:function
,:(=)
or:(->)
.name
: optional, function name, can has typeNothing
,Symbol
orExpr
, default isnothing
.args
: optional, function arguments, a list ofExpr
orSymbol
.kwargs
: optional, function keyword arguments, a list ofExpr(:kw, name, default)
.rettype
: optional, the explicit return type of a function, can be aType
,Symbol
,Expr
or justnothing
, default isnothing
.generated
: optional, if this is a generated function.whereparams
: optional, type variables, can be a list ofType
,Expr
ornothing
, default isnothing
.body
: optional, function body, anExpr
, default isExpr(:block)
.line::LineNumberNode
: aLineNumberNode
to indicate the line information.doc::String
: the docstring of this definition.
Example
Construct a function expression
julia> JLFunction(;name=:foo, args=[:(x::T)], body= quote 1+1 end, head=:function, whereparams=[:T])
function foo(x::T) where {T}
#= REPL[25]:1 =#
1 + 1
end
Decompose a function expression
julia> ex = :(function foo(x::T) where {T}
#= REPL[25]:1 =#
1 + 1
end)
:(function foo(x::T) where T
#= REPL[26]:1 =#
#= REPL[26]:3 =#
1 + 1
end)
julia> jl = JLFunction(ex)
function foo(x::T) where {T}
#= REPL[26]:1 =#
#= REPL[26]:3 =#
1 + 1
end
Generate Expr
from JLFunction
julia> codegen_ast(jl)
:(function foo(x::T) where T
#= REPL[26]:1 =#
#= REPL[26]:3 =#
1 + 1
end)
Expronicon.JLStruct
— Typemutable struct JLStruct <: JLExpr
Type describes a Julia struct.
JLStruct(;kw...)
Create a JLStruct
instance.
Available Fields and Keyword Arguments
All the following fields are valid as keyword arguments kw
in the constructor, and can be access via <object>.<field>
.
The only required keyword argument for the constructor is name
, the rest are all optional.
name::Symbol
: name of the struct, this is the only required keyword argument.ismutable::Bool
: if the struct definition is mutable.typevars::Vector{Any}
: type variables of the struct, should beSymbol
orExpr
.supertype
: supertype of the struct definition.fields::Vector{JLField}
: field definitions of the struct, should be aJLField
.constructors::Vector{JLFunction}
: constructors definitions of the struct, should beJLFunction
.line::LineNumberNode
: aLineNumberNode
to indicate the definition position for error report etc.doc::String
: documentation string of the struct.misc
: other things that happens inside the struct body, by definition this will just fall through and is equivalent to eval them outside the struct body.
Example
Construct a Julia struct.
julia> JLStruct(;name=:Foo, typevars=[:T], fields=[JLField(;name=:x, type=Int)])
struct Foo{T}
x::Int64
end
Decompose a Julia struct expression
julia> ex = :(struct Foo{T}
x::Int64
end)
:(struct Foo{T}
#= REPL[31]:2 =#
x::Int64
end)
julia> jl = JLStruct(ex)
struct Foo{T}
#= REPL[31]:2 =#
x::Int64
end
Generate a Julia struct expression
julia> codegen_ast(jl)
:(struct Foo{T}
#= REPL[31]:2 =#
x::Int64
end)
Expronicon.JLKwStruct
— Typemutable struct JLKwStruct <: JLExpr
JLKwStruct(;kw...)
Type describes a Julia struct that allows keyword definition of defaults. This syntax is similar to JLStruct
except the the fields are of type JLKwField
.
Fields and Keyword Arguments
All the following fields are valid as keyword arguments kw
in the constructor, and can be access via <object>.<field>
.
The only required keyword argument for the constructor is name
, the rest are all optional.
name::Symbol
: name of the struct, this is the only required keyword argument.typealias::String
: an alias of theJLKwStruct
, see also the@option
macro in Configurations.jl.ismutable::Bool
: if the struct definition is mutable.typevars::Vector{Any}
: type variables of the struct, should beSymbol
orExpr
.supertype
: supertype of the struct definition.fields::Vector{JLField}
: field definitions of the struct, should be aJLField
.constructors::Vector{JLFunction}
: constructors definitions of the struct, should beJLFunction
.line::LineNumberNode
: aLineNumberNode
to indicate the definition position for error report etc.doc::String
: documentation string of the struct.misc
: other things that happens inside the struct body, by definition this will just fall through and is equivalent to eval them outside the struct body.
Expronicon.JLIfElse
— TypeJLIfElse <: JLExpr
JLIfElse(;kw...)
JLIfElse
describes a Julia if ... elseif ... else ... end
expression. It allows one to easily construct such expression by inserting condition and code block via a map.
Fields and Keyword Arguments
All the following fields are valid as keyword arguments kw
in the constructor, and can be access via <object>.<field>
.
conds::Vector{Any}
: expression for the conditions.stmts::Vector{Any}
: expression for the statements for corresponding condition.otherwise
: theelse
body.
Example
Construct JLIfElse object
One can construct an ifelse
as following
julia> jl = JLIfElse()
nothing
julia> jl[:(foo(x))] = :(x = 1 + 1)
:(x = 1 + 1)
julia> jl[:(goo(x))] = :(y = 1 + 2)
:(y = 1 + 2)
julia> jl.otherwise = :(error("abc"))
:(error("abc"))
julia> jl
if foo(x)
x = 1 + 1
elseif goo(x)
y = 1 + 2
else
error("abc")
end
Generate the Julia Expr
object
to generate the corresponding Expr
object, one can call codegen_ast
.
julia> codegen_ast(jl)
:(if foo(x)
x = 1 + 1
elseif goo(x)
y = 1 + 2
else
error("abc")
end)
Expronicon.JLMatch
— TypeJLMatch <: JLExpr
JLMatch
describes a Julia pattern match expression defined by MLStyle
. It allows one to construct such expression by simply assign each code block to the corresponding pattern expression.
JLMatch
is not available in ExproniconLite since it depends on MLStyle's pattern matching functionality.
Example
One can construct a MLStyle
pattern matching expression easily by assigning the corresponding pattern and its result to the map
field.
julia> jl = JLMatch(:x)
#= line 0 =#
nothing
julia> jl = JLMatch(:x)
#= line 0 =#
nothing
julia> jl.map[1] = true
true
julia> jl.map[2] = :(sin(x))
:(sin(x))
julia> jl
#= line 0 =#
@match x begin
1 => true
2 => sin(x)
_ => nothing
end
to generate the corresponding Julia Expr
object, one can call codegen_ast
.
julia> codegen_ast(jl)
:(let
true
var"##return#263" = nothing
var"##265" = x
if var"##265" isa Int64
#= line 0 =#
if var"##265" === 1
var"##return#263" = let
true
end
#= unused:1 =# @goto var"####final#264#266"
end
#= line 0 =#
if var"##265" === 2
var"##return#263" = let
sin(x)
end
#= unused:1 =# @goto var"####final#264#266"
end
end
#= line 0 =#
begin
var"##return#263" = let
nothing
end
#= unused:1 =# @goto var"####final#264#266"
end
(error)("matching non-exhaustive, at #= line 0 =#")
#= unused:1 =# @label var"####final#264#266"
var"##return#263"
end)
Expronicon.JLFor
— TypeJLFor <: JLExpr
Syntax type for Julia for loop.
Expronicon.JLField
— Typemutable struct JLField <: JLExpr
JLField(;kw...)
Type describes a Julia field in a Julia struct.
Fields and Keyword Arguments
All the following fields are valid as keyword arguments kw
in the constructor, and can be access via <object>.<field>
.
The only required keyword argument for the constructor is name
, the rest are all optional.
name::Symbol
: the name of the field.type
: the type of the field.isconst
: if the field is annotated withconst
.line::LineNumberNode
: aLineNumberNode
to indicate the line information.doc::String
: the docstring of this definition.
Expronicon.JLKwField
— Typemutable struct JLKwField <: JLExpr
Type describes a Julia field that can have a default value in a Julia struct.
JLKwField(;kw...)
Create a JLKwField
instance.
Fields and Keyword Arguments
All the following fields are valid as keyword arguments kw
in the constructor, and can be access via <object>.<field>
.
The only required keyword argument for the constructor is name
, the rest are all optional.
name::Symbol
: the name of the field.type
: the type of the field.isconst
: if the field is annotated withconst
.default
: default value of the field, default isno_default
.line::LineNumberNode
: aLineNumberNode
to indicate the line information.doc::String
: the docstring of this definition.
Expronicon.NoDefault
— TypeNoDefault
Type describes a field should have no default value.
Expronicon.no_default
— Constantconst no_default = NoDefault()
Constant instance for NoDefault
that describes a field should have no default value.
Expronicon.JLExpr
— Typeabstract type JLExpr end
Abstract type for Julia syntax type.
Analysis
Functions for analysing a given Julia Expr
, e.g splitting Julia function/struct definitions etc.
Transform
Some common transformations for Julia Expr
, these functions takes an Expr
and returns an Expr
.
Expronicon.Substitute
— TypeSubstitute(condition) -> substitute(f(expr), expr)
Returns a function that substitutes expr
with f(expr)
if condition(expr)
is true. Applied recursively to all sub-expressions.
Example
julia> sub = Substitute() do expr
expr isa Symbol && expr in [:x] && return true
return false
end;
julia> sub(_->1, :(x + y))
:(1 + y)
Expronicon.alias_gensym
— MethodExpronicon.annotations_only
— Methodannotations_only(ex)
Return type annotations only. See also name_only
.
Expronicon.canonicalize_lambda_head
— Methodcanonicalize_lambda_head(ex)
Canonicalize the Expr(:function, Expr(:block, x, Expr(:(=), key, default)), body)
to
Expr(:function, Expr(:tuple, Expr(:parameters, Expr(:kw, key, default)), x), body)
Expronicon.eval_interp
— Methodeval_interp(m::Module, ex)
evaluate the interpolation operator in ex
inside given module m
.
Expronicon.eval_literal
— Methodeval_literal(m::Module, ex)
Evaluate the literal values and insert them back to the expression. The literal value can be checked via is_literal
.
Expronicon.expr_map
— Methodexpr_map(f, c...; skip_nothing::Bool=false)
Similar to Base.map
, but expects f
to return an expression, and will concanate these expression as a Expr(:block, ...)
expression.
Skip nothing
if skip_nothing
is true
.
Example
julia> expr_map(1:10, 2:11) do i,j
:(1 + $i + $j)
end
quote
1 + 1 + 2
1 + 2 + 3
1 + 3 + 4
1 + 4 + 5
1 + 5 + 6
1 + 6 + 7
1 + 7 + 8
1 + 8 + 9
1 + 9 + 10
1 + 10 + 11
end
Expronicon.flatten_blocks
— Methodflatten_blocks(ex)
Remove hierachical expression blocks.
Expronicon.name_only
— Methodname_only(ex)
Remove everything else leaving just names, currently supports function calls, type with type variables, subtype operator <:
and type annotation ::
.
Example
julia> using Expronicon
julia> name_only(:(sin(2)))
:sin
julia> name_only(:(Foo{Int}))
:Foo
julia> name_only(:(Foo{Int} <: Real))
:Foo
julia> name_only(:(x::Int))
:x
Expronicon.nexprs
— Methodnexprs(f, n::Int)
Create n
similar expressions by evaluating f
.
Example
julia> nexprs(5) do k
:(1 + $k)
end
quote
1 + 1
1 + 2
1 + 3
1 + 4
1 + 5
end
Expronicon.prettify
— Methodprettify(ex; kw...)
Prettify given expression, remove all LineNumberNode
and extra code blocks.
Options (Kwargs)
All the options are true
by default.
rm_lineinfo
: removeLineNumberNode
.flatten_blocks
: flattenbegin ... end
code blocks.rm_nothing
: removenothing
in thebegin ... end
.preserve_last_nothing
: preserve the lastnothing
in thebegin ... end
.rm_single_block
: remove singlebegin ... end
.alias_gensym
: replace##<name>#<num>
with<name>_<id>
.renumber_gensym
: renumber the gensym id.
the LineNumberNode
inside macro calls won't be removed since the macrocall
expression requires a LineNumberNode
. See also issues/#9.
Expronicon.renumber_gensym
— Methodrenumber_gensym(ex)
Re-number gensym with counter from this expression. Produce a deterministic gensym name for testing etc. See also: alias_gensym
Expronicon.rm_annotations
— Methodrm_annotations(x)
Remove type annotation of given expression.
Expronicon.rm_lineinfo
— Methodrm_lineinfo(ex)
Remove LineNumberNode
in a given expression.
the LineNumberNode
inside macro calls won't be removed since the macrocall
expression requires a LineNumberNode
. See also issues/#9.
Expronicon.rm_nothing
— Methodrm_nothing(ex)
Remove the constant value nothing
in given expression ex
.
Keyword Arguments
preserve_last_nothing
: iftrue
, the lastnothing
will be preserved.
Expronicon.substitute
— Methodsubstitute(ex::Expr, old=>new)
Substitute the old symbol old
with new
.
CodeGen
Code generators, functions that generates Julia Expr
from given arguments, Expronicon
types.
Expronicon.codegen_ast
— Methodcodegen_ast(def)
Generate Julia AST object Expr
from a given syntax type.
Example
One can generate the Julia AST object from a JLKwStruct
syntax type.
julia> def = @expr JLKwStruct struct Foo{N, T}
x::T = 1
end
#= kw =# struct Foo{N, T}
#= REPL[19]:2 =#
x::T = 1
end
julia> codegen_ast(def)|>rm_lineinfo
quote
struct Foo{N, T}
x::T
end
begin
function Foo{N, T}(; x = 1) where {N, T}
Foo{N, T}(x)
end
function Foo{N}(; x::T = 1) where {N, T}
Foo{N, T}(x)
end
end
end
Expronicon.codegen_ast_fields
— Methodcodegen_ast_fields(fields; just_name::Bool=true)
Generate a list of Julia AST object for each field, only generate a list of field names by default, option just_name
can be turned off to call codegen_ast
on each field object.
Expronicon.codegen_ast_kwfn
— Functioncodegen_ast_kwfn(def[, name = nothing])
Generate the keyword function from a Julia struct definition.
Example
julia> def = @expr JLKwStruct struct Foo{N, T}
x::T = 1
end
#= kw =# struct Foo{N, T}
#= REPL[19]:2 =#
x::T = 1
end
julia> codegen_ast_kwfn(def)|>prettify
quote
function Foo{N, T}(; x = 1) where {N, T}
Foo{N, T}(x)
end
function Foo{N}(; x::T = 1) where {N, T}
Foo{N, T}(x)
end
end
julia> def = @expr JLKwStruct struct Foo
x::Int = 1
end
#= kw =# struct Foo
#= REPL[23]:2 =#
x::Int = 1
end
julia> codegen_ast_kwfn(def)|>prettify
quote
function Foo(; x = 1)
Foo(x)
end
nothing
end
Expronicon.codegen_ast_kwfn_infer
— Functioncodegen_ast_kwfn_infer(def, name = nothing)
Generate the keyword function that infers the type.
Expronicon.codegen_ast_kwfn_plain
— Functioncodegen_ast_kwfn_plain(def[, name = nothing])
Generate the plain keyword function that does not infer type variables. So that one can use the type conversions defined by constructors.
Expronicon.codegen_ast_struct
— Methodcodegen_ast_struct(def)
Generate pure Julia struct Expr
from struct definition. This is equivalent to codegen_ast
for JLStruct
. See also codegen_ast
.
Example
julia> def = JLKwStruct(:(struct Foo
x::Int=1
Foo(x::Int) = new(x)
end))
struct Foo
x::Int = 1
end
julia> codegen_ast_struct(def)
:(struct Foo
#= REPL[21]:2 =#
x::Int
Foo(x::Int) = begin
#= REPL[21]:4 =#
new(x)
end
end)
Expronicon.codegen_ast_struct_body
— Methodcodegen_ast_struct_body(def)
Generate the struct body.
Example
julia> def = JLStruct(:(struct Foo
x::Int
Foo(x::Int) = new(x)
end))
struct Foo
x::Int
end
julia> codegen_ast_struct_body(def)
quote
#= REPL[15]:2 =#
x::Int
Foo(x::Int) = begin
#= REPL[15]:4 =#
new(x)
end
end
Expronicon.codegen_ast_struct_head
— Methodcodegen_ast_struct_head(def)
Generate the struct head.
Example
julia> using Expronicon
julia> def = JLStruct(:(struct Foo{T} end))
struct Foo{T}
end
julia> codegen_ast_struct_head(def)
:(Foo{T})
julia> def = JLStruct(:(struct Foo{T} <: AbstractArray end))
struct Foo{T} <: AbstractArray
end
julia> codegen_ast_struct_head(def)
:(Foo{T} <: AbstractArray)
Expronicon.struct_name_plain
— Methodstruct_name_plain(def)
Plain constructor name. See also struct_name_without_inferable
.
Example
julia> def = @expr JLKwStruct struct Foo{N, Inferable}
x::Inferable = 1
end
julia> struct_name_plain(def)
:(Foo{N, Inferable})
Expronicon.struct_name_without_inferable
— Methodstruct_name_without_inferable(def; leading_inferable::Bool=true)
Constructor name that assume some of the type variables is inferred. See also struct_name_plain
. The kwarg leading_inferable
can be used to configure whether to preserve the leading inferable type variables, the default is true
to be consistent with the default julia constructors.
Example
julia> def = @expr JLKwStruct struct Foo{N, Inferable}
x::Inferable = 1
end
julia> struct_name_without_inferable(def)
:(Foo{N})
julia> def = @expr JLKwStruct struct Foo{Inferable, NotInferable}
x::Inferable
end
julia> struct_name_without_inferable(def; leading_inferable=true)
:(Foo{Inferable, NotInferable})
julia> struct_name_without_inferable(def; leading_inferable=false)
:(Foo{NotInferable})
Expronicon.xcall
— Methodxcall(name, args...; kw...)
Create a function call to name
.
Expronicon.xcall
— Methodxcall(m::Module, name::Symbol, args...; kw...)
Create a function call to GlobalRef(m, name)
.
due to Revise/#616, to make your macro work with Revise, we use the dot expression Expr(:., <module>, QuoteNode(<name>))
instead of GlobalRef
here.
Expronicon.xfirst
— Methodxfirst(collection)
Create a function call expression to Base.first
.
Expronicon.xgetindex
— Methodxgetindex(collection, key...)
Create a function call expression to Base.getindex
.
Expronicon.xiterate
— Methodxiterate(it, st)
Create a function call expression to Base.iterate
.
Expronicon.xiterate
— Methodxiterate(it)
Create a function call expression to Base.iterate
.
Expronicon.xlast
— Methodxlast(collection)
Create a function call expression to Base.last
.
Expronicon.xmap
— Methodxmap(f, xs...)
Create a function call expression to Base.map
.
Expronicon.xmapreduce
— Methodxmapreduce(f, op, xs...)
Create a function call expression to Base.mapreduce
.
Expronicon.xnamedtuple
— Methodxnamedtuple(;kw...)
Create a NamedTuple
expression.
Expronicon.xprint
— Methodxprint(xs...)
Create a function call expression to Base.print
.
Expronicon.xprintln
— Methodxprintln(xs...)
Create a function call expression to Base.println
.
Expronicon.xpush
— Methodxpush(collection, items...)
Create a function call expression to Base.push!
.
Expronicon.xtuple
— Methodxtuple(xs...)
Create a Tuple
expression.
Printings
Pretty printing functions.
Algebra Data Type
Algebra data type