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.JLFunctionType
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 type Nothing, Symbol or Expr, default is nothing.
  • args: optional, function arguments, a list of Expr or Symbol.
  • kwargs: optional, function keyword arguments, a list of Expr(:kw, name, default).
  • rettype: optional, the explicit return type of a function, can be a Type, Symbol, Expr or just nothing, default is nothing.
  • generated: optional, if this is a generated function.
  • whereparams: optional, type variables, can be a list of Type, Expr or nothing, default is nothing.
  • body: optional, function body, an Expr, default is Expr(:block).
  • line::LineNumberNode: a LineNumberNode 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.JLStructType
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 be Symbol or Expr.
  • supertype: supertype of the struct definition.
  • fields::Vector{JLField}: field definitions of the struct, should be a JLField.
  • constructors::Vector{JLFunction}: constructors definitions of the struct, should be JLFunction.
  • line::LineNumberNode: a LineNumberNode 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.JLKwStructType
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 the JLKwStruct, 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 be Symbol or Expr.
  • supertype: supertype of the struct definition.
  • fields::Vector{JLField}: field definitions of the struct, should be a JLField.
  • constructors::Vector{JLFunction}: constructors definitions of the struct, should be JLFunction.
  • line::LineNumberNode: a LineNumberNode 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.JLIfElseType
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: the else 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.JLMatchType
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> 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.JLFieldType
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 with const.
  • line::LineNumberNode: a LineNumberNode to indicate the line information.
  • doc::String: the docstring of this definition.
Expronicon.JLKwFieldType
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 with const.
  • default: default value of the field, default is no_default.
  • line::LineNumberNode: a LineNumberNode to indicate the line information.
  • doc::String: the docstring of this definition.
Expronicon.JLExprType
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.SubstituteType
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> sub = Substitute() do expr
           expr isa Symbol && expr in [:x] && return true
           return false
       end;

julia> sub(_->1, :(x + y))
:(1 + y)
Expronicon.canonicalize_lambda_headMethod
canonicalize_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_interpMethod
eval_interp(m::Module, ex)

evaluate the interpolation operator in ex inside given module m.

Expronicon.eval_literalMethod
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_mapMethod
expr_map(f, c...)

Similar to Base.map, but expects f to return an expression, and will concanate these expression as a Expr(:block, ...) expression.

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.name_onlyMethod
name_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.nexprsMethod
nexprs(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.prettifyMethod
prettify(ex; kw...)

Prettify given expression, remove all LineNumberNode and extra code blocks.

Options (Kwargs)

All the options are true by default.

  • rm_lineinfo: remove LineNumberNode.
  • flatten_blocks: flatten begin ... end code blocks.
  • rm_nothing: remove nothing in the begin ... end.
  • preserve_last_nothing: preserve the last nothing in the begin ... end.
  • rm_single_block: remove single begin ... 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.rm_lineinfoMethod
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_nothingMethod
rm_nothing(ex)

Remove the constant value nothing in given expression ex.

Keyword Arguments

  • preserve_last_nothing: if true, the last nothing will be preserved.

CodeGen

Code generators, functions that generates Julia Expr from given arguments, Expronicon types.

Expronicon.codegen_astMethod
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> 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_fieldsMethod
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_kwfnFunction
codegen_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_plainFunction
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_structMethod
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> 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_bodyMethod
codegen_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_headMethod
codegen_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_without_inferableMethod
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> 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.xcallMethod
xcall(name, args...; kw...)

Create a function call to name.

Expronicon.xcallMethod
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.xfirstMethod
xfirst(collection)

Create a function call expression to Base.first.

Expronicon.xgetindexMethod
xgetindex(collection, key...)

Create a function call expression to Base.getindex.

Expronicon.xiterateMethod
xiterate(it, st)

Create a function call expression to Base.iterate.

Expronicon.xlastMethod
xlast(collection)

Create a function call expression to Base.last.

Expronicon.xmapMethod
xmap(f, xs...)

Create a function call expression to Base.map.

Expronicon.xmapreduceMethod
xmapreduce(f, op, xs...)

Create a function call expression to Base.mapreduce.

Expronicon.xprintMethod
xprint(xs...)

Create a function call expression to Base.print.

Expronicon.xprintlnMethod
xprintln(xs...)

Create a function call expression to Base.println.

Expronicon.xpushMethod
xpush(collection, items...)

Create a function call expression to Base.push!.

Printings

Pretty printing functions.

Algebra Data Type

Algebra data type