Skip to content

Commit

Permalink
setup project
Browse files Browse the repository at this point in the history
  • Loading branch information
Roger-luo committed Sep 21, 2023
1 parent 912270f commit 0996cde
Show file tree
Hide file tree
Showing 16 changed files with 333 additions and 2 deletions.
3 changes: 2 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
name = "Liang"
uuid = "689e9e03-1340-4615-b78b-52f74a012268"
authors = ["Roger-luo<[email protected]>",]
authors = ["Roger-luo<[email protected]>"]
version = "0.1.0"

[deps]
ExproniconLite = "55351af7-c7e9-48d6-89ff-24e801d99491"

[compat]
julia = "1.10"
6 changes: 5 additions & 1 deletion src/Liang.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
module Liang

# write your code here
include("data/mod.jl")
include("expr/mod.jl")
include("rewrite/mod.jl")
include("rules/mod.jl")
include("target/mod.jl")

end # Liang
7 changes: 7 additions & 0 deletions src/data/err.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Base.@kwdef struct SyntaxError <: Exception
msg::String
end

function Base.showerror(io::IO, e::SyntaxError)
print(io, e.msg)
end
19 changes: 19 additions & 0 deletions src/data/macro.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# @data MyADT begin
# Foo
# Bar(Int, Float64)

# struct Baz
# x::Int
# y::Float64
# z::Vector{MyADT}
# end
# end

macro data(name::Symbol, expr)
return esc(data_m(name, expr))
end

