+require "./printer"
+
module Mal
class Symbol
property :str
def initialize(@str)
end
+
+ def ==(other : Symbol)
+ @str == other.str
+ end
end
class List < Array(Type)
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 ValueType = Nil | Bool | Int32 | String | Symbol | List | Vector | HashMap | ((Array(Type) -> 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.val
+ @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 = Array(Type) -> Type
+ 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
+