end
end
+redef class VarVariable
+ redef readable var _is_typed: Bool = false
+end
###############################################################################
v.base_variable_ctx = v.variable_ctx
v.variable_ctx = v.variable_ctx.sub(self)
- var escapable = new EscapableClosure(self, variable.closure, null)
+ var blist: nullable Array[AExpr] = null
+ var t = v.local_property.signature.return_type
+ if t != null then blist = new Array[AExpr]
+ var escapable = new EscapableClosure(self, variable.closure, blist)
_escapable = escapable
v.escapable_ctx.push(escapable, null)
if v.variable_ctx.unreash == false then
if variable.closure.signature.return_type != null then
v.error(self, "Control error: Reached end of block (a 'continue' with a value was expected).")
- else if variable.closure.is_break then
- v.error(self, "Control error: Reached end of break block (an 'abort' was expected).")
+ else if variable.closure.is_break and escapable.break_list != null then
+ v.error(self, "Control error: Reached end of break block (a 'break' with a value was expected).")
end
end
end
+ if blist != null then for x in blist do
+ v.check_conform_expr(x, t)
+ end
old_var_ctx.merge(v.variable_ctx)
v.variable_ctx = old_var_ctx
redef fun after_typing(v)
do
- var va = new VarVariable(n_id.to_symbol, self)
+ var va = new VarVariable(n_id.to_symbol, n_id)
_variable = va
v.variable_ctx.add(va)
- if n_expr != null then v.variable_ctx.mark_is_set(va)
+ var ne = n_expr
+ if ne != null then v.variable_ctx.mark_is_set(va)
if n_type != null then
if not n_type.is_typed then return
va.stype = n_type.stype
- if n_expr != null then
- v.check_conform_expr(n_expr.as(not null), va.stype)
+ if ne != null then
+ v.check_conform_expr(ne, va.stype)
end
- else
- if not v.check_expr(n_expr.as(not null)) then return
+ else if ne != null then
+ if not v.check_expr(ne) then return
va.stype = n_expr.stype
end
+ va._is_typed = true
_is_typed = true
end
end
if esc == null then return
if esc.is_break_block then
- v.error(self, "Error: 'continue' forbiden in break blocks.")
+ v.error(self, "Error: cannot 'continue', only 'break'.")
return
end
end
end
+redef class ADoExpr
+ # The corresponding escapable block
+ readable var _escapable: nullable EscapableBlock
+
+ redef fun accept_typing(v)
+ do
+ var escapable = new BreakOnlyEscapableBlock(self)
+ _escapable = escapable
+ v.escapable_ctx.push(escapable, n_label)
+
+ super
+
+ v.escapable_ctx.pop
+ _is_typed = true
+ end
+end
+
redef class AIfExpr
redef fun accept_typing(v)
do
end
end
+redef class ALoopExpr
+ # The corresponding escapable block
+ readable var _escapable: nullable EscapableBlock
+
+ redef fun accept_typing(v)
+ do
+ var escapable = new EscapableBlock(self)
+ _escapable = escapable
+ v.escapable_ctx.push(escapable, n_label)
+ var old_var_ctx = v.variable_ctx
+ var old_base_var_ctx = v.base_variable_ctx
+ v.base_variable_ctx = v.variable_ctx
+ v.variable_ctx = v.variable_ctx.sub(self)
+
+ # Process inside
+ if n_block != null then
+ v.variable_ctx = v.variable_ctx.sub(n_block.as(not null))
+ v.enter_visit(n_block)
+ end
+
+ v.variable_ctx = old_var_ctx
+ v.base_variable_ctx = old_base_var_ctx
+ v.escapable_ctx.pop
+ _is_typed = true
+ end
+end
+
redef class AForExpr
var _variable: nullable AutoVariable
redef fun variable do return _variable.as(not null)
var old_base_var_ctx = v.base_variable_ctx
v.base_variable_ctx = v.variable_ctx
v.variable_ctx = v.variable_ctx.sub(self)
- var va = new AutoVariable(n_id.to_symbol, self)
+ var va = new AutoVariable(n_id.to_symbol, n_id)
_variable = va
v.variable_ctx.add(va)
end
redef class AAssertExpr
- redef fun after_typing(v)
+ redef fun accept_typing(v)
do
+ # Process condition
+ v.enter_visit(n_expr)
v.check_conform_expr(n_expr, v.type_bool)
+
+ # Process optional 'else' part
+ if n_else != null then
+ var old_var_ctx = v.variable_ctx
+ v.use_if_false_variable_ctx(n_expr)
+ v.enter_visit(n_else)
+ v.variable_ctx = old_var_ctx
+ end
+
+ # Prepare outside
v.use_if_true_variable_ctx(n_expr)
_is_typed = true
end
redef fun after_typing(v)
do
v.variable_ctx.mark_is_set(variable)
- var t = v.variable_ctx.stype(variable)
# Check the base type
var btype = v.base_variable_ctx.stype(variable)
- if not v.check_conform_expr(n_value, btype) then return
+ if not v.check_expr(n_value) then return
+ if btype != null and not v.check_conform_expr(n_value, btype) then return
# Always cast
v.variable_ctx.stype(variable) = n_value.stype
# Check the base type
var btype = v.base_variable_ctx.stype(variable)
- if not v.check_conform(n_value, t2, btype) then return
+ if not v.check_expr(n_value) then return
+ if btype != null and not v.check_conform(n_value, t2, btype) then return
# Always cast
v.variable_ctx.stype(variable) = t2
redef class ASuperExpr
redef readable var _init_in_superclass: nullable MMMethod
+ redef fun compute_raw_arguments do return n_args.to_a
redef fun after_typing(v)
do
var precs: Array[MMLocalProperty] = v.local_property.prhe.direct_greaters
register_super_init_call(v, p)
if n_args.length > 0 then
var signature = get_signature(v, v.self_var.stype.as(not null), p, true)
- _arguments = process_signature(v, signature, p.name, n_args.to_a)
+ process_signature(v, signature, p.name, compute_raw_arguments)
end
else
v.error(self, "Error: No super method to call for {v.local_property}.")
redef fun prop_signature do return _prop_signature.as(not null)
var _prop_signature: nullable MMSignature
- # The real arguments used (after star transformation) (once computed)
- redef fun arguments do return _arguments.as(not null)
- var _arguments: nullable Array[AExpr]
+ # Raw arguments used (without vararg transformation)
+ redef fun raw_arguments: Array[AExpr]
+ do
+ var res = _raw_arguments_cache
+ if res != null then
+ return res
+ else
+ res = compute_raw_arguments
+ if res == null then res = new Array[AExpr]
+ _raw_arguments_cache = res
+ return res
+ end
+ end
+
+ var _raw_arguments_cache: nullable Array[AExpr] = null
+
+ fun compute_raw_arguments: nullable Array[AExpr]
+ do
+ print "{location} no compute_raw_arguments"
+ return null
+ end
# Check the conformity of a set of arguments `raw_args' to a signature.
- private fun process_signature(v: TypingVisitor, psig: MMSignature, name: Symbol, raw_args: nullable Array[AExpr]): nullable Array[AExpr]
+ private fun process_signature(v: TypingVisitor, psig: MMSignature, name: Symbol, raw_args: nullable Array[AExpr]): Bool
do
var par_vararg = psig.vararg_rank
var par_arity = psig.arity
var raw_arity: Int
if raw_args == null then raw_arity = 0 else raw_arity = raw_args.length
if par_arity > raw_arity or (par_arity != raw_arity and par_vararg == -1) then
- v.error(self, "Error: '{name}' arity missmatch.")
- return null
+ v.error(self, "Error: arity missmatch; prototype is '{name}{psig}'.")
+ return false
end
var arg_idx = 0
- var args = new Array[AExpr]
for par_idx in [0..par_arity[ do
var a: AExpr
var par_type = psig[par_idx]
if par_idx == par_vararg then
- var star = new Array[AExpr]
for i in [0..(raw_arity-par_arity)] do
a = raw_args[arg_idx]
v.check_conform_expr(a, par_type)
- star.add(a)
arg_idx = arg_idx + 1
end
- var aa = new AArrayExpr.init_aarrayexpr(star)
- aa.do_typing(v, par_type)
- a = aa
else
a = raw_args[arg_idx]
v.check_conform_expr(a, par_type)
arg_idx = arg_idx + 1
end
- args.add(a)
end
- return args
+ return true
end
# Check the conformity of a set of defined closures
# Process each closure definition
for i in [0..arity[ do
- var csi = cs[i]
var cdi = cd[i]
- var esc = new EscapableClosure(cdi, csi, break_list)
- v.escapable_ctx.push(esc, n_label)
- cdi.accept_typing2(v, esc)
- v.escapable_ctx.pop
+ var cni = cdi.n_id.to_symbol
+ var csi = psig.closure_named(cni)
+ if csi != null then
+ var esc = new EscapableClosure(cdi, csi, break_list)
+ v.escapable_ctx.push(esc, n_label)
+ cdi.accept_typing2(v, esc)
+ v.escapable_ctx.pop
+ else if cs.length == 1 then
+ v.error(cdi.n_id, "Error: no closure named '!{cni}' in {name}; only closure is !{cs.first.name}.")
+ else
+ var a = new Array[String]
+ for c in cs do
+ a.add("!{c.name}")
+ end
+ v.error(cdi.n_id, "Error: no closure named '!{cni}' in {name}; only closures are {a.join(",")}.")
+ end
end
# Check break type conformity
var prop = get_property(v, type_recv, is_implicit_self, name)
if prop == null then return
var sig = get_signature(v, type_recv, prop, recv_is_self)
- var args = process_signature(v, sig, prop.name, raw_args)
- if args == null then return
+ if not process_signature(v, sig, prop.name, raw_args) then return
var rtype = process_closures(v, sig, prop.name, closure_defs)
if rtype == null and sig.return_type != null then return
_prop = prop
_prop_signature = sig
- _arguments = args
_return_type = rtype
end
end
redef class ANewExpr
+ redef fun compute_raw_arguments do return n_args.to_a
redef fun after_typing(v)
do
if not n_type.is_typed then return
name = n_id.to_symbol
end
- do_typing(v, t, false, false, name, n_args.to_a, null)
+ do_typing(v, t, false, false, name, raw_arguments, null)
if _prop == null then return
if not prop.global.is_init then
# Name of the invoked property
fun name: Symbol is abstract
- # Raw arguments used (withour star transformation)
- fun raw_arguments: nullable Array[AExpr] is abstract
-
# Closure definitions
redef fun closure_defs: nullable Array[AClosureDef] do return null
v.check_conform(self, t2, n_value.stype)
_read_prop = prop
- var old_args = arguments
+ raw_args = raw_args.to_a
raw_args.add(n_value)
do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, "{name}=".to_symbol, raw_args, null)
end
end
- _arguments = old_args # FIXME: What if star parameters do not match betwen the two methods?
_is_typed = true
end
end
redef class ABinopExpr
- redef fun raw_arguments do return [n_expr2]
+ redef fun compute_raw_arguments do return [n_expr2]
end
redef class AEqExpr
redef fun name do return once "==".to_symbol
redef class AUminusExpr
redef fun name do return once "unary -".to_symbol
- redef fun raw_arguments do return null
+ redef fun compute_raw_arguments do return null
end
redef class ACallFormExpr
end
redef fun name do return n_id.to_symbol
- redef fun raw_arguments do return n_args.to_a
+ redef fun compute_raw_arguments do return n_args.to_a
end
redef class ACallAssignExpr
end
redef fun name do return (n_id.text + "=").to_symbol
- redef fun raw_arguments do
+ redef fun compute_raw_arguments do
var res = n_args.to_a
res.add(n_value)
return res
end
redef fun name do return n_id.to_symbol
- redef fun raw_arguments do return n_args.to_a
+ redef fun compute_raw_arguments do return n_args.to_a
end
redef class ABraExpr
redef fun name do return once "[]".to_symbol
- redef fun raw_arguments do return n_args.to_a
+ redef fun compute_raw_arguments do return n_args.to_a
+ redef fun closure_defs
+ do
+ if n_closure_defs.is_empty then
+ return null
+ else
+ return n_closure_defs.to_a
+ end
+ end
end
redef class ABraAssignExpr
redef fun name do return once "[]=".to_symbol
- redef fun raw_arguments do
+ redef fun compute_raw_arguments do
var res = n_args.to_a
res.add(n_value)
return res
redef class ABraReassignExpr
redef fun name do return once "[]".to_symbol
- redef fun raw_arguments do return n_args.to_a
+ redef fun compute_raw_arguments do return n_args.to_a
end
redef class AInitExpr
redef fun name do return once "init".to_symbol
- redef fun raw_arguments do return n_args.to_a
+ redef fun compute_raw_arguments do return n_args.to_a
end
redef class AClosureCallExpr
var _variable: nullable ClosureVariable
redef fun variable do return _variable.as(not null)
+ redef fun compute_raw_arguments do return n_args.to_a
redef fun after_typing(v)
do
var va = variable
if va.closure.is_break then v.variable_ctx.unreash = true
var sig = va.closure.signature
- var args = process_signature(v, sig, n_id.to_symbol, n_args.to_a)
+ var s = process_signature(v, sig, n_id.to_symbol, compute_raw_arguments)
if not n_closure_defs.is_empty then
process_closures(v, sig, n_id.to_symbol, n_closure_defs.to_a)
end
- if args == null then return
+ if not s then return
_prop_signature = sig
- _arguments = args
_stype = sig.return_type
_is_typed = true
end
end
+redef class AClosureId
+ fun to_symbol: Symbol is abstract
+end
+redef class ASimpleClosureId
+ redef fun to_symbol: Symbol do return n_id.to_symbol
+end
+redef class ABreakClosureId
+ redef fun to_symbol: Symbol do return n_kwbreak.to_symbol
+end
+
redef class AClosureDef
var _closure: nullable MMClosure
redef fun closure do return _closure.as(not null)
_escapable = esc
var sig = esc.closure.signature
- if sig.arity != n_id.length then
- v.error(self, "Error: {sig.arity} automatic variable names expected, {n_id.length} found.")
+ if sig.arity != n_ids.length then
+ v.error(self, "Error: {sig.arity} automatic variable names expected, {n_ids.length} found.")
return
end
v.base_variable_ctx = v.variable_ctx
v.variable_ctx = v.variable_ctx.sub(self)
variables = new Array[AutoVariable]
- for i in [0..n_id.length[ do
- var va = new AutoVariable(n_id[i].to_symbol, self)
+ for i in [0..n_ids.length[ do
+ var va = new AutoVariable(n_ids[i].to_symbol, n_ids[i])
variables.add(va)
va.stype = sig[i]
v.variable_ctx.add(va)
if v.variable_ctx.unreash == false then
if closure.signature.return_type != null then
v.error(self, "Control error: Reached end of block (a 'continue' with a value was expected).")
- else if closure.is_break then
- v.error(self, "Control error: Reached end of break block (a 'break' was expected).")
+ else if closure.is_break and esc.break_list != null then
+ v.error(self, "Control error: Reached end of break block (a 'break' with a value was expected).")
end
end
v.variable_ctx = old_var_ctx