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
— Type.
julia
mutable 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
.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
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
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
julia> codegen_ast(jl)
:(function foo(x::T) where T
#= REPL[26]:1 =#
#= REPL[26]:3 =#
1 + 1
end)
#Expronicon.JLStruct
— Type.
julia
mutable 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
julia> JLStruct(;name=:Foo, typevars=[:T], fields=[JLField(;name=:x, type=Int)])
struct Foo{T}
x::Int64
end
Decompose a Julia struct expression
julia
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
julia> codegen_ast(jl)
:(struct Foo{T}
#= REPL[31]:2 =#
x::Int64
end)
#Expronicon.JLKwStruct
— Type.
julia
mutable 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
— Type.
julia
JLIfElse <: 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
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
julia> codegen_ast(jl)
:(if foo(x)
x = 1 + 1
elseif goo(x)
y = 1 + 2
else
error("abc")
end)
#Expronicon.JLMatch
— Type.
julia
JLMatch <: 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.
!!! tip 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
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
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
— Type.
julia
JLFor <: JLExpr
Syntax type for Julia for loop.
#Expronicon.JLField
— Type.
julia
mutable 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
— Type.
julia
mutable 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
— Type.
julia
NoDefault
Type describes a field should have no default value.
#Expronicon.no_default
— Constant.
julia
const no_default = NoDefault()
Constant instance for NoDefault
that describes a field should have no default value.
#Expronicon.JLExpr
— Type.
julia
abstract 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
— Type.
julia
Substitute(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
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
— Method.
julia
alias_gensym(ex)
Replace gensym with <name>_<id>
.
!!! note Borrowed from MacroTools.
#Expronicon.annotations_only
— Method.
julia
annotations_only(ex)
Return type annotations only. See also name_only
.
#Expronicon.eval_interp
— Method.
julia
eval_interp(m::Module, ex)
evaluate the interpolation operator in ex
inside given module m
.
#Expronicon.eval_literal
— Method.
julia
eval_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
— Method.
julia
expr_map(f, c...)
Similar to Base.map
, but expects f
to return an expression, and will concatenate these expression as a Expr(:block, ...)
expression.
Example
julia
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
— Method.
julia
flatten_blocks(ex)
Remove hierarchical expression blocks.
#Expronicon.name_only
— Method.
julia
name_only(ex)
Remove everything else leaving just names, currently supports function calls, type with type variables, subtype operator <:
and type annotation ::
.
Example
julia
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
— Method.
julia
nexprs(f, n::Int)
Create n
similar expressions by evaluating f
.
Example
julia
julia> nexprs(5) do k
:(1 + $k)
end
quote
1 + 1
1 + 2
1 + 3
1 + 4
1 + 5
end
#Expronicon.prettify
— Method.
julia
prettify(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.
!!! tips the LineNumberNode
inside macro calls won't be removed since the macrocall
expression requires a LineNumberNode
. See also issues/#9.
#Expronicon.renumber_gensym
— Method.
julia
renumber_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
— Method.
julia
rm_annotations(x)
Remove type annotation of given expression.
#Expronicon.rm_lineinfo
— Method.
julia
rm_lineinfo(ex)
Remove LineNumberNode
in a given expression.
!!! tips the LineNumberNode
inside macro calls won't be removed since the macrocall
expression requires a LineNumberNode
. See also issues/#9.
#Expronicon.rm_nothing
— Method.
julia
rm_nothing(ex)
Remove the constant value nothing
in given expression ex
.
Keyword Arguments
preserve_last_nothing
: iftrue
, the lastnothing
will be preserved.
#Expronicon.substitute
— Method.
julia
substitute(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
— Method.
julia
codegen_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
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
— Method.
julia
codegen_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
— Function.
julia
codegen_ast_kwfn(def[, name = nothing])
Generate the keyword function from a Julia struct definition.
Example
julia
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
— Function.
julia
codegen_ast_kwfn_infer(def, name = nothing)
Generate the keyword function that infers the type.
#Expronicon.codegen_ast_kwfn_plain
— Function.
julia
codegen_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
— Method.
julia
codegen_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
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
— Method.
julia
codegen_ast_struct_body(def)
Generate the struct body.
Example
julia
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
— Method.
julia
codegen_ast_struct_head(def)
Generate the struct head.
Example
julia
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
— Method.
julia
struct_name_plain(def)
Plain constructor name. See also struct_name_without_inferable
.
Example
julia
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
— Method.
julia
struct_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
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
— Method.
julia
xcall(name, args...; kw...)
Create a function call to name
.
#Expronicon.xcall
— Method.
julia
xcall(m::Module, name::Symbol, args...; kw...)
Create a function call to GlobalRef(m, name)
.
!!! tip 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
— Method.
julia
xfirst(collection)
Create a function call expression to Base.first
.
#Expronicon.xgetindex
— Method.
julia
xgetindex(collection, key...)
Create a function call expression to Base.getindex
.
#Expronicon.xiterate
— Method.
julia
xiterate(it, st)
Create a function call expression to Base.iterate
.
#Expronicon.xiterate
— Method.
julia
xiterate(it)
Create a function call expression to Base.iterate
.
#Expronicon.xlast
— Method.
julia
xlast(collection)
Create a function call expression to Base.last
.
#Expronicon.xmap
— Method.
julia
xmap(f, xs...)
Create a function call expression to Base.map
.
#Expronicon.xmapreduce
— Method.
julia
xmapreduce(f, op, xs...)
Create a function call expression to Base.mapreduce
.
#Expronicon.xnamedtuple
— Method.
julia
xnamedtuple(;kw...)
Create a NamedTuple
expression.
#Expronicon.xprint
— Method.
julia
xprint(xs...)
Create a function call expression to Base.print
.
#Expronicon.xprintln
— Method.
julia
xprintln(xs...)
Create a function call expression to Base.println
.
#Expronicon.xpush
— Method.
julia
xpush(collection, items...)
Create a function call expression to Base.push!
.
#Expronicon.xtuple
— Method.
julia
xtuple(xs...)
Create a Tuple
expression.
Printings
Pretty printing functions.
Algebra Data Type
Algebra data type