crystal: `make MAL_IMPL=crystal test^mal` succeeds finally
[jackhill/mal.git] / crystal / env.cr
1 require "./types"
2 require "./error"
3
4 module Mal
5
6 class Env
7 property data
8
9 def initialize(@outer)
10 @data = {} of String => Mal::Type
11 end
12
13 def initialize(@outer, binds, exprs : Array(Mal::Type))
14 @data = {} of String => Mal::Type
15
16 eval_error "binds must be list or vector" unless binds.is_a? Array
17
18 # Note:
19 # Array#zip() can't be used because overload resolution failed
20 (0...binds.size).each do |idx|
21 sym = binds[idx].unwrap
22 eval_error "bind name must be symbol" unless sym.is_a? Mal::Symbol
23
24 if sym.str == "&"
25 eval_error "missing variable parameter name" if binds.size == idx
26 next_param = binds[idx+1].unwrap
27 eval_error "bind name must be symbol" unless next_param.is_a? Mal::Symbol
28 var_args = Mal::List.new
29 exprs[idx..-1].each{|e| var_args << e} if idx < exprs.size
30 @data[next_param.str] = Mal::Type.new var_args
31 break
32 end
33
34 @data[sym.str] = exprs[idx]
35 end
36 end
37
38 def dump
39 puts "ENV BEGIN".colorize.red
40 @data.each do |k, v|
41 puts " #{k} -> #{print(v)}".colorize.red
42 end
43 puts "ENV END".colorize.red
44 end
45
46 def set(key, value)
47 @data[key] = value
48 end
49
50 def find(key)
51 return self if @data.has_key? key
52
53 o = @outer
54 if o
55 o.find key
56 else
57 nil
58 end
59 end
60
61 def get(key)
62 e = find key
63 eval_error "'#{key}' not found" unless e
64 e.data[key]
65 end
66 end
67
68 end