Merge pull request #377 from asarhaddon/fix-runtests-pre-eval
[jackhill/mal.git] / crystal / types.cr
1 require "./printer"
2
3 module Mal
4 class Type
5 alias Func = (Array(Type) -> Type)
6
7 property :is_macro, :meta
8
9 def initialize(@val : ValueType)
10 @is_macro = false
11 @meta = nil.as(Type | Nil)
12 end
13
14 def initialize(other : Type)
15 @val = other.unwrap
16 @is_macro = other.is_macro
17 @meta = other.meta
18 end
19
20 def unwrap
21 @val
22 end
23
24 def macro?
25 @is_macro
26 end
27
28 def to_s
29 pr_str(self)
30 end
31
32 def dup
33 Type.new(@val).tap do |t|
34 t.is_macro = @is_macro
35 t.meta = @meta
36 end
37 end
38
39 def ==(other : Type)
40 @val == other.unwrap
41 end
42
43 macro rel_op(*ops)
44 {% for op in ops %}
45 def {{op.id}}(other : Mal::Type)
46 l, r = @val, other.unwrap
47 {% for t in [Int64, String] %}
48 if l.is_a?({{t}}) && r.is_a?({{t}})
49 return (l) {{op.id}} (r)
50 end
51 {% end %}
52 if l.is_a?(Symbol) && r.is_a?(Symbol)
53 return l.str {{op.id}} r.str
54 end
55 false
56 end
57 {% end %}
58 end
59
60 rel_op :<, :>, :<=, :>=
61 end
62
63 class Symbol
64 property :str
65
66 def initialize(@str : String)
67 end
68
69 def ==(other : Symbol)
70 @str == other.str
71 end
72 end
73
74 class List < Array(Type)
75 end
76
77 class Vector < Array(Type)
78 end
79
80 class HashMap < Hash(String, Type)
81 end
82
83 class Atom
84 property :val
85
86 def initialize(@val : Type)
87 end
88
89 def ==(rhs : Atom)
90 @val == rhs.val
91 end
92 end
93
94 class Closure
95 property :ast, :params, :env, :fn
96
97 def initialize(@ast : Type, @params : Array(Mal::Type) | List | Vector, @env : Env, @fn : Func)
98 end
99 end
100
101 alias Type::ValueType = Nil | Bool | Int64 | String | Symbol | List | Vector | HashMap | Func | Closure | Atom
102 alias Func = Type::Func
103 end
104
105 macro gen_type(t, *args)
106 Mal::Type.new {{t.id}}.new({{*args}})
107 end
108
109 class Array
110 def to_mal(t = Mal::List)
111 each_with_object(t.new) { |e, l| l << e }
112 end
113 end