class Pione::Lang::DelegatableTable
DelegatableTable
is a value table identified by two keys(package id and name).
Public Class Methods
new(parent, table=Hash.new {|h, k| h[k] = Hash.new})
click to toggle source
# 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
Public Instance Methods
bound?(package_id, name)
click to toggle source
Return true if the name with the package id is bound.
# 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()
click to toggle source
# 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)
click to toggle source
Find value of the reference recursively. We will raise CircularReferenceError
if the reference is circular.
# 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)
click to toggle source
# File lib/pione/lang/environment.rb, line 36 def get!(env, ref) get(env, ref) rescue UnboundError nil end
get_value(env, ref)
click to toggle source
Get the value expression corresponding to the reference in the table. This method is not circular.
# 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()
click to toggle source
# 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()
click to toggle source
Return all reference in the table and the parent.
# 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)
click to toggle source
Return all names that related to the package ID and ancestors.
@return [Array<String>]
all names in the table
# 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)
click to toggle source
Update table with the name and value. We will raise RebindError
if the reference is bound already.
# 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
set!(ref, val)
click to toggle source
Update the table with the name and value. This method permits to overwrite the value, so you can ignore RebindError
.
# File lib/pione/lang/environment.rb, line 81 def set!(ref, val) @table[ref.package_id][ref.name] = val end