Class: N65::SymbolTable

Inherits:
Object
  • Object
show all
Defined in:
lib/n65/symbol_table.rb

Defined Under Namespace

Classes: CantExitScope, InvalidScope, UndefinedSymbol

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeSymbolTable

Initialize a symbol table that begins in global scope



15
16
17
18
19
20
21
# File 'lib/n65/symbol_table.rb', line 15

def initialize
  @symbols = {
    :global => {}
  }
  @anonymous_scope_number = 0
  @scope_stack = [:global]
end

Instance Attribute Details

#scope_stackObject

Returns the value of attribute scope_stack.



5
6
7
# File 'lib/n65/symbol_table.rb', line 5

def scope_stack
  @scope_stack
end

Instance Method Details

#define_symbol(symbol, value) ⇒ Object

Define a symbol in the current scope



52
53
54
55
# File 'lib/n65/symbol_table.rb', line 52

def define_symbol(symbol, value)
  scope = current_scope
  scope[symbol.to_sym] = value
end

#enter_scope(name = nil) ⇒ Object

Define a new scope, which can be anonymous or named

and switch into that scope


27
28
29
30
31
32
33
34
35
36
37
# File 'lib/n65/symbol_table.rb', line 27

def enter_scope(name = nil)
  name = generate_name if name.nil? 
  name = name.to_sym
  scope = current_scope
  if scope.has_key?(name)
    #path_string = generate_scope_path(path_ary)
    fail(InvalidScope, "Scope: #{name} already exists")
  end
  scope[name] = {}
  @scope_stack.push(name)
end

#exit_scopeObject

Exit the current scope



42
43
44
45
46
47
# File 'lib/n65/symbol_table.rb', line 42

def exit_scope
  if @scope_stack.size == 1
    fail(CantExitScope, "You cannot exit global scope")
  end
  @scope_stack.pop
end

#export_to_yamlObject

Export the symbol table as YAML



145
146
147
148
149
150
# File 'lib/n65/symbol_table.rb', line 145

def export_to_yaml
  @symbols.to_yaml.gsub(/(\d+)$/) do |match|
    integer = match.to_i
    sprintf("0x%.4X", integer)
  end
end

#resolve_symbol(name) ⇒ Object



95
96
97
98
99
100
101
# File 'lib/n65/symbol_table.rb', line 95

def resolve_symbol(name)
  method = name.include?('.') ? :resolve_symbol_dot_syntax : :resolve_symbol_scoped
  value = self.send(method, name)

  fail(UndefinedSymbol, name) if value.nil?
  value
end

#resolve_symbol_dot_syntax(name) ⇒ Object

Dot syntax means to check an absolute path to the symbol

:global is ignored if it is provided as part of the path


129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/n65/symbol_table.rb', line 129

def resolve_symbol_dot_syntax(name)
  path_ary = name.split('.').map(&:to_sym)
  symbol = path_ary.pop
  root = "-#{symbol}".to_sym
  path_ary.shift if path_ary.first == :global

  scope = retreive_scope(path_ary)

  ##  We see if there is a key either under this name, or root
  v = scope[symbol]
  v.kind_of?(Hash) ? v[root] : v
end

#resolve_symbol_scoped(name) ⇒ Object

Resolve symbol by working backwards through each

containing scope.  Similarly named scopes shadow outer scopes


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/n65/symbol_table.rb', line 107

def resolve_symbol_scoped(name)
  root = "-#{name}".to_sym
  stack = @scope_stack.dup
  loop do
    scope = retreive_scope(stack)

    ##  We see if there is a key either under this name, or root
    v = scope[name.to_sym] || scope[root]
    v = v.kind_of?(Hash) ? v[root] : v

    return v unless v.nil?

    ##  Pop the stack so we can decend to the parent scope, if any
    stack.pop
    return nil if stack.empty?
  end
end