Merge: Contract implementation
[nit.git] / src / semantize / scope.nit
index a69c57a..de85c22 100644 (file)
@@ -18,6 +18,7 @@
 module scope
 
 import phase
+import modelbuilder
 
 redef class ToolContext
        # Run `APropdef::do_scope` on each propdef.
@@ -33,13 +34,13 @@ end
 # A local variable (including parameters, automatic variables and self)
 class Variable
        # The name of the variable (as used in the program)
-       var name: String
+       var name: String is writable
 
        # Alias of `name`
        redef fun to_s do return self.name
 
        # The declaration of the variable, if any
-       var location: nullable Location = null
+       var location: nullable Location = null is writable
 
        # Is the local variable not read and need a warning?
        var warn_unread = false is writable
@@ -70,6 +71,9 @@ private class ScopeVisitor
        # The tool context used to display errors
        var toolcontext: ToolContext
 
+       # The analysed property
+       var propdef: APropdef
+
        var selfvariable = new Variable("self")
 
        init
@@ -191,6 +195,7 @@ private class ScopeVisitor
                                var res = search_label("")
                                if res == null then
                                        self.error(nlabel, "Syntax Error: invalid anonymous label.")
+                                       node.is_broken = true
                                        return null
                                end
                                return res
@@ -199,6 +204,7 @@ private class ScopeVisitor
                        var res = search_label(name)
                        if res == null then
                                self.error(nlabel, "Syntax Error: invalid label `{name}`.")
+                               node.is_broken = true
                                return null
                        end
                        return res
@@ -218,6 +224,7 @@ private class ScopeVisitor
        fun error(node: ANode, message: String)
        do
                self.toolcontext.error(node.hot_location, message)
+               node.is_broken = true
        end
 end
 
@@ -244,10 +251,13 @@ redef class ANode
 end
 
 redef class APropdef
+       # The break escape mark associated with the return
+       var return_mark: nullable EscapeMark
+
        # Entry point of the scope analysis
        fun do_scope(toolcontext: ToolContext)
        do
-               var v = new ScopeVisitor(toolcontext)
+               var v = new ScopeVisitor(toolcontext, self)
                v.enter_visit(self)
                v.shift_scope
        end
@@ -258,6 +268,11 @@ redef class AParam
        var variable: nullable Variable
        redef fun accept_scope_visitor(v)
        do
+               if variable != null then
+                       v.register_variable(self.n_id, variable.as(not null))
+                       return
+               end
+
                super
                var nid = self.n_id
                var variable = new Variable(nid.text)
@@ -322,6 +337,21 @@ redef class ABreakExpr
        end
 end
 
+redef class AReturnExpr
+       redef fun accept_scope_visitor(v)
+       do
+               super
+
+               var escapemark = v.propdef.return_mark
+               if escapemark == null then
+                       escapemark = new EscapeMark
+                       v.propdef.return_mark = escapemark
+               end
+
+               escapemark.escapes.add(self)
+               self.escapemark = escapemark
+       end
+end
 
 redef class ADoExpr
        # The break escape mark associated with the 'do' block
@@ -331,6 +361,7 @@ redef class ADoExpr
        do
                self.break_mark = v.make_escape_mark(n_label, false)
                v.enter_visit_block(n_block, self.break_mark)
+               v.enter_visit_block(n_catch)
        end
 end
 
@@ -377,9 +408,6 @@ redef class ALoopExpr
 end
 
 redef class AForExpr
-       # The automatic variables in order
-       var variables: nullable Array[Variable]
-
        # The break escape mark associated with the 'for'
        var break_mark: nullable EscapeMark
 
@@ -388,18 +416,22 @@ redef class AForExpr
 
        redef fun accept_scope_visitor(v)
        do
-               v.enter_visit(n_expr)
+               for g in n_groups do
+                       v.enter_visit(g.n_expr)
+               end
 
                # Protect automatic variables
                v.scopes.unshift(new Scope)
 
-               # Create the automatic variables
-               var variables = new Array[Variable]
-               self.variables = variables
-               for nid in n_ids do
-                       var va = new Variable(nid.text)
-                       v.register_variable(nid, va)
-                       variables.add(va)
+               for g in n_groups do
+                       # Create the automatic variables
+                       var variables = new Array[Variable]
+                       g.variables = variables
+                       for nid in g.n_ids do
+                               var va = new Variable(nid.text)
+                               v.register_variable(nid, va)
+                               variables.add(va)
+                       end
                end
 
                var escapemark = v.make_escape_mark(n_label, true)
@@ -411,6 +443,11 @@ redef class AForExpr
        end
 end
 
+redef class AForGroup
+       # The automatic variables in order
+       var variables: nullable Array[Variable]
+end
+
 redef class AWithExpr
        # The break escape mark associated with the 'with'
        var break_mark: nullable EscapeMark
@@ -439,18 +476,18 @@ end
 
 redef class AVarFormExpr
        # The associated variable
-       var variable: nullable Variable
+       var variable: nullable Variable is writable
 end
 
 redef class ACallFormExpr
        redef fun accept_scope_visitor(v)
        do
                if n_expr isa AImplicitSelfExpr then
-                       var name = n_id.text
+                       var name = n_qid.n_id.text
                        var variable = v.search_variable(name)
                        if variable != null then
                                var n: AExpr
-                               if not n_args.n_exprs.is_empty or n_args isa AParExprs then
+                               if not n_args.n_exprs.is_empty or n_args isa AParExprs or self isa ACallrefExpr then
                                        v.error(self, "Error: `{name}` is a variable, not a method.")
                                        return
                                end
@@ -473,14 +510,14 @@ redef class ACallExpr
        redef fun variable_create(variable)
        do
                variable.warn_unread = false
-               return new AVarExpr.init_avarexpr(n_id)
+               return new AVarExpr.init_avarexpr(n_qid.n_id)
        end
 end
 
 redef class ACallAssignExpr
        redef fun variable_create(variable)
        do
-               return new AVarAssignExpr.init_avarassignexpr(n_id, n_assign, n_value)
+               return new AVarAssignExpr.init_avarassignexpr(n_qid.n_id, n_assign, n_value)
        end
 end
 
@@ -488,6 +525,14 @@ redef class ACallReassignExpr
        redef fun variable_create(variable)
        do
                variable.warn_unread = false
-               return new AVarReassignExpr.init_avarreassignexpr(n_id, n_assign_op, n_value)
+               return new AVarReassignExpr.init_avarreassignexpr(n_qid.n_id, n_assign_op, n_value)
+       end
+end
+
+redef class ALambdaExpr
+       redef fun accept_scope_visitor(v)
+       do
+               # TODO
+               return
        end
 end