syntax: merge ScopeContext and EscapeContext
[nit.git] / src / syntax / control_flow.nit
diff --git a/src/syntax/control_flow.nit b/src/syntax/control_flow.nit
deleted file mode 100644 (file)
index 7661039..0000000
+++ /dev/null
@@ -1,377 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2008-2009 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.
-
-# Analysis control flow and variable visibility in property bodies, statements and expressions
-package control_flow
-
-import syntax_base
-
-# Associate symbols to variable
-# Can be nested
-abstract class ScopeContext
-       # Look for the variable from its name
-       # Return null if nothing found
-       fun [](s: Symbol): nullable Variable
-       do
-               if _dico.has_key(s) then
-                       return _dico[s]
-               else
-                       return null
-               end
-       end
-
-       # Register a new variable with its name
-       fun add(v: Variable)
-       do
-               var old_var = self[v.name]
-               if old_var != null then
-                       _visitor.error(v.decl, "Error: '{v}' already defined at {old_var.decl.location.relative_to(v.decl.location)}.")
-               end
-               _dico[v.name] = v
-               _all_variables.add(v)
-       end
-
-       # Build a new ScopeContext
-       fun sub(node: ANode): ScopeContext
-       do
-               return new SubScopeContext.with_prev(self, node)
-       end
-
-       # Variables by name (in the current context only)
-       var _dico: Map[Symbol, Variable] = new HashMap[Symbol, Variable]
-
-       # All variables in all contextes
-       var _all_variables: Set[Variable]
-
-       # The visitor of the context (used to display error)
-       var _visitor: AbsSyntaxVisitor
-
-       # The syntax node that introduced the context
-       readable var _node: ANode
-
-       init(visitor: AbsSyntaxVisitor, node: ANode)
-       do
-               _visitor = visitor
-               _node = node
-       end
-end
-
-# Root of a variable scope context hierarchy
-class RootScopeContext
-special ScopeContext
-       init(visitor: AbsSyntaxVisitor, node: ANode)
-       do
-               super(visitor, node)
-               _all_variables = new HashSet[Variable]
-       end
-end
-
-# Contexts that can see local variables of a prevous context
-# Local variables added to this context are not shared with the previous context
-class SubScopeContext
-special ScopeContext
-       readable var _prev: ScopeContext
-
-       redef fun [](s)
-       do
-               if _dico.has_key(s) then
-                       return _dico[s]
-               else
-                       return prev[s]
-               end
-       end
-
-       init with_prev(p: ScopeContext, node: ANode)
-       do
-               init(p._visitor, node)
-               _prev = p
-               _all_variables = p._all_variables
-       end
-end
-
-#################################################################
-
-# All-in-one context for flow control.
-# It features:
-# * reachability
-# * set/unset variable
-# * adaptive type of variable
-# FlowContextes are imutables, new contexts are created:
-# * as an empty root context
-# * as the adaptation of a existing context (see methods sub_*)
-# * as the merge of existing contexts
-abstract class FlowContext
-       # Display an error localised on `n' if the variable `v' is not set
-       fun check_is_set(n: ANode, v: Variable)
-       do
-               if v.must_be_set and not is_set(v) then
-                       _visitor.error(n, "Error: variable '{v}' is possibly unset.")
-               end
-       end
-
-       # The effective static type of a given variable
-       # May be different from the declaration static type
-       fun stype(v: Variable): nullable MMType
-       do
-               return v.stype
-       end
-
-       # Return a context where the variable is marked as set
-       fun sub_setvariable(v: Variable): FlowContext
-       do
-               var ctx = new SubFlowContext.with_prev(self, node)
-               ctx._set_variables.add(v)
-               return ctx
-       end
-
-       # Return a context where unreash == true
-       fun sub_unreash(node: ANode): FlowContext
-       do
-               var ctx = new SubFlowContext.with_prev(self, node)
-               ctx._unreash = true
-               return ctx
-       end
-
-       # Return a context where v is casted as t
-       fun sub_with(node: ANode, v: Variable, t: MMType): FlowContext
-       do
-               return new CastFlowContext(self, node, v, t)
-       end
-
-       # Merge various alternative contexts (all must be reashable)
-       # Note that self can belong to alternatives
-       # Base is self
-       fun merge(node: ANode, alternatives: Array[FlowContext]): FlowContext
-       do
-               for a in alternatives do assert not a.unreash
-               if alternatives.length == 1 then return alternatives.first
-               return new MergeFlowContext(self, node, alternatives)
-       end
-
-       # Merge only context that are reachable
-       # Used for if/then/else merges
-       # Base is self
-       fun merge_reash(node: ANode, alt1, alt2: FlowContext): FlowContext
-       do
-               if alt1.unreash then
-                       if alt2.unreash then
-                               return self.sub_unreash(node)
-                       else
-                               var t = alt2
-                               alt2 = alt1
-                               alt1 = t
-                       end
-               end
-
-               if alt2.unreash or alt1 == alt2 then
-                       return alt1
-                       #if alt1 == self then
-                       #       return self
-                       #else
-                       #       return merge(node, [alt1])
-                       #end
-               else
-                       return merge(node, [alt1, alt2])
-               end
-       end
-
-       # The visitor of the context (used to display error)
-       var _visitor: AbsSyntaxVisitor
-
-       # The syntax node that introduced the context
-       readable var _node: ANode
-
-       init(visitor: AbsSyntaxVisitor, node: ANode)
-       do
-               _visitor = visitor
-               _node = node
-       end
-
-       # Is a control flow break met? (return, break, continue)
-       readable var _unreash: Bool = false
-
-       # Is a control flow already broken?
-       # Used to avoid repeating the same error message
-       readable writable var _already_unreash: Bool = false
-
-       # Set of variable that are set (assigned)
-       readable var _set_variables: HashSet[Variable] = new HashSet[Variable]
-
-       # Is a variable set?
-       fun is_set(v: Variable): Bool
-       do
-               return _set_variables.has(v)
-       end
-end
-
-# Root of a variable context hierarchy
-class RootFlowContext
-special FlowContext
-       init(visitor: AbsSyntaxVisitor, node: ANode)
-       do
-               super(visitor, node)
-       end
-end
-
-# Contexts that are an evolution of a single previous context
-class SubFlowContext
-special FlowContext
-       readable var _prev: FlowContext
-
-       redef fun is_set(v)
-       do
-               return _set_variables.has(v) or _prev.is_set(v)
-       end
-
-       redef fun stype(v)
-       do
-               return prev.stype(v)
-       end
-
-       init with_prev(p: FlowContext, node: ANode)
-       do
-               init(p._visitor, node)
-               _prev = p
-       end
-end
-
-# A variable context where a variable got a type adptation
-class CastFlowContext
-special SubFlowContext
-       # The casted variable
-       var _variable: Variable
-
-       # The new static type of the variable
-       var _stype: nullable MMType
-
-       redef fun stype(v)
-       do
-               if v == _variable then
-                       return _stype
-               else
-                       return prev.stype(v)
-               end
-       end
-
-       init(p: FlowContext, node: ANode, v: Variable, s: nullable MMType)
-       do
-               with_prev(p, node)
-               _variable = v
-               _stype = s
-       end
-end
-
-# Context that resulting from the combinaisons of other contexts.
-# Most of the merge computation are done lasily.
-class MergeFlowContext
-special FlowContext
-       var _base: FlowContext
-       var _alts: Array[FlowContext]
-
-       # Updated static type of variables
-       var _stypes: Map[Variable, nullable MMType] = new HashMap[Variable, nullable MMType]
-
-       init(base: FlowContext, node: ANode, alts: Array[FlowContext])
-       do
-               super(base._visitor, node)
-               _alts = alts
-               _base = base
-       end
-
-       redef fun stype(v)
-       do
-               if _stypes.has_key(v) then
-                       return _stypes[v]
-               else
-                       var s = merge_stype(v)
-                       _stypes[v] = s
-                       return s
-               end
-       end
-
-       private fun merge_stype(v: Variable): nullable MMType
-       do
-               var candidate: nullable MMType = null
-               var is_nullable = false
-               var same_candidate: nullable MMType = _alts.first.stype(v)
-               for ctx in _alts do
-                       var t = ctx.stype(v)
-                       if t == null then
-                               return null
-                       end
-                       if t != same_candidate then
-                               same_candidate = null
-                       end
-                       if t isa MMTypeNone then
-                               is_nullable = true
-                               continue
-                       end
-                       if t isa MMNullableType then
-                               is_nullable = true
-                               t = t.as_notnull
-                       end
-                       if candidate == null or candidate < t then
-                               candidate = t
-                       end
-               end
-               if same_candidate != null then
-                       return same_candidate
-               end
-               if is_nullable then
-                       if candidate == null then
-                               return _visitor.type_none
-                       else
-                               candidate = candidate.as_nullable
-                       end
-               end
-               if candidate == null then
-                       return _base.stype(v)
-               else
-                       for ctx in _alts do
-                               var t = ctx.stype(v)
-                               if not t < candidate then
-                                       return _base.stype(v)
-                               end
-                       end
-               end
-               return candidate
-       end
-
-       redef fun is_set(v)
-       do
-               if _set_variables.has(v) then
-                       return true
-               else
-                       for ctx in _alts do
-                               if not ctx.is_set(v) then
-                                       return false
-                               end
-                       end
-                       _set_variables.add(v)
-                       return true
-               end
-       end
-end
-
-
-redef class Variable
-       # Is the variable must be set before being used ?
-       fun must_be_set: Bool do return false
-end
-
-redef class VarVariable
-       redef fun must_be_set do return true
-end