Class: Loxxy::BackEnd::Resolver

Inherits:
Object
  • Object
show all
Defined in:
lib/loxxy/back_end/resolver.rb

Overview

A class aimed to perform variable resolution when it visits the parse tree. Resolving means retrieve the declaration of a variable/function everywhere it is referenced.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeResolver

Returns a new instance of Resolver.



25
26
27
28
# File 'lib/loxxy/back_end/resolver.rb', line 25

def initialize
  @scopes = []
  @locals = {}
end

Instance Attribute Details

#localsHash {LoxNode => Integer} (readonly)

A map from a LoxNode involving a variable and the number of enclosing scopes where it is declared.

Returns:

  • (Hash {LoxNode => Integer})


23
24
25
# File 'lib/loxxy/back_end/resolver.rb', line 23

def locals
  @locals
end

#scopesArray<Hash{String => Boolean}> (readonly)

A stack of Hashes of the form String => Boolean

Returns:

  • (Array<Hash{String => Boolean}>)


18
19
20
# File 'lib/loxxy/back_end/resolver.rb', line 18

def scopes
  @scopes
end

Instance Method Details

#after_assign_expr(anAssignExpr, aVisitor) ⇒ Object

Assignment expressions require their variables resolved



82
83
84
# File 'lib/loxxy/back_end/resolver.rb', line 82

def after_assign_expr(anAssignExpr, aVisitor)
  resolve_local(anAssignExpr, aVisitor)
end

#after_block_stmt(_aBlockStmt) ⇒ Object



47
48
49
# File 'lib/loxxy/back_end/resolver.rb', line 47

def after_block_stmt(_aBlockStmt)
  end_scope
end

#after_call_expr(aCallExpr, aVisitor) ⇒ Object



98
99
100
101
102
# File 'lib/loxxy/back_end/resolver.rb', line 98

def after_call_expr(aCallExpr, aVisitor)
  # Evaluate callee part
  aCallExpr.callee.accept(aVisitor)
  aCallExpr.arguments.reverse_each { |arg| arg.accept(aVisitor) }
end

#after_for_stmt(aForStmt, aVisitor) ⇒ Object



55
56
57
58
59
60
# File 'lib/loxxy/back_end/resolver.rb', line 55

def after_for_stmt(aForStmt, aVisitor)
  aForStmt.test_expr.accept(aVisitor)
  aForStmt.body_stmt.accept(aVisitor)
  aForStmt.update_expr&.accept(aVisitor)
  after_block_stmt(aForStmt)
end

#after_if_stmt(anIfStmt, aVisitor) ⇒ Object



62
63
64
65
# File 'lib/loxxy/back_end/resolver.rb', line 62

def after_if_stmt(anIfStmt, aVisitor)
  anIfStmt.then_stmt.accept(aVisitor)
  anIfStmt.else_stmt&.accept(aVisitor)
end

#after_var_stmt(aVarStmt) ⇒ Object



77
78
79
# File 'lib/loxxy/back_end/resolver.rb', line 77

def after_var_stmt(aVarStmt)
  define(aVarStmt.name)
end

#after_variable_expr(aVarExpr, aVisitor) ⇒ Object



94
95
96
# File 'lib/loxxy/back_end/resolver.rb', line 94

def after_variable_expr(aVarExpr, aVisitor)
  resolve_local(aVarExpr, aVisitor)
end

#after_while_stmt(aWhileStmt, aVisitor) ⇒ Object



67
68
69
70
# File 'lib/loxxy/back_end/resolver.rb', line 67

def after_while_stmt(aWhileStmt, aVisitor)
  aWhileStmt.body.accept(aVisitor)
  aWhileStmt.condition.accept(aVisitor)
end

#analyze(aVisitor) ⇒ Loxxy::Datatype::BuiltinDatatype

Given an abstract syntax parse tree visitor, launch the visit and execute the visit events in the output stream.

Parameters:

  • aVisitor (AST::ASTVisitor)

Returns:



34
35
36
37
38
39
40
# File 'lib/loxxy/back_end/resolver.rb', line 34

def analyze(aVisitor)
  begin_scope
  aVisitor.subscribe(self)
  aVisitor.start
  aVisitor.unsubscribe(self)
  end_scope
end

#before_block_stmt(_aBlockStmt) ⇒ Object

block statement introduces a new scope



43
44
45
# File 'lib/loxxy/back_end/resolver.rb', line 43

def before_block_stmt(_aBlockStmt)
  begin_scope
end

#before_for_stmt(aForStmt) ⇒ Object



51
52
53
# File 'lib/loxxy/back_end/resolver.rb', line 51

def before_for_stmt(aForStmt)
  before_block_stmt(aForStmt)
end

#before_fun_stmt(aFunStmt, aVisitor) ⇒ Object

function declaration creates a new scope for its body & binds its parameters for that scope



105
106
107
108
109
# File 'lib/loxxy/back_end/resolver.rb', line 105

def before_fun_stmt(aFunStmt, aVisitor)
  declare(aFunStmt.name)
  define(aFunStmt.name)
  resolve_function(aFunStmt, aVisitor)
end

#before_var_stmt(aVarStmt) ⇒ Object

A variable declaration adds a new variable to current scope



73
74
75
# File 'lib/loxxy/back_end/resolver.rb', line 73

def before_var_stmt(aVarStmt)
  declare(aVarStmt.name)
end

#before_variable_expr(aVarExpr) ⇒ Object

Variable expressions require their variables resolved



87
88
89
90
91
92
# File 'lib/loxxy/back_end/resolver.rb', line 87

def before_variable_expr(aVarExpr)
  var_name = aVarExpr.name
  if !scopes.empty? && (scopes.last[var_name] == false)
    raise StandardError, "Can't read variable #{var_name} in its own initializer"
  end
end