src: create groups for related things
[nit.git] / src / scope.nit
diff --git a/src/scope.nit b/src/scope.nit
deleted file mode 100644 (file)
index 83c5fe4..0000000
+++ /dev/null
@@ -1,428 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2012 Jean Privat <jean@pryen.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Identification and scping of local variables and labels.
-module scope
-
-import phase
-
-redef class ToolContext
-       var scope_phase: Phase = new ScopePhase(self, null)
-end
-
-private class ScopePhase
-       super Phase
-       redef fun process_npropdef(npropdef) do npropdef.do_scope(toolcontext)
-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
-
-       # Alias of `name`
-       redef fun to_s do return self.name
-end
-
-# Mark where break and continue will branch.
-# Marks are either associated with a label of with a for_loop structure
-class EscapeMark
-       # The name of the label (unless the mark is an anonymous loop mark)
-       var name: nullable String
-
-       # Is the mark atached to a loop (loop, while, for)
-       # Such a mark is a candidate to a labelless 'continue' or 'break'
-       var for_loop: Bool
-
-       # Each 'continue' attached to the mark
-       var continues: Array[AContinueExpr] = new Array[AContinueExpr]
-
-       # Each 'break' attached to the mark
-       var breaks: Array[ABreakExpr] = new Array[ABreakExpr]
-end
-
-# Visit a npropdef and:
-#  * Identify variables and labels
-#  * Associate each break and continue to its escapemark
-#  * Transform `ACallFormExpr` that access a variable into `AVarFormExpr`
-# FIXME: Should the class be private?
-private class ScopeVisitor
-       super Visitor
-
-       # The tool context used to display errors
-       var toolcontext: ToolContext
-
-       var selfvariable: Variable = new Variable("self")
-
-       init(toolcontext: ToolContext)
-       do
-               self.toolcontext = toolcontext
-               scopes.add(new Scope)
-       end
-
-       # All stacked scope. `scopes.first` is the current scope
-       private var scopes: List[Scope] = new List[Scope]
-
-       # Regiter a local variable.
-       # Display an error on toolcontext if a variable with the same name is masked.
-       fun register_variable(node: ANode, variable: Variable): Bool
-       do
-               var name = variable.name
-               var found = search_variable(name)
-               if found != null then
-                       self.error(node, "Error: A variable named `{name}' already exists")
-                       return false
-               end
-               scopes.first.variables[name] = variable
-               return true
-       end
-
-       # Look for a variable named `name`.
-       # Return null if no such a variable is found.
-       fun search_variable(name: String): nullable Variable
-       do
-               for scope in scopes do
-                       var res = scope.get_variable(name)
-                       if res != null then
-                               return res
-                       end
-               end
-               return null
-       end
-
-       redef fun visit(n)
-       do
-               n.accept_scope_visitor(self)
-       end
-
-       # Enter in a statement block `node` as inside a new scope.
-       # The block can be optionally attached to an `escapemark`.
-       private fun enter_visit_block(node: nullable AExpr, escapemark: nullable EscapeMark)
-       do
-               if node == null then return
-               var scope = new Scope
-               scope.escapemark = escapemark
-               scopes.unshift(scope)
-               enter_visit(node)
-               scopes.shift
-       end
-
-       # Look for a label `name`.
-       # Return nulll if no such a label is found.
-       private fun search_label(name: String): nullable EscapeMark
-       do
-               for scope in scopes do
-                       var res = scope.escapemark
-                       if res != null and res.name == name then
-                               return res
-                       end
-               end
-               return null
-       end
-
-       # Create a new escape mark (possibly with a label)
-       # Display an error on toolcontext if a label with the same name is masked.
-       private fun make_escape_mark(nlabel: nullable ALabel, for_loop: Bool): EscapeMark
-       do
-               var name: nullable String
-               if nlabel != null then
-                       var nid = nlabel.n_id
-                       if nid == null then
-                               var res = search_label("")
-                               if res != null then
-                                       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.")
-                               end
-                       end
-               else
-                       name = null
-               end
-               var res = new EscapeMark(name, for_loop)
-               return res
-       end
-
-       # Look for an escape mark optionally associated with a label.
-       # If a label is given, the the escapemark of this label is returned.
-       # If there is no label, the nearest escapemark that is `for loop` is returned.
-       # If there is no valid escapemark, then an error is displayed ans null is returned.
-       # Return nulll if no such a label is found.
-       private fun get_escapemark(node: ANode, nlabel: nullable ALabel): nullable EscapeMark
-       do
-               if nlabel != null then
-                       var nid = nlabel.n_id
-                       if nid == null then
-                               var res = search_label("")
-                               if res == null then
-                                       self.error(nlabel, "Syntax error: invalid anonymous label.")
-                                       return null
-                               end
-                               return res
-                       end
-                       var name = nid.text
-                       var res = search_label(name)
-                       if res == null then
-                               self.error(nlabel, "Syntax error: invalid label {name}.")
-                               return null
-                       end
-                       return res
-               else
-                       for scope in scopes do
-                               var res = scope.escapemark
-                               if res != null then
-                                       return res
-                               end
-                       end
-                       self.error(node, "Syntax Error: 'break' statment outside block.")
-                       return null
-               end
-       end
-
-       # Display an error
-       private fun error(node: ANode, message: String)
-       do
-               self.toolcontext.error(node.hot_location, message)
-       end
-end
-
-private class Scope
-       var variables: HashMap[String, Variable] = new HashMap[String, Variable]
-
-       var escapemark: nullable EscapeMark = null
-
-       fun get_variable(name: String): nullable Variable
-       do
-               if self.variables.has_key(name) then
-                       return self.variables[name]
-               else
-                       return null
-               end
-       end
-end
-
-redef class ANode
-       private fun accept_scope_visitor(v: ScopeVisitor)
-       do
-               visit_all(v)
-       end
-end
-
-redef class APropdef
-       # Entry point of the scope analysis
-       fun do_scope(toolcontext: ToolContext)
-       do
-               var v = new ScopeVisitor(toolcontext)
-               v.enter_visit(self)
-       end
-end
-
-redef class AParam
-       # The variable associated with the parameter
-       var variable: nullable Variable
-       redef fun accept_scope_visitor(v)
-       do
-               super
-               var nid = self.n_id
-               var variable = new Variable(nid.text)
-               v.register_variable(nid, variable)
-               self.variable = variable
-       end
-end
-
-redef class AVardeclExpr
-       # The variable associated with the variable declaration
-       var variable: nullable Variable
-       redef fun accept_scope_visitor(v)
-       do
-               super
-               var nid = self.n_id
-               var variable = new Variable(nid.text)
-               v.register_variable(nid, variable)
-               self.variable = variable
-       end
-end
-
-redef class ASelfExpr
-       # The variable associated with the self reciever
-       var variable: nullable Variable
-       redef fun accept_scope_visitor(v)
-       do
-               super
-               self.variable = v.selfvariable
-       end
-end
-
-redef class AContinueExpr
-       # The escape mark associated with the continue
-       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
-               if not escapemark.for_loop then
-                       v.error(self, "Error: cannot 'continue', only 'break'.")
-               end
-               escapemark.continues.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)
-               self.escapemark = escapemark
-       end
-end
-
-
-redef class ADoExpr
-       # The escape mark associated with the 'do' block
-       var escapemark: 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)
-       end
-end
-
-redef class AIfExpr
-       redef fun accept_scope_visitor(v)
-       do
-               v.enter_visit(n_expr)
-               v.enter_visit_block(n_then, null)
-               v.enter_visit_block(n_else, null)
-       end
-end
-
-redef class AWhileExpr
-       # The escape mark associated with the 'while'
-       var escapemark: nullable EscapeMark
-       redef fun accept_scope_visitor(v)
-       do
-               var escapemark = v.make_escape_mark(n_label, true)
-               self.escapemark = escapemark
-               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
-       redef fun accept_scope_visitor(v)
-       do
-               var escapemark = v.make_escape_mark(n_label, true)
-               self.escapemark = escapemark
-               v.enter_visit_block(n_block, escapemark)
-       end
-end
-
-redef class AForExpr
-       # The automatic variables in order
-       var variables: nullable Array[Variable]
-
-       # The escape mark associated with the 'for'
-       var escapemark: nullable EscapeMark
-
-       redef fun accept_scope_visitor(v)
-       do
-               v.enter_visit(n_expr)
-
-               # 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)
-               end
-
-               var escapemark = v.make_escape_mark(n_label, true)
-               self.escapemark = escapemark
-               v.enter_visit_block(n_block, escapemark)
-
-               v.scopes.shift
-       end
-end
-
-redef class AVarFormExpr
-       # The associated variable
-       var variable: nullable Variable
-end
-
-redef class ACallFormExpr
-       redef fun accept_scope_visitor(v)
-       do
-               if n_expr isa AImplicitSelfExpr then
-                       var name = 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
-                                       v.error(self, "Error: {name} is variable, not a function.")
-                                       return
-                               end
-                               n = variable_create(variable)
-                               n.variable = variable
-                               replace_with(n)
-                               n.accept_scope_visitor(v)
-                               return
-                       end
-               end
-
-               super
-       end
-
-       # Create a variable acces corresponding to the call form
-       private fun variable_create(variable: Variable): AVarFormExpr is abstract
-end
-
-redef class ACallExpr
-       redef fun variable_create(variable)
-       do
-               return new AVarExpr.init_avarexpr(n_id)
-       end
-end
-
-redef class ACallAssignExpr
-       redef fun variable_create(variable)
-       do
-               return new AVarAssignExpr.init_avarassignexpr(n_id, n_assign, n_value)
-       end
-end
-
-redef class ACallReassignExpr
-       redef fun variable_create(variable)
-       do
-               return new AVarReassignExpr.init_avarreassignexpr(n_id, n_assign_op, n_value)
-       end
-end