import phase
redef class ToolContext
+ # Run `APropdef::do_scope` on each propdef.
var scope_phase: Phase = new ScopePhase(self, null)
end
# The name of the label (unless the mark is an anonymous loop mark)
var name: nullable String
- # Is the mark attached to a loop (loop, while, for)
- # Such a mark is a candidate to a labelless 'continue' or 'break'
- var for_loop: Bool
+ # The associated `continue` mark, if any.
+ # If the mark attached to a loop (loop, while, for), a distinct mark is used.
+ private var continue_mark: nullable EscapeMark = null
- # Each 'continue' attached to the mark
- var continues = new Array[AContinueExpr]
-
- # Each 'break' attached to the mark
- var breaks = new Array[ABreakExpr]
+ # Each break/continue attached to the mark
+ var escapes = new Array[AEscapeExpr]
end
# Visit a npropdef and:
var selfvariable = new Variable("self")
- init(toolcontext: ToolContext)
+ init
do
- self.toolcontext = toolcontext
scopes.add(new Scope)
end
# All stacked scope. `scopes.first` is the current scope
- private var scopes = new List[Scope]
+ var scopes = new List[Scope]
# Shift and check the last scope
fun shift_scope
var name = variable.name
var found = search_variable(name)
if found != null then
- self.error(node, "Error: A variable named `{name}' already exists")
+ self.error(node, "Error: a variable named `{name}` already exists.")
return false
end
scopes.first.variables[name] = variable
if nid == null then
var res = search_label("")
if res != null then
- self.error(nlabel, "Syntax error: anonymous label already defined.")
+ self.error(nlabel, "Syntax Error: anonymous label already defined.")
end
name = ""
else
name = nid.text
var found = self.search_label(name)
if found != null then
- self.error(nlabel, "Syntax error: label {name} already defined.")
+ self.error(nlabel, "Syntax Error: label `{name}` already defined.")
end
end
else
name = null
end
- var res = new EscapeMark(name, for_loop)
+ var res = new EscapeMark(name)
+ if for_loop then res.continue_mark = new EscapeMark(name)
return res
end
if nid == null then
var res = search_label("")
if res == null then
- self.error(nlabel, "Syntax error: invalid anonymous label.")
+ self.error(nlabel, "Syntax Error: invalid anonymous label.")
return null
end
return res
var name = nid.text
var res = search_label(name)
if res == null then
- self.error(nlabel, "Syntax error: invalid label {name}.")
+ self.error(nlabel, "Syntax Error: invalid label `{name}`.")
return null
end
return res
return res
end
end
- self.error(node, "Syntax Error: 'break' statement outside block.")
+ self.error(node, "Syntax Error: `break` statement outside block.")
return null
end
end
end
end
-redef class AContinueExpr
- # The escape mark associated with the continue
+redef class AEscapeExpr
+ # The escape mark associated with the break/continue
var escapemark: nullable EscapeMark
+end
+
+redef class AContinueExpr
redef fun accept_scope_visitor(v)
do
super
var escapemark = v.get_escapemark(self, self.n_label)
if escapemark == null then return # Skip error
- if not escapemark.for_loop then
+ escapemark = escapemark.continue_mark
+ if escapemark == null then
v.error(self, "Error: cannot 'continue', only 'break'.")
+ return
end
- escapemark.continues.add(self)
+ escapemark.escapes.add(self)
self.escapemark = escapemark
end
end
redef class ABreakExpr
- # The escape mark associated with the break
- var escapemark: nullable EscapeMark
redef fun accept_scope_visitor(v)
do
super
var escapemark = v.get_escapemark(self, self.n_label)
if escapemark == null then return # Skip error
- escapemark.breaks.add(self)
+ escapemark.escapes.add(self)
self.escapemark = escapemark
end
end
redef class ADoExpr
- # The escape mark associated with the 'do' block
- var escapemark: nullable EscapeMark
+ # The break escape mark associated with the 'do' block
+ var break_mark: nullable EscapeMark
+
redef fun accept_scope_visitor(v)
do
- self.escapemark = v.make_escape_mark(n_label, false)
- v.enter_visit_block(n_block, self.escapemark)
+ self.break_mark = v.make_escape_mark(n_label, false)
+ v.enter_visit_block(n_block, self.break_mark)
end
end
end
redef class AWhileExpr
- # The escape mark associated with the 'while'
- var escapemark: nullable EscapeMark
+ # The break escape mark associated with the 'while'
+ var break_mark: nullable EscapeMark
+
+ # The continue escape mark associated with the 'while'
+ var continue_mark: nullable EscapeMark
+
redef fun accept_scope_visitor(v)
do
var escapemark = v.make_escape_mark(n_label, true)
- self.escapemark = escapemark
+ self.break_mark = escapemark
+ self.continue_mark = escapemark.continue_mark
v.enter_visit(n_expr)
v.enter_visit_block(n_block, escapemark)
end
end
redef class ALoopExpr
- # The escape mark associated with the 'loop'
- var escapemark: nullable EscapeMark
+ # The break escape mark associated with the 'loop'
+ var break_mark: nullable EscapeMark
+
+ # The continue escape mark associated with the 'loop'
+ var continue_mark: nullable EscapeMark
+
redef fun accept_scope_visitor(v)
do
var escapemark = v.make_escape_mark(n_label, true)
- self.escapemark = escapemark
+ self.break_mark = escapemark
+ self.continue_mark = escapemark.continue_mark
v.enter_visit_block(n_block, escapemark)
end
end
# The automatic variables in order
var variables: nullable Array[Variable]
- # The escape mark associated with the 'for'
- var escapemark: nullable EscapeMark
+ # The break escape mark associated with the 'for'
+ var break_mark: nullable EscapeMark
+
+ # The continue escape mark associated with the 'for'
+ var continue_mark: nullable EscapeMark
redef fun accept_scope_visitor(v)
do
end
var escapemark = v.make_escape_mark(n_label, true)
- self.escapemark = escapemark
+ self.break_mark = escapemark
+ self.continue_mark = escapemark.continue_mark
+ v.enter_visit_block(n_block, escapemark)
+
+ v.shift_scope
+ end
+end
+
+redef class AWithExpr
+ # The break escape mark associated with the 'with'
+ var break_mark: nullable EscapeMark
+
+ redef fun accept_scope_visitor(v)
+ do
+ v.scopes.unshift(new Scope)
+
+ var escapemark = v.make_escape_mark(n_label, true)
+ self.break_mark = escapemark
+
+ v.enter_visit(n_expr)
v.enter_visit_block(n_block, escapemark)
v.shift_scope
end
end
+redef class AAssertExpr
+ redef fun accept_scope_visitor(v)
+ do
+ v.enter_visit(n_expr)
+ v.enter_visit_block(n_else, null)
+ end
+end
+
redef class AVarFormExpr
# The associated variable
var variable: nullable Variable
if variable != null then
var n: AExpr
if not n_args.n_exprs.is_empty or n_args isa AParExprs then
- v.error(self, "Error: {name} is variable, not a function.")
+ v.error(self, "Error: `{name}` is a variable, not a method.")
return
end
n = variable_create(variable)