# \[ANN\] Expronicon.jl - meta programming made easy

**URL:** <https://discourse.julialang.org/t/ann-expronicon-jl-meta-programming-made-easy/57765>\
**Category:** Package Announcements\
**Tags:** package, announcement, metaprogramming\
**Created:** [March 23, 2021, 3:57am UTC](https://discourse.julialang.org/t/ann-expronicon-jl-meta-programming-made-easy/57765 "2021-03-23T03:57:23Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Roger-luo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roger-luo/32/3399_2.png) [@Roger-luo](https://discourse.julialang.org/u/Roger-luo)\
**Post date:** [March 23, 2021, 3:57am UTC](https://discourse.julialang.org/t/ann-expronicon-jl-meta-programming-made-easy/57765/1 "2021-03-23T03:57:23Z")

</div>

I created a new package [Expronicon.jl](https://github.com/Roger-luo/Expronicon.jl) to wrap up some meta-programming tools on Julia’s `Expr` I wrote in the past year using [MLStyle](https://github.com/thautwarm/MLStyle.jl) The goal of Expronicon is to serve as a stdlib for MLStyle for meta programming Julia `Expr`

This package provides a few tools as following

# Syntax Types

In many other meta programming packages, such as MacroTools, ExprTools etc. one often use a function called `split_function` to split function components into a `Dict` for easy manipulation and construction, Expronicon moves one step further, it defines several more types for easy manipulation:

1. `JLFunction`: similar to what generated by `split_function` but is a Julia struct, this allows pretty printing and method dispatches:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/1/6/16d6aa23f6eb1333747cdd1ba8f30856868fa50c.jpeg)

1. `JLStruct`: represents a normal Julia struct syntax

 ![image](https://global.discourse-cdn.com/julialang/original/3X/6/1/61cbc4a4bf4da59976057d303d817d2e3e4ec59b.jpeg)

1. `JLKwStruct`: represents keyword struct syntax (similar to `JLStruct`)

 ![image](https://global.discourse-cdn.com/julialang/original/3X/0/c/0c9832a0d1403fd25fa4e52c49755b6cf31888fb.jpeg)

1. `JLIfElse`: represent Julia ifelse statements, this uses a dictionary to store conditions and their corresponding code block

### Construct JLIfElse object

One can construct an `ifelse` as following

```julia
julia> jl = JLIfElse()
nothing

julia> jl.map[:(foo(x))] = :(x = 1 + 1)
:(x = 1 + 1)

julia> jl.map[:(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)

```

1. `JLMatch`

`JLMatch` describes a Julia pattern match expression defined by  
[`MLStyle`](https://github.com/thautwarm/MLStyle.jl). It allows  
one to construct such expression by simply assign each code block  
to the corresponding pattern expression.

# 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)

```

## Others

other features include transformations, analysis path, pretty printings etc.

---

<div class="post-metadata">

**Author:** ![tisztamo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tisztamo/32/16200_2.png) [@tisztamo](https://discourse.julialang.org/u/tisztamo)\
**Post date:** [March 23, 2021, 8:36am UTC](https://discourse.julialang.org/t/ann-expronicon-jl-meta-programming-made-easy/57765/2 "2021-03-23T08:36:56Z")

</div>

That looks great, thank you!

I have recently struggled a lot with nested quotes while turning a function into a generated one by a macro, and I had the feeling that I need a higher level API.

Based on the experience I will stay away from manipulating the AST for as long as possible, but next time I must do it, I will definitely learn to use MLStyle and Expronicon! 🙂

---

<div class="post-metadata">

**Author:** ![Roger-luo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roger-luo/32/3399_2.png) [@Roger-luo](https://discourse.julialang.org/u/Roger-luo)\
**Post date:** [April 6, 2021, 5:58am UTC](https://discourse.julialang.org/t/ann-expronicon-jl-meta-programming-made-easy/57765/3 "2021-04-06T05:58:41Z")

</div>

As the stdlib for MLStyle, we support using syntax type for pattern matching now

```julia
using MLStyle
using Expronicon

f = @λ begin
   JLFunction(;name=:foo, args) => (args, )
   JLFunction(;name=:boo, args) => (args, )
   _ => nothing
end

ex_foo = @expr function foo(x::Int, y::T) where {T <: Real}
    x + y
end

ex_boo = @expr function foo(x::Int)
    x
end

```

this gives

```julia
julia> f(ex_foo)
(Any[:(x::Int), :(y::T)],)

julia> f(ex_boo)
(Any[:(x::Int)],)

```

You can use **most of the built-in syntax types** (there is only `JLMatch` doesn’t support this since it’s mainly used for code generation) as your expression template to match using MLStyle. If you define your own syntax type, you can also support pattern matching via [`@syntax_pattern`](https://rogerluo.me/Expronicon.jl/dev/#Expronicon.@syntax_pattern).

* * *

Except this, I have added a bunch of new tools into Expronicon as well as a quick start guide for metaprogramming in Julia: [Quick Start · Expronicon.jl](https://rogerluo.dev/Expronicon.jl/dev/)

Now some of my other packages have been rewritten using Expronicon. The test coverage has been pushed to 95%, It should be stable enough to provide you a modern metaprogramming experience along with MLStyle now.
