Class: Scope

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

Overview

Class to handle scopes when evaluating AST.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parent_scope = nil) ⇒ Scope

Returns a new instance of Scope.



8
9
10
11
12
# File 'lib/nodes.rb', line 8

def initialize(parent_scope = nil)
  @identifiers = {}
  @non_local_variables = []
  @parent_scope = parent_scope
end

Instance Attribute Details

#identifiersObject (readonly)

Returns the value of attribute identifiers.



7
8
9
# File 'lib/nodes.rb', line 7

def identifiers
  @identifiers
end

#non_local_variablesObject (readonly)

Returns the value of attribute non_local_variables.



7
8
9
# File 'lib/nodes.rb', line 7

def non_local_variables
  @non_local_variables
end

#parent_scopeObject (readonly)

Returns the value of attribute parent_scope.



7
8
9
# File 'lib/nodes.rb', line 7

def parent_scope
  @parent_scope
end

Instance Method Details

#get_identifier(name) ⇒ Object

Get value of identifier in current or parent scope(s) if defined.



51
52
53
54
55
56
57
58
# File 'lib/nodes.rb', line 51

def get_identifier(name)
  scope = get_scope(name)
  if scope
    return scope.identifiers[name]
  else
    raise NameError,"Identifier #{name} not defined in scope."
  end
end

#get_scope(name) ⇒ Object

Get first scope where identifier is defined.



61
62
63
64
65
66
67
# File 'lib/nodes.rb', line 61

def get_scope(name)
  if @identifiers.has_key?(name)
    return self
  elsif @parent_scope
    return @parent_scope.get_scope(name)
  end
end

#is_function?(name) ⇒ Boolean

Checks if a identifier is a function.

Returns:

  • (Boolean)


70
71
72
73
74
75
76
# File 'lib/nodes.rb', line 70

def is_function?(name)
  scope = get_scope(name)
  return false unless scope

  id_value = scope.get_identifier(name)
  return id_value.is_a?(Hash) 
end

#set_function(name, block, parameters) ⇒ Object

Set a function in current scope.



79
80
81
# File 'lib/nodes.rb', line 79

def set_function(name, block, parameters)
  @identifiers[name] = {:parameters => parameters, :block => block}
end

#set_non_local_variable(name) ⇒ Object

Add non local variable used in scope



44
45
46
47
48
# File 'lib/nodes.rb', line 44

def set_non_local_variable(name)
  unless @non_local_variables.include?(name) || is_function?(name)
    @non_local_variables.append(name)
  end
end

#set_variable(name, op, expression) ⇒ Object

Set variable in current scope



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/nodes.rb', line 15

def set_variable(name, op, expression)

  # Checks if the variable has been used as a non-local variable, if true: raise NameError
  if @non_local_variables.include?(name)
    raise NameError, "Local identifier #{name} referenced before assignment"
  end

  if op == '='
    @identifiers[name] = expression
  else

    # Checks if the variable is local, raise NameError if otherwise
    unless @identifiers.has_key?(name)
      raise NameError, "Local identifier #{name} referenced before assignment"
    end

    if op == '+='
      @identifiers[name] += expression
    else
      if @identifiers[name].is_a?(String) || expression.is_a?(String)
        raise TypeError, "Operation #{op} is not allowed for identifier #{name} or the expression as they must not be strings"
      else
        @identifiers[name] -= expression
      end
    end
  end
end