| 1 | require "./types" |
| 2 | require "./error" |
| 3 | |
| 4 | module 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 |
| 66 | end |