load-file: accept empty file or final comment, return nil
[jackhill/mal.git] / crystal / types.cr
index 5620330..10c36da 100644 (file)
@@ -1,44 +1,20 @@
 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 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
 
-    property :is_macro
+    property :is_macro, :meta
 
     def initialize(@val : ValueType)
       @is_macro = false
+      @meta = nil.as(Type | Nil)
     end
 
     def initialize(other : Type)
       @val = other.unwrap
-      @is_macro = false
+      @is_macro = other.is_macro
+      @meta = other.meta
     end
 
     def unwrap
@@ -53,6 +29,13 @@ module Mal
       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
@@ -61,7 +44,7 @@ module Mal
       {% for op in ops %}
         def {{op.id}}(other : Mal::Type)
           l, r = @val, other.unwrap
-            {% for t in [Int32, String] %}
+            {% for t in [Int64, String] %}
               if l.is_a?({{t}}) && r.is_a?({{t}})
                 return (l) {{op.id}} (r)
               end
@@ -77,6 +60,45 @@ module Mal
     rel_op :<, :>, :<=, :>=
   end
 
+  class Symbol
+    property :str
+
+    def initialize(@str : String)
+    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 : Type)
+    end
+
+    def ==(rhs : Atom)
+      @val == rhs.val
+    end
+  end
+
+  class Closure
+    property :ast, :params, :env, :fn
+
+    def initialize(@ast : Type, @params : Array(Mal::Type) | List | Vector, @env : Env, @fn : Func)
+    end
+  end
+
+  alias Type::ValueType = Nil | Bool | Int64 | String | Symbol | List | Vector | HashMap | Func | Closure | Atom
   alias Func = Type::Func
 end
 
@@ -86,7 +108,6 @@ end
 
 class Array
   def to_mal(t = Mal::List)
-    each_with_object(t.new){|e, l| l << e}
+    each_with_object(t.new) { |e, l| l << e }
   end
 end
-