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