var previous: Array[FlowContext] = new Array[FlowContext]
# Additional reachable flow that loop up to self.
- # Loops apears in `loop`, `while`, `for`, closure and with `continue`
+ # Loops apears in `loop`, `while`, `for`, and with `continue`
var loops: Array[FlowContext] = new Array[FlowContext]
private var is_marked_unreachable: Bool = false
end
end
-redef class AClosureCallExpr
- redef fun accept_flow_visitor(v)
- do
- super
- # FIXME: break closure call?
- # v.make_unreachable_flow
- end
-end
-
-redef class AClosureDef
- redef fun accept_flow_visitor(v)
- do
- var before_loop = v.make_sub_flow
-
- v.enter_visit(self.n_expr)
-
- var after_block = v.current_flow_context
- before_loop.add_loop(after_block)
-
- v.make_merge_flow(v.current_flow_context, before_loop)
- end
-end
-
redef class AIsaExpr
redef fun accept_flow_visitor(v)
do
#
# TODO: better doc
#
-# TODO: liearization, closures, extern stuff
+# TODO: liearization, extern stuff
# FIXME: better handling of the types
module model
redef fun collect_mtypes(mmodule) do return new HashSet[MClassType]
end
-# A signature of a method (or a closure)
+# A signature of a method
class MSignature
super MType
# The each parameter (in order)
var mparameters: Array[MParameter]
- var mclosures = new Array[MParameter]
-
# The return type (null for a procedure)
var return_mtype: nullable MType
var d = p.mtype.depth
if d > dmax then dmax = d
end
- for p in mclosures do
- var d = p.mtype.depth
- if d > dmax then dmax = d
- end
return dmax + 1
end
for p in mparameters do
res += p.mtype.length
end
- for p in mclosures do
- res += p.mtype.length
- end
return res
end
ret = ret.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
end
var res = new MSignature(params, ret)
- for p in self.mclosures do
- res.mclosures.add(p.resolve_for(mtype, anchor, mmodule, cleanup_virtual))
- end
return res
end
end
if self.ret_type == null then return false # Skip errir
end
- for nclosure in self.n_closure_decls do
- if not nclosure.n_signature.visit_signature(modelbuilder, nclassdef) then return false
- end
-
self.is_visited = true
return true
end
msignature = new MSignature(mparameters, ret_type)
mpropdef.msignature = msignature
mpropdef.is_abstract = self isa ADeferredMethPropdef
-
- if nsig != null then
- for nclosure in nsig.n_closure_decls do
- var clos_signature = nclosure.n_signature.build_signature(modelbuilder, nclassdef)
- if clos_signature == null then return
- var mparameter = new MParameter(nclosure.n_id.text, clos_signature, false)
- msignature.mclosures.add(mparameter)
- end
- end
-
end
redef fun check_signature(modelbuilder, nclassdef)
self.discover_call_trace.add mpropdef
self.debug("Discovered {mpropdef}")
end
- if args.length < mpropdef.msignature.arity + 1 or args.length > mpropdef.msignature.arity + 1 + mpropdef.msignature.mclosures.length then
+ if args.length < mpropdef.msignature.arity + 1 or args.length > mpropdef.msignature.arity + 1 then
fatal("NOT YET IMPLEMENTED: Invalid arity for {mpropdef}. {args.length} arguments given.")
end
- if args.length < mpropdef.msignature.arity + 1 + mpropdef.msignature.mclosures.length then
- fatal("NOT YET IMPLEMENTED: default closures")
- end
# Look for the AST node that implements the property
var mproperty = mpropdef.mproperty
end
end
- fun call_closure(closure: ClosureInstance, args: Array[Instance]): nullable Instance
- do
- var nclosuredef = closure.nclosuredef
- var f = closure.frame
- for i in [0..closure.nclosuredef.mclosure.mtype.as(MSignature).arity[ do
- var variable = nclosuredef.variables[i]
- f.map[variable] = args[i]
- end
-
- self.frames.unshift(f)
-
- self.stmt(nclosuredef.n_expr)
-
- self.frames.shift
-
- if self.is_continue(nclosuredef.escapemark) then
- var res = self.escapevalue
- self.escapevalue = null
- return res
- end
- return null
- end
-
# Execute `mproperty` for a `args` (where `args[0]` is the receiver).
# Return a falue if `mproperty` is a function, or null if it is a procedure.
# The call is polimotphic. There is a message-seding/late-bindng according to te receiver (args[0]).
redef fun to_f do return val.as(Float)
end
-private class ClosureInstance
- super Instance
-
- var frame: Frame
-
- var nclosuredef: AClosureDef
-
- init(mtype: MType, frame: Frame, nclosuredef: AClosureDef)
- do
- super(mtype)
- self.frame = frame
- self.nclosuredef = nclosuredef
- end
-end
-
# Information about local variables in a running method
private class Frame
# The current visited node
assert variable != null
f.map[variable] = args[i+1]
end
- for i in [0..mpropdef.msignature.mclosures.length[ do
- var c = mpropdef.msignature.mclosures[i]
- var variable = self.n_signature.n_closure_decls[i].variable
- assert variable != null
- f.map[variable] = args[i + 1 + mpropdef.msignature.arity]
- end
v.frames.unshift(f)
if i == null then return null
args.add(i)
end
- for c in self.n_closure_defs do
- var mtype = c.mclosure.mtype
- var instance = new ClosureInstance(mtype, v.frame, c)
- args.add(instance)
- end
var mproperty = self.mproperty.as(not null)
var res = v.send(mproperty, args)
- if v.is_break(self.escapemark) then
- res = v.escapevalue
- v.escapevalue = null
- end
return res
end
end
end
end
-redef class AClosureCallExpr
- redef fun expr(v)
- do
- var args = new Array[Instance]
- for a in self.n_args.n_exprs do
- var i = v.expr(a)
- if i == null then return null
- args.add(i)
- end
- var i = v.frame.map[self.variable.as(not null)]
- assert i isa ClosureInstance
- var res = v.call_closure(i, args)
- return res
- end
-end
-
redef class ADebugTypeExpr
redef fun stmt(v)
do
redef fun to_s do return self.name
end
-# A local variable associated to a closure definition
-class ClosureVariable
- super Variable
-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, closure)
+ # 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
end
# Visit a npropdef and:
-# * Identify variables, closures and labels
+# * Identify variables and labels
# * Associate each break and continue to its escapemark
# * Transform `ACallFormExpr` that access a variable into `AVarFormExpr`
-# * Transform `ACallFormExpr` that call a closure into `AClosureCallExpr`
# FIXME: Should the class be private?
private class ScopeVisitor
super Visitor
end
end
-redef class AClosureDecl
- # The variable associated with the closure declaration
- var variable: nullable ClosureVariable
- redef fun accept_scope_visitor(v)
- do
- var nid = self.n_id
- var variable = new ClosureVariable(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
var variable = v.search_variable(name)
if variable != null then
var n: AExpr
- if variable isa ClosureVariable then
- n = new AClosureCallExpr.init_aclosurecallexpr(n_id, n_args, n_closure_defs)
- n.variable = variable
- else
- 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
+ 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
return new AVarReassignExpr.init_avarreassignexpr(n_id, n_assign_op, n_value)
end
end
-
-redef class AClosureCallExpr
- # the associate closure variable
- var variable: nullable ClosureVariable
-end
-
-redef class ASendExpr
- # The escape mark used with the closures if any
- var escapemark: nullable EscapeMark
-
- redef fun accept_scope_visitor(v)
- do
- if self.n_closure_defs.length > 0 then
- var escapemark = v.make_escape_mark(self.n_closure_defs.last.n_label, true)
- self.escapemark = escapemark
- end
- super
- end
-end
-
-redef class AClosureDef
- # The automatic variables in order
- var variables: nullable Array[Variable]
-
- # The escape mark used with the closure
- var escapemark: nullable EscapeMark
-
- redef fun accept_scope_visitor(v)
- do
- v.scopes.unshift(new Scope)
-
- var variables = new Array[Variable]
- self.variables = variables
-
- for nid in self.n_ids do
- var va = new Variable(nid.text)
- v.register_variable(nid, va)
- variables.add(va)
- end
-
- self.escapemark = self.parent.as(ASendExpr).escapemark
- v.enter_visit_block(self.n_expr, escapemark)
-
- v.scopes.shift
- end
-end
assert variable != null
variable.declared_type = mtype
end
- for i in [0..mmethoddef.msignature.mclosures.length[ do
- var mclosure = mmethoddef.msignature.mclosures[i]
- var variable = self.n_signature.n_closure_decls[i].variable
- assert variable != null
- variable.declared_type = mclosure.mtype
- end
v.visit_stmt(nblock)
if not nblock.after_flow_context.is_unreachable and mmethoddef.msignature.return_mtype != null then
else
self.is_typed = true
end
-
- if self.n_closure_defs.length == msignature.mclosures.length then
- for i in [0..self.n_closure_defs.length[ do
- self.n_closure_defs[i].accept_typing(v, msignature.mclosures[i])
- end
- else
- debug("closure: got {self.n_closure_defs.length}, want {msignature.mclosures.length}")
- end
end
# The name of the property
###
-redef class AClosureCallExpr
- redef fun accept_typing(v)
- do
- var variable = self.variable
- if variable == null then return # Skip error
-
- var recvtype = v.nclassdef.mclassdef.bound_mtype
- var msignature = variable.declared_type.as(not null)
- msignature = v.resolve_for(msignature, recvtype, false).as(MSignature)
-
- var args = n_args.to_a
- v.check_signature(self, args, variable.name, msignature)
-
- self.is_typed = true
- self.mtype = msignature.return_mtype
- end
-end
-
-redef class AClosureDef
- var mclosure: nullable MParameter
-
- private fun accept_typing(v: TypeVisitor, mparameter: MParameter)
- do
- var variables = self.variables
- if variables == null then return
-
- self.mclosure = mparameter
- var msignature = mparameter.mtype.as(MSignature)
-
- if msignature.arity != variables.length then
- v.error(self, "Type error: closure {mparameter.name} expects {msignature.arity} parameters, {variables.length} given")
- return
- end
-
- for i in [0..variables.length[ do
- variables[i].declared_type = msignature.mparameters[i].mtype
- end
-
- v.visit_stmt(self.n_expr)
- end
-end
-
-###
-
redef class ADebugTypeExpr
redef fun accept_typing(v)
do