function data_m(name::Symbol, expr)
expr isa Expr || throw(SyntaxError("Expected an \
expression, got $(typeof(expr)): $expr"))
end
15 changes: 15 additions & 0 deletions src/data/mod.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
Provides the Algebraic Data Types (ADTs) for the project.
"""
module Data

using ExproniconLite: JLKwField, JLKwStruct, rm_lineinfo, rm_nothing, no_default

include("err.jl")
include("macro.jl")
include("syntax.jl")
include("scan.jl")
include("show.jl")


end # Data
24 changes: 24 additions & 0 deletions src/data/scan.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
struct SizeInfo
tag::Int
bits::Int
ptrs::Int
end

struct FieldInfo
var::Symbol
expr::Union{Symbol,Expr}
is_bitstype::Bool
type_guess # eval-ed type
end

struct VariantInfo
def::Variant
tag::UInt8
fields::Vector{FieldInfo}
end

struct EmitInfo
def::TypeDef
size::SizeInfo
variants::Dict{Variant, VariantInfo}
end
114 changes: 114 additions & 0 deletions src/data/show.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
struct FormatPrinter{IO_t, Indent, Leading, Print, PrintLn, Unquoted, Show, Sep}
io::IO_t
indent::Indent
leading::Leading
print::Print
println::PrintLn
unquoted::Unquoted
show::Show
sep::Sep
end

function FormatPrinter(io::IO)
indent(n::Int) = Base.print(io, ' ' ^ n)
leading() = indent(get(io, :indent, 0))
print(xs...; kw...) = Base.printstyled(io, xs...; kw...)
println(xs...; kw...) = begin
Base.printstyled(io, xs..., '\n'; kw...)
leading()
end
print_unquoted(xs...; kw...) = print(Base.sprint(Base.show_unquoted, xs...); kw...)
show(mime, x) = Base.show(io, mime, x)
show(x) = Base.show(io, x)

function sep(left, right, trim::Int = 20)
_, width = displaysize(io)
width = min(width, 80)
nindent = get(io, :indent, 0)
ncontent = textwidth(string(left)) - textwidth(string(right))
nsep = max(0, width - nindent - trim - ncontent)
print(" ", "-"^nsep, " "; color=:light_black)
end

FormatPrinter(io,
indent, leading,
print, println,
print_unquoted,
show, sep
)
end

function indent(f::FormatPrinter, n::Int = 4)
FormatPrinter(IOContext(f.io, :indent=>get(f.io, :indent, 0) + n))
end

function Base.show(io::IO, ::MIME"text/plain", var::TypeVar)
isnothing(var.lower) || printstyled(io, var.lower, " <: "; color=:light_cyan)
printstyled(io, var.name; color=:light_cyan)
isnothing(var.upper) || printstyled(io, " <: ", var.upper; color=:light_cyan)
end

function Base.show(io::IO, ::MIME"text/plain", var::Variant)
f = FormatPrinter(io)
f.leading()
isnothing(var.source) || f.println(var.source; color=:light_black)
if var.kind === Named
var.is_mutable && f.print("mutable "; color=:red)
f.print("struct "; color=:red)
f.print(var.name)

ff = indent(f)
for field in var.fields::Vector{NamedField}
ff.println()
isnothing(field.source) || (ff.println(field.source; color=:light_black))
ff.print(field.name)
ff.print("::"; color=:red)
ff.unquoted(field.type; color=:light_cyan)
if field.default !== no_default
ff.print(" = "; color=:red)
ff.unquoted(field.default; color=:light_cyan)
end
end
f.println()
f.print("end"; color=:red)
elseif var.kind === Anonymous
f.print(var.name)
f.print('('; color=:red)
fields = var.fields::Vector{Field}
if !isempty(fields)
f.unquoted(fields[1].type; color=:light_cyan)
for each in fields[2:end]
f.print(", ")
f.unquoted(each.type; color=:light_cyan)
end
end
f.print(')'; color=:red)
else # Singleton
f.print(var.name)
end
end

function Base.show(io::IO, mime::MIME"text/plain", def::TypeDef)
f = FormatPrinter(io); f.leading()

isnothing(def.source) || f.println(def.source; color=:light_black)
f.print("@data "; color=:red)
f.print(def.name)

if !isnothing(def.supertype)
f.print(" <: "; color=:red)
f.unquoted(def.supertype; color=:light_cyan)
end

f.println(" begin"; color=:red)
vf = indent(f)
for (idx, each) in enumerate(def.variants)
vf.show(mime, each)

if idx < length(def.variants)
vf.println()
end
end
f.println()
f.print("end"; color=:red)
end # function Base.show
108 changes: 108 additions & 0 deletions src/data/syntax.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
@enum VariantKind begin
Singleton = 1
Anonymous = 2
Named = 3
end

struct Field
type::Union{Symbol,Expr}

function Field(type::Union{Symbol,Expr})
type isa Symbol && return new(type)
Meta.isexpr(type, :kw) && throw(SyntaxError("field type cannot be a keyword argument"))
new(type)
end
end

struct NamedField
name::Symbol
type::Union{Symbol,Expr}
default # no_default, expr, or literal
source::Union{Nothing,LineNumberNode}
end

function NamedField(f::JLKwField)
NamedField(f.name, f.type, f.default, f.line)
end

struct Variant
kind::VariantKind
name::Symbol
is_mutable::Bool
fields::Union{Vector{Field},Vector{NamedField}}
source::Union{Nothing,LineNumberNode}

function Variant(kind, name, is_mutable, fields, source)
if kind == Named
all(fields) do f
f isa NamedField
end || throw(ArgumentError("fields must be a Vector{Field}"))
elseif kind == Anonymous
all(fields) do f
f isa Field
end || throw(ArgumentError("fields must be a Vector{NamedField}"))
elseif kind == Singleton
isnothing(fields) || isempty(fields) || throw(ArgumentError("fields must be nothing or empty"))
else
throw(ArgumentError("kind must be Named, Anonymous, or Singleton"))
end

name in fieldnames(DataType) && throw(SyntaxError("cannot use reserved name $name for variant", source))
name in (:data, :tag) && throw(SyntaxError("cannot use reserved name $name for variant", source))

new(kind, name, is_mutable, fields, source)
end
end

struct TypeDef
mod::Module
name::Symbol
supertype::Union{Nothing,Symbol,Expr}
variants::Vector{Variant}
source::Union{Nothing,LineNumberNode}
end

function Variant(ex::Union{Symbol, Expr}, source = nothing)
if Meta.isexpr(ex, :struct)
def = JLKwStruct(ex)
def.ismutable && throw(SyntaxError("mutable structs are not supported"; source))
Variant(Named, def.name, def.ismutable, NamedField.(def.fields), source)
elseif Meta.isexpr(ex, :call)
ex.args[1] isa Symbol || throw(SyntaxError("variant name must be a symbol"; source))
Variant(Anonymous, ex.args[1], false, Field.(ex.args[2:end]), source)
elseif ex isa Symbol
Variant(Singleton, ex, false, Field[], source)
else
throw(SyntaxError("variant must be a struct, call, or symbol"; source))
end
end

function TypeDef(mod::Module, head, body::Expr; source=nothing)
name, supertype = scan_data_head(head, source)
variants = Variant[]
let source = source
for each in body.args
each isa LineNumberNode && (source = each; continue)
push!(variants, Variant(each, source))
end
end # let

length(variants) > 0 || throw(SyntaxError("type $name must have at least one variant"; source))
length(variants) > 256 && throw(SyntaxError("too many variants in type $name, 256 maximum"; source))
return TypeDef(mod, name, supertype, variants, source)
end

function scan_data_head(head, source=nothing)
if Meta.isexpr(head, :<:)
name, _ = scan_data_head(head.args[1])
supertype = head.args[2]
elseif Meta.isexpr(head, :curly)
throw(ArgumentError("type parameters are not allowed, we do not support generic ADTs yet"))
elseif head isa Symbol
name = head
supertype = nothing
else
throw(ArgumentError("type name must be a symbol or curly expression"))
end
return name, supertype
end
7 changes: 7 additions & 0 deletions src/expr/mod.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""
Definition & Construction of Expressions
"""
module Expression


end # Expression
5 changes: 5 additions & 0 deletions src/rewrite/mod.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""
The rewrite engine.
"""
module Rewrite
end # Rewrite
5 changes: 5 additions & 0 deletions src/rules/mod.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""
Rewrite rules.
"""
module Rules
end # Rules
5 changes: 5 additions & 0 deletions src/target/mod.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""
Code generation targets.
"""
module Target
end # Target
Empty file added test/data/err.jl
Empty file.
3 changes: 3 additions & 0 deletions test/data/macro.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using Liang.Data: data_m

data_m(:MyADT, :(Foo))
2 changes: 2 additions & 0 deletions test/data/mod.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module TestData
end # TestData
12 changes: 12 additions & 0 deletions test/data/syntax.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Liang.Data: TypeDef

TypeDef(Main, :MyADT, quote
Foo
Bar(Int, Float64)

struct Baz
x::Int
y::Float64
z::Vector{MyADT}
end
end)

0 comments on commit 0996cde

Please sign in to comment.