Rename REAMDE to README.md
[nit.git] / src / semantize / scope.nit
index 30aade4..4ea5f27 100644 (file)
@@ -20,6 +20,7 @@ module scope
 import phase
 
 redef class ToolContext
+       # Run `APropdef::do_scope` on each propdef.
        var scope_phase: Phase = new ScopePhase(self, null)
 end
 
@@ -50,15 +51,12 @@ class EscapeMark
        # 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:
@@ -74,14 +72,13 @@ private class ScopeVisitor
 
        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
@@ -102,7 +99,7 @@ private class ScopeVisitor
                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
@@ -163,20 +160,21 @@ private class ScopeVisitor
                        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
 
@@ -192,7 +190,7 @@ private class ScopeVisitor
                        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
@@ -200,7 +198,7 @@ private class ScopeVisitor
                        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
@@ -211,7 +209,7 @@ private class ScopeVisitor
                                        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
@@ -303,10 +301,12 @@ redef class AContinueExpr
                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
@@ -317,19 +317,20 @@ redef class ABreakExpr
                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
 
@@ -343,24 +344,34 @@ redef class AIfExpr
 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
@@ -369,8 +380,11 @@ redef class AForExpr
        # 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
@@ -389,7 +403,26 @@ redef class AForExpr
                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
@@ -410,7 +443,7 @@ redef class ACallFormExpr
                        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)