lib/loxxy/back_end/resolver.rb in loxxy-0.2.06 vs lib/loxxy/back_end/resolver.rb in loxxy-0.3.00
- old
+ new
@@ -115,10 +115,13 @@
aWhileStmt.condition&.accept(aVisitor)
end
# A variable declaration adds a new variable to current scope
def before_var_stmt(aVarStmt)
+ # Oddly enough, Lox allows the re-definition of a variable at top-level scope
+ return if scopes.size == 1 && scopes.last[aVarStmt.name]
+
declare(aVarStmt.name)
end
def after_var_stmt(aVarStmt)
define(aVarStmt.name)
@@ -136,11 +139,11 @@
# Variable expressions require their variables resolved
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"
+ raise Loxxy::RuntimeError, "Can't read variable #{var_name} in its own initializer"
end
end
def after_variable_expr(aVarExpr, aVisitor)
resolve_local(aVarExpr, aVisitor)
@@ -203,22 +206,21 @@
def end_scope
scopes.pop
end
- # rubocop: disable Style/SoleNestedConditional
def declare(aVarName)
return if scopes.empty?
curr_scope = scopes.last
- if scopes.size > 1 # Not at top-level?
# Oddly enough, Lox allows variable re-declaration at top-level
- if curr_scope.include?(aVarName)
- msg = "Error at '#{aVarName}': Already variable with this name in this scope."
- raise Loxxy::RuntimeError, msg
- end
+ if curr_scope.include?(aVarName)
+ msg = "Error at '#{aVarName}': Already variable with this name in this scope."
+ raise Loxxy::RuntimeError, msg
+ elsif curr_scope.size == 255 && current_function != :none
+ msg = "Error at '#{aVarName}': Too many local variables in function."
+ raise Loxxy::RuntimeError, msg
end
- # rubocop: enable Style/SoleNestedConditional
# The initializer is not yet processed.
# Mark the variable as 'not yet ready' = exists but may not be referenced yet
curr_scope[aVarName] = false
end