require "./printer" module Mal class Symbol property :str def initialize(@str) end def ==(other : Symbol) @str == other.str end end class List < Array(Type) end class Vector < Array(Type) end class HashMap < Hash(String, Type) end class Atom property :val def initialize(@val) end def ==(rhs : Atom) @val == rhs.val end end class Closure property :ast, :params, :env, :fn def initialize(@ast, @params, @env, @fn) end end class Type alias Func = (Array(Type) -> Type) alias ValueType = Nil | Bool | Int32 | String | Symbol | List | Vector | HashMap | Func | Closure | Atom is_macro :: Bool meta :: Type property :is_macro, :meta def initialize(@val : ValueType) @is_macro = false @meta = nil end def initialize(other : Type) @val = other.unwrap @is_macro = other.is_macro @meta = other.meta end def unwrap @val end def macro? @is_macro end def to_s pr_str(self) end def dup Type.new(@val).tap do |t| t.is_macro = @is_macro t.meta = @meta end end def ==(other : Type) @val == other.unwrap end macro rel_op(*ops) {% for op in ops %} def {{op.id}}(other : Mal::Type) l, r = @val, other.unwrap {% for t in [Int32, String] %} if l.is_a?({{t}}) && r.is_a?({{t}}) return (l) {{op.id}} (r) end {% end %} if l.is_a?(Symbol) && r.is_a?(Symbol) return l.str {{op.id}} r.str end false end {% end %} end rel_op :<, :>, :<=, :>= end alias Func = Type::Func end macro gen_type(t, *args) Mal::Type.new {{t.id}}.new({{*args}}) end class Array def to_mal(t = Mal::List) each_with_object(t.new){|e, l| l << e} end end