ExproniconLite.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.
ExproniconLite.JLForMethod
JLFor(kernel, iterators::Vector)

Convenient constructor for creating multiple loop expression from a list of iterators.

Example

julia> JLFor([:it1, :it2, :it3]) do i, j, k
    :(kernel_function_call($i, $j, $k))
end
for ##i#291 = it1, ##i#292 = it2, ##i#293 = it3
    kernel_function_call(##i#291, ##i#292, ##i#293)
end
ExproniconLite.JLForMethod
JLFor(ex::Expr)

Create a JLFor from given Julia for loop expression.

Example

julia> ex = @expr for i in 1:10, j in 1:j
           M[i, j] += 1
       end
:(for i = 1:10, j = 1:j
      #= REPL[3]:2 =#
      M[i, j] += 1
  end)

julia> jl = JLFor(ex)
for i in 1 : 10,
    j in 1 : j
    #= loop body =#
    begin
        #= REPL[3]:2 =#        
        M[i, j] += 1        
    end
end

julia> jl.vars
2-element Vector{Any}:
 :i
 :j

julia> jl.iterators
2-element Vector{Any}:
 :(1:10)
 :(1:j)
ExproniconLite.JLForMethod
JLFor(;vars=[], iterators=[], kernel=nothing)

Generate a JLFor object.

Kwargs

  • vars: loop variables.
  • iterators: loop iterators.
  • kernel: loop kernel.
ExproniconLite.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)
ExproniconLite.JLFunctionMethod
JLFunction(ex::Expr)

Create a JLFunction object from a Julia function Expr.

Example

julia> JLFunction(:(f(x) = 2))
f(x) = begin
    #= REPL[37]:1 =#    
    2    
end
ExproniconLite.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)
ExproniconLite.JLIfElseMethod
JLIfElse(ex::Expr)

Create a JLIfElse from given Julia ifelse Expr.

Example

julia> ex = :(if foo(x)
             x = 1 + 1
         elseif goo(x)
             y = 1 + 2
         else
             error("abc")
         end)
:(if foo(x)
      #= REPL[41]:2 =#
      x = 1 + 1
  elseif #= REPL[41]:3 =# goo(x)
      #= REPL[41]:4 =#
      y = 1 + 2
  else
      #= REPL[41]:6 =#
      error("abc")
  end)

julia> JLIfElse(ex)
if foo(x)
    begin
        #= REPL[41]:2 =#        
        x = 1 + 1        
    end
elseif begin
    #= REPL[41]:3 =#    
    goo(x)    
end
    begin
        #= REPL[41]:4 =#        
        y = 1 + 2        
    end
else
    begin
        #= REPL[41]:6 =#        
        error("abc")        
    end
end
ExproniconLite.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.
ExproniconLite.JLKwStructType
JLKwStruct(ex::Expr, typealias=nothing)

Create a JLKwStruct from given Julia struct Expr, with an option to attach an alias to this type name.

Example

julia> JLKwStruct(:(struct Foo
           x::Int = 1
       end))
#= kw =# struct Foo
    #= REPL[39]:2 =#
    x::Int = 1
end
ExproniconLite.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.
ExproniconLite.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)
ExproniconLite.JLStructMethod
JLStruct(ex::Expr)

Create a JLStruct object from a Julia struct Expr.

Example

julia> JLStruct(:(struct Foo
           x::Int
       end))
struct Foo
    #= REPL[38]:2 =#
    x::Int
end
ExproniconLite.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)
ExproniconLite.assert_equal_exprMethod
assert_equal_expr(m::Module, lhs, rhs)

Assert that lhs and rhs are equal in m. Throw an ExprNotEqual if they are not equal.

ExproniconLite.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)
ExproniconLite.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
ExproniconLite.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.

ExproniconLite.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
ExproniconLite.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.

ExproniconLite.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)
ExproniconLite.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
ExproniconLite.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)
ExproniconLite.compare_exprMethod
compare_expr([m=Main], lhs, rhs)

Compare two expression of type Expr or Symbol semantically, which:

  1. ignore the detail value LineNumberNode in comparision;
  2. ignore the detailed name of typevars declared by where;
  3. recognize inserted objects and Symbol, e.g :($Int) is equal to :(Int);
  4. recognize QuoteNode(:x) and Symbol("x") as equal;
  5. will guess module and type objects and compare their value directly instead of their expression;
Tips

This function is usually combined with prettify with preserve_last_nothing=true and alias_gensym=false.

This gives a way to compare two Julia expression semantically which means although some details of the expression is different but they should produce the same lowered code.

ExproniconLite.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
ExproniconLite.guess_moduleMethod
guess_module(m, ex)

Guess the module of given expression ex (of a module) in module m. If ex is not a module, or cannot be determined return nothing.

ExproniconLite.guess_typeMethod
guess_type(m::Module, ex)

Guess the actual type of expression ex (of a type) in module m. Returns the type if it can be determined, otherwise returns the expression. This function is used in compare_expr.

ExproniconLite.has_kwfn_constructorFunction
has_kwfn_constructor(def[, name = struct_name_plain(def)])

Check if the struct definition contains keyword function constructor of name. The constructor name to check by default is the plain constructor which does not infer any type variables and requires user to input all type variables. See also struct_name_plain.

ExproniconLite.has_plain_constructorFunction
has_plain_constructor(def, name = struct_name_plain(def))

Check if the struct definition contains the plain constructor of name. By default the name is the inferable name struct_name_plain.

Example

def = @expr JLKwStruct struct Foo{T, N}
    x::Int
    y::N

    Foo{T, N}(x, y) where {T, N} = new{T, N}(x, y)
end

has_plain_constructor(def) # true

def = @expr JLKwStruct struct Foo{T, N}
    x::T
    y::N

    Foo(x, y) = new{typeof(x), typeof(y)}(x, y)
end

has_plain_constructor(def) # false

the arguments must have no type annotations.

def = @expr JLKwStruct struct Foo{T, N}
    x::T
    y::N

    Foo{T, N}(x::T, y::N) where {T, N} = new{T, N}(x, y)
end

has_plain_constructor(def) # false
ExproniconLite.is_datatype_exprMethod
is_datatype_expr(ex)

Check if ex is an expression for a concrete DataType, e.g where is not allowed in the expression.

ExproniconLite.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
ExproniconLite.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
ExproniconLite.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.

ExproniconLite.print_exprMethod
print_expr([io::IO], ex; kw...)

Print a given expression. ex can be a Expr or a syntax type JLExpr.

ExproniconLite.print_inlineMethod
print_expr([io::IO], ex; kw...)

Print a given expression within one line. ex can be a Expr or a syntax type JLExpr.

ExproniconLite.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.

ExproniconLite.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.
ExproniconLite.split_anonymous_function_headMethod
split_anonymous_function_head(ex::Expr) -> nothing, args, kw, whereparams, rettype

Split anonymous function head to arguments, keyword arguments and where parameters.

ExproniconLite.split_field_if_matchFunction
split_field_if_match(typename::Symbol, expr, default::Bool=false)

Split the field definition if it matches the given type name. Returns NamedTuple with name, type, default and isconst fields if it matches, otherwise return nothing.

ExproniconLite.split_function_headMethod
split_function_head(ex::Expr) -> name, args, kw, whereparams, rettype

Split function head to name, arguments, keyword arguments and where parameters.

ExproniconLite.split_structMethod
split_struct(ex::Expr) -> ismutable, name, typevars, supertype, body

Split struct definition head and body.

ExproniconLite.split_struct_nameMethod
split_struct_name(ex::Expr) -> name, typevars, supertype

Split the name, type parameters and supertype definition from struct declaration head.

ExproniconLite.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})
ExproniconLite.uninferrable_typevarsMethod
uninferrable_typevars(def::Union{JLStruct, JLKwStruct}; leading_inferable::Bool=true)

Return the type variables that are not inferrable in given struct definition.

ExproniconLite.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.

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

Create a function call expression to Base.push!.

ExproniconLite.@exprMacro
@expr <type> <expression>

Return the expression in given type.

Example

julia> ex = @expr JLKwStruct struct Foo{N, T}
           x::T = 1
       end
#= kw =# struct Foo{N, T}
    #= /home/roger/code/julia/Expronicon/test/analysis.jl:5 =#
    x::T = 1
end
ExproniconLite.@exprMacro
@expr <expression>

Return the original expression object.

Example

julia> ex = @expr x + 1
:(x + 1)
ExproniconLite.@test_exprMacro
@test_expr <type> <ex>

Test if the syntax type generates the same expression ex. Returns the corresponding syntax type instance. Requires using Test before using this macro.

Example

def = @test_expr JLFunction function (x, y)
    return 2
end
@test is_kw_fn(def) == false
ExproniconLite.@test_exprMacro
@test_expr <expr> == <expr>

Test if two expression is equivalent semantically, this uses compare_expr to decide if they are equivalent, ignores things such as LineNumberNode generated Symbol in Expr(:curly, ...) or Expr(:where, ...).

Note

This macro requires one using Test to import the Test module name.