# 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
_set_variables.add(v)
end
- fun check_is_set(n: PNode, v: Variable)
+ 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.")
- var x = self
- while true do
- print " {x.node.locate}: {x._set_variables.join(", ")} ; {x._dico.join(", ")}"
- var x0 = x
- if x0 isa SubVariableContext then
- x = x0.prev
- else
- break
- end
- end
end
end
var _stypes: Map[Variable, nullable MMType] = new HashMap[Variable, nullable MMType]
# Build a new VariableContext
- fun sub(node: PNode): SubVariableContext
+ fun sub(node: ANode): SubVariableContext
do
return new SubVariableContext.with_prev(self, node)
end
# Build a nested VariableContext with new variable information
- fun sub_with(node: PNode, v: Variable, t: MMType): SubVariableContext
+ fun sub_with(node: ANode, v: Variable, t: MMType): SubVariableContext
do
var ctx = sub(node)
ctx.stype(v) = t
var _visitor: AbsSyntaxVisitor
# The syntax node that introduced the context
- readable var _node: PNode
+ readable var _node: ANode
- init(visitor: AbsSyntaxVisitor, node: PNode)
+ init(visitor: AbsSyntaxVisitor, node: ANode)
do
_visitor = visitor
_node = node
do
if ctx1.unreash then
merge(ctx2)
+ return
else if ctx2.unreash then
merge(ctx1)
+ return
end
for v in _all_variables do
if not is_set(v) and ctx1.is_set(v) and ctx2.is_set(v) then
var s2 = ctx2.stype(v)
if s1 == s and s2 == s then
# NOP
- else if s1 == s2 then
- stype(v) = s1
- else if s2 == null or s1 < s2 then
- stype(v) = s2
- else if s1 == null or s2 < s1 then
- stype(v) = s1
+ else if s1 == null or s2 == null then
+ stype(v) = null
else
+ var sm = merge_types(s1, s2)
+ if sm == null then
+ stype(v) = basectx.stype(v)
+ else
+ stype(v) = sm
+ end
+ end
+ end
+ end
+
+ # Combine informations of ctx to the current flow context informations as an alternative
+ # Require that all contexts are reachable at the end
+ fun combine_merge(ctxs: Array[VariableContext], basectx: VariableContext)
+ do
+ for v in _all_variables do
+ do
+ if not is_set(v) then
+ for ctx in ctxs do
+ if not ctx.is_set(v) then break label set
+ end
+ mark_is_set(v)
+ end
+ end label set
+
+ var candidate: nullable MMType = null
+ var is_nullable = false
+ var same_candidate: nullable MMType = ctxs.first.stype(v)
+ for ctx in ctxs do
+ var t = ctx.stype(v)
+ if t == null then
+ stype(v) = null
+ continue label each_variable
+ 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
+ stype(v) = same_candidate
+ end
+ if is_nullable then
+ if candidate == null then
+ candidate = _visitor.type_none
+ else
+ candidate = candidate.as_nullable
+ end
+ end
+ if candidate == null then
stype(v) = basectx.stype(v)
+ else
+ for ctx in ctxs do
+ var t = ctx.stype(v)
+ if not t < candidate then
+ stype(v) = basectx.stype(v)
+ continue label each_variable
+ end
+ end
end
+ stype(v) = candidate
+ end label each_variable
+ end
+
+ # Combine and get the most specific comon supertype
+ # return null if no comon supertype is found
+ private fun merge_types(t1, t2: MMType): nullable MMType
+ do
+ if t1 == t2 then return t1
+ if t1 isa MMTypeNone then return t2.as_nullable
+ if t2 isa MMTypeNone then return t1.as_nullable
+ var is_nullable = false
+ if t1.is_nullable then
+ is_nullable = true
+ t1 = t1.as_notnull
+ end
+ if t2.is_nullable then
+ is_nullable = true
+ t2 = t2.as_notnull
+ end
+ var t: MMType
+ if t1 < t2 then
+ t = t2
+ else if t2 < t1 then
+ t = t1
+ else
+ return null
end
+ if is_nullable then t = t.as_nullable
+ return t
end
redef fun to_s
do
var s = new Buffer
- s.append(node.locate)
+ s.append(node.location.to_s)
for v in _all_variables do
var t = stype(v)
if t == null then continue
class RootVariableContext
special VariableContext
- init(visitor: AbsSyntaxVisitor, node: PNode)
+ init(visitor: AbsSyntaxVisitor, node: ANode)
do
super(visitor, node)
_all_variables = new HashSet[Variable]
end
end
- init with_prev(p: VariableContext, node: PNode)
+ init with_prev(p: VariableContext, node: ANode)
do
init(p._visitor, node)
_prev = p