Class: Pione::Lang::DelegatableTable
- Inherits:
-
Object
- Object
- Pione::Lang::DelegatableTable
- Defined in:
- lib/pione/lang/environment.rb
Overview
DelegatableTable is a value table identified by two keys(package id and name).
Direct Known Subclasses
Instance Method Summary collapse
-
#bound?(package_id, name) ⇒ Boolean
Return true if the name with the package id is bound.
- #dumpable ⇒ Object
-
#get(env, ref) ⇒ Object
Find value of the reference recursively.
- #get!(env, ref) ⇒ Object
-
#get_value(env, ref) ⇒ Object
Get the value expression corresponding to the reference in the table.
-
#initialize(parent, table = Hash.new {|h, k| h[k] = Hash.new}) ⇒ DelegatableTable
constructor
A new instance of DelegatableTable.
- #inspect ⇒ Object
-
#keys ⇒ Object
Return all reference in the table and the parent.
-
#select_names_by(env, package_id) ⇒ Array<String>
Return all names that related to the package ID and ancestors.
-
#set(ref, val) ⇒ Object
Update table with the name and value.
-
#set!(ref, val) ⇒ Object
Update the table with the name and value.
Constructor Details
#initialize(parent, table = Hash.new {|h, k| h[k] = Hash.new}) ⇒ DelegatableTable
Returns a new instance of DelegatableTable.
5 6 7 8 |
# File 'lib/pione/lang/environment.rb', line 5 def initialize(parent, table=Hash.new {|h, k| h[k] = Hash.new}) @parent = parent # parent delegatable table @table = table # 2d table end |
Instance Method Details
#bound?(package_id, name) ⇒ Boolean
Return true if the name with the package id is bound.
11 12 13 |
# File 'lib/pione/lang/environment.rb', line 11 def bound?(package_id, name) (@table.has_key?(package_id) and @table[package_id][name]) || (@parent ? @parent.bound?(package_id, name) : false) end |
#dumpable ⇒ Object
119 120 121 122 123 |
# File 'lib/pione/lang/environment.rb', line 119 def dumpable parent = @parent ? @parent.dumpable : nil table = Hash[*@table.to_a.flatten] self.class.new(parent, table) end |
#get(env, ref) ⇒ Object
Find value of the reference recursively. We will raise +CircularReferenceError+ if the reference is circular.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/pione/lang/environment.rb', line 17 def get(env, ref) history = [ref.package_id, ref.name] # detect reference loop if env.reference_history.include?(history) raise CircularReferenceError.new(ref) end # push package id and name to history _env = env.set(reference_history: env.reference_history + [history]) # get the expression and evaluate it if expr = get_value(env, ref) evaluate_value(_env, expr) else raise UnboundError.new(ref) end end |
#get!(env, ref) ⇒ Object
36 37 38 39 40 |
# File 'lib/pione/lang/environment.rb', line 36 def get!(env, ref) get(env, ref) rescue UnboundError nil end |
#get_value(env, ref) ⇒ Object
Get the value expression corresponding to the reference in the table. This method is not circular.
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/pione/lang/environment.rb', line 44 def get_value(env, ref) unless ref.package_id raise ArgumentError.new("package id is invalid: %s" % ref.inspect) end # when it is known reference if expr = @table[ref.package_id][ref.name] return expr end if bound?(ref.package_id, ref.name) # get value from parent table return @parent.get_value(env, ref) if @parent else # otherwise, find by parent package id env.find_ancestor_ids(ref.package_id).each do |ancestor_id| if val = get_value(env, ref.set(package_id: ancestor_id)) return val end end end return nil end |
#inspect ⇒ Object
111 112 113 114 115 116 117 |
# File 'lib/pione/lang/environment.rb', line 111 def inspect if @parent "#%s(%s,%s)" % [self.class.name.split("::").last, @table, @parent.inspect] else "#%s(%s)" % [self.class.name.split("::").last, @table] end end |
#keys ⇒ Object
Return all reference in the table and the parent.
86 87 88 89 90 91 92 93 |
# File 'lib/pione/lang/environment.rb', line 86 def keys @table.keys.inject(@parent ? @parent.keys : []) do |res, k1| @table[k1].keys.inject(res) do |_res, k2| ref = make_reference(k1, k2) _res.include?(ref) ? _res : res << ref end end end |
#select_names_by(env, package_id) ⇒ Array<String>
Return all names that related to the package ID and ancestors.
99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/pione/lang/environment.rb', line 99 def select_names_by(env, package_id) names = @parent ? @parent.select_names_by(package_id) : [] target_ids = [package_id, *env.find_ancestor_ids(package_id)] target_ids.each_with_object(names) do |target_id, names| @table[target_id].keys.each do |name| if not(names.include?(name)) names << name end end end end |
#set(ref, val) ⇒ Object
Update table with the name and value. We will raise +RebindError+ if the reference is bound already.
71 72 73 74 75 76 77 |
# File 'lib/pione/lang/environment.rb', line 71 def set(ref, val) unless bound?(ref.package_id, ref.name) set!(ref, val) else raise RebindError.new(ref) end end |