# An AST2ICode context stores the currently built icode informations
class A2IContext
-special ICodeBuilder
+ super ICodeBuilder
redef fun stmt(s: ICode)
do
if _current_node != null then
fun add_new_array(stype: MMType, length: Int): IRegister
do
var prop = visitor.get_method(stype, once "with_capacity".to_symbol)
- var ni = expr(new INative("TAG_Int({length})", null), visitor.type_int)
+ var ni = expr(new IIntValue(length.to_s), visitor.type_int)
return expr(new INew(stype, prop, [ni]), stype)
end
# The method associated to the iroutine (if any)
readable var _method: nullable MMMethod
+ # The register of self (if any)
+ var selfreg: nullable IRegister writable
+
init(visitor: AbsSyntaxVisitor, r: IRoutine, m: nullable MMMethod)
do
- super(visitor.module, r)
+ super(visitor.mmmodule, r)
_visitor = visitor
_return_seq = r.body
_return_value = r.result
fun generate_icode(tc: ToolContext)
do
var v = new A2IVisitor(tc, self)
- for c in src_local_classes do
- for p in c.src_local_properties do
+ for c in src_local_classes.values do
+ for p in c.src_local_properties.values do
if p isa MMSrcMethod then
p.generate_iroutine(v)
else if p isa MMSrcAttribute then
end
class A2IVisitor
-special AbsSyntaxVisitor
+ super AbsSyntaxVisitor
writable var _icode_ctx: nullable A2IContext
fun icode_ctx: A2IContext do return _icode_ctx.as(not null)
redef fun visit(n) do n.accept_icode_generation(self)
v.seq = iclos.body
escapable.continue_seq = iclos.body
escapable.continue_value = iclos.result
+ escapable.break_seq = v.return_seq
+ escapable.break_value = v.return_value
n_signature.fill_iroutine_parameters(v, variable.closure.signature, iclos.params, null)
if n_expr != null then
v.generate_stmt(n_expr)
v.iroutine.closure_decls[position].default = iclos
+
+ # Add a final break in case of break block witout value
+ if variable.closure.is_break and v.return_value == null then
+ v.add_escape(v.return_seq.as(not null))
+ end
end
v.seq = old_seq
end
var params = v.iroutine.params.to_a
var selfreg = v.variable(self_var)
v.stmt(new IMove(selfreg, params[0]))
+ v.selfreg = selfreg
params.shift
var orig_meth: MMLocalProperty = method.global.intro
if n_block != null then
v.generate_stmt(n_block)
end
+ v.selfreg = null
+ end
+end
+
+redef class AExternPropdef
+ redef fun fill_iroutine(v, method)
+ do
+ # add all explicit extern calls for this extern method
+ for explicit_import in method.as(MMMethSrcMethod).explicit_imports
+ do
+ var prop = explicit_import.method
+ var ic : IAbsCall
+ if prop.is_init then
+ ic = new INew(prop.signature.recv, prop, new List[IRegister])
+ else
+ ic = new ICall(prop, new List[IRegister])
+ end
+ ic.is_explicit_from_extern = true
+ v.stmt(ic)
+ end
+ end
+end
+
+redef class AExternInitPropdef
+ redef fun fill_iroutine(v, method)
+ do
+ var params = v.iroutine.params
+ var sig = method.signature
+ assert params.length == sig.arity + 1
+ var rtype = sig.recv # sig.return_type
+ v.add_assignment(new IRegister(rtype), v.expr(new INative(method, params), rtype))
+
+ super
end
end
redef fun fill_iroutine(v, method)
do
var params = v.iroutine.params
- var ename = "{method.module.name}_{method.local_class.name}_{method.local_class.name}_{method.name}_{method.signature.arity}"
- if n_extern != null then
- ename = n_extern.text
- ename = ename.substring(1, ename.length-2)
- end
- var sig = method.signature
- assert params.length == sig.arity + 1
- var args = new Array[String]
- args.add(sig.recv.unboxtype("@@@"))
- for i in [0..sig.arity[ do
- args.add(sig[i].unboxtype("@@@"))
- end
- var s = "{ename}({args.join(", ")})"
- var rtype = sig.return_type
+ var rtype = method.signature.return_type
if rtype != null then
- s = rtype.boxtype(s)
- v.add_return_value(v.expr(new INative(s, params), rtype))
+ v.add_return_value(v.expr(new INative(method, params), rtype))
else
- v.stmt(new INative(s, params))
+ v.stmt(new INative(method, params))
end
+
+ super
end
end
redef class AInternMethPropdef
redef fun fill_iroutine(v, method)
do
- var p = v.iroutine.params.to_a
- var c = method.local_class.name
- var n = method.name
- var s: nullable String = null
- if c == once "Int".to_symbol then
- if n == once "object_id".to_symbol then
- s = "@@@"
- else if n == once "unary -".to_symbol then
- s = "TAG_Int(-UNTAG_Int(@@@))"
- else if n == once "output".to_symbol then
- s = "printf(\"%ld\\n\", UNTAG_Int(@@@));"
- else if n == once "ascii".to_symbol then
- s = "TAG_Char(UNTAG_Int(@@@))"
- else if n == once "succ".to_symbol then
- s = "TAG_Int(UNTAG_Int(@@@)+1)"
- else if n == once "prec".to_symbol then
- s = "TAG_Int(UNTAG_Int(@@@)-1)"
- else if n == once "to_f".to_symbol then
- s = "BOX_Float((float)UNTAG_Int(@@@))"
- else if n == once "+".to_symbol then
- s = "TAG_Int(UNTAG_Int(@@@)+UNTAG_Int(@@@))"
- else if n == once "-".to_symbol then
- s = "TAG_Int(UNTAG_Int(@@@)-UNTAG_Int(@@@))"
- else if n == once "*".to_symbol then
- s = "TAG_Int(UNTAG_Int(@@@)*UNTAG_Int(@@@))"
- else if n == once "/".to_symbol then
- s = "TAG_Int(UNTAG_Int(@@@)/UNTAG_Int(@@@))"
- else if n == once "%".to_symbol then
- s = "TAG_Int(UNTAG_Int(@@@)%UNTAG_Int(@@@))"
- else if n == once "<".to_symbol then
- s = "TAG_Bool(UNTAG_Int(@@@)<UNTAG_Int(@@@))"
- else if n == once ">".to_symbol then
- s = "TAG_Bool(UNTAG_Int(@@@)>UNTAG_Int(@@@))"
- else if n == once "<=".to_symbol then
- s = "TAG_Bool(UNTAG_Int(@@@)<=UNTAG_Int(@@@))"
- else if n == once ">=".to_symbol then
- s = "TAG_Bool(UNTAG_Int(@@@)>=UNTAG_Int(@@@))"
- else if n == once "lshift".to_symbol then
- s = "TAG_Int(UNTAG_Int(@@@)<<UNTAG_Int(@@@))"
- else if n == once "rshift".to_symbol then
- s = "TAG_Int(UNTAG_Int(@@@)>>UNTAG_Int(@@@))"
- else if n == once "==".to_symbol then
- s = "TAG_Bool((@@@)==(@@@))"
- else if n == once "!=".to_symbol then
- s = "TAG_Bool((@@@)!=(@@@))"
- end
- else if c == once "Float".to_symbol then
- if n == once "object_id".to_symbol then
- s = "TAG_Int((bigint)UNBOX_Float(@@@))"
- else if n == once "unary -".to_symbol then
- s = "BOX_Float(-UNBOX_Float(@@@))"
- else if n == once "output".to_symbol then
- s = "printf(\"%f\\n\", UNBOX_Float(@@@));"
- else if n == once "to_i".to_symbol then
- s = "TAG_Int((bigint)UNBOX_Float(@@@))"
- else if n == once "+".to_symbol then
- s = "BOX_Float(UNBOX_Float(@@@)+UNBOX_Float(@@@))"
- else if n == once "-".to_symbol then
- s = "BOX_Float(UNBOX_Float(@@@)-UNBOX_Float(@@@))"
- else if n == once "*".to_symbol then
- s = "BOX_Float(UNBOX_Float(@@@)*UNBOX_Float(@@@))"
- else if n == once "/".to_symbol then
- s = "BOX_Float(UNBOX_Float(@@@)/UNBOX_Float(@@@))"
- else if n == once "<".to_symbol then
- s = "TAG_Bool(UNBOX_Float(@@@)<UNBOX_Float(@@@))"
- else if n == once ">".to_symbol then
- s = "TAG_Bool(UNBOX_Float(@@@)>UNBOX_Float(@@@))"
- else if n == once "<=".to_symbol then
- s = "TAG_Bool(UNBOX_Float(@@@)<=UNBOX_Float(@@@))"
- else if n == once ">=".to_symbol then
- s = "TAG_Bool(UNBOX_Float(@@@)>=UNBOX_Float(@@@))"
- end
- else if c == once "Char".to_symbol then
- if n == once "object_id".to_symbol then
- s = "TAG_Int(UNTAG_Char(@@@))"
- else if n == once "unary -".to_symbol then
- s = "TAG_Char(-UNTAG_Char(@@@))"
- else if n == once "output".to_symbol then
- s = "printf(\"%c\", (unsigned char)UNTAG_Char(@@@));"
- else if n == once "ascii".to_symbol then
- s = "TAG_Int((unsigned char)UNTAG_Char(@@@))"
- else if n == once "succ".to_symbol then
- s = "TAG_Char(UNTAG_Char(@@@)+1)"
- else if n == once "prec".to_symbol then
- s = "TAG_Char(UNTAG_Char(@@@)-1)"
- else if n == once "to_i".to_symbol then
- s = "TAG_Int(UNTAG_Char(@@@)-'0')"
- else if n == once "+".to_symbol then
- s = "TAG_Char(UNTAG_Char(@@@)+UNTAG_Char(@@@))"
- else if n == once "-".to_symbol then
- s = "TAG_Char(UNTAG_Char(@@@)-UNTAG_Char(@@@))"
- else if n == once "*".to_symbol then
- s = "TAG_Char(UNTAG_Char(@@@)*UNTAG_Char(@@@))"
- else if n == once "/".to_symbol then
- s = "TAG_Char(UNTAG_Char(@@@)/UNTAG_Char(@@@))"
- else if n == once "%".to_symbol then
- s = "TAG_Char(UNTAG_Char(@@@)%UNTAG_Char(@@@))"
- else if n == once "<".to_symbol then
- s = "TAG_Bool(UNTAG_Char(@@@)<UNTAG_Char(@@@))"
- else if n == once ">".to_symbol then
- s = "TAG_Bool(UNTAG_Char(@@@)>UNTAG_Char(@@@))"
- else if n == once "<=".to_symbol then
- s = "TAG_Bool(UNTAG_Char(@@@)<=UNTAG_Char(@@@))"
- else if n == once ">=".to_symbol then
- s = "TAG_Bool(UNTAG_Char(@@@)>=UNTAG_Char(@@@))"
- else if n == once "==".to_symbol then
- s = "TAG_Bool((@@@)==(@@@))"
- else if n == once "!=".to_symbol then
- s = "TAG_Bool((@@@)!=(@@@))"
- end
- else if c == once "Bool".to_symbol then
- if n == once "object_id".to_symbol then
- s = "TAG_Int(UNTAG_Bool(@@@))"
- else if n == once "unary -".to_symbol then
- s = "TAG_Bool(-UNTAG_Bool(@@@))"
- else if n == once "output".to_symbol then
- s = "(void)printf(UNTAG_Bool(@@@)?\"true\\n\":\"false\\n\");"
- else if n == once "ascii".to_symbol then
- s = "TAG_Bool(UNTAG_Bool(@@@))"
- else if n == once "to_i".to_symbol then
- s = "TAG_Int(UNTAG_Bool(@@@))"
- else if n == once "==".to_symbol then
- s = "TAG_Bool((@@@)==(@@@))"
- else if n == once "!=".to_symbol then
- s = "TAG_Bool((@@@)!=(@@@))"
- end
- else if c == once "NativeArray".to_symbol then
- if n == once "object_id".to_symbol then
- s = "TAG_Int(((Nit_NativeArray)@@@)->object_id)"
- else if n == once "[]".to_symbol then
- s = "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]"
- else if n == once "[]=".to_symbol then
- s = "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]=@@@"
- else if n == once "copy_to".to_symbol then
- var t = p[0]
- p[0] = p[1]
- p[1] = t
- s = "(void)memcpy(((Nit_NativeArray )@@@)->val, ((Nit_NativeArray)@@@)->val, UNTAG_Int(@@@)*sizeof(val_t))"
- end
- else if c == once "NativeString".to_symbol then
- if n == once "object_id".to_symbol then
- s = "TAG_Int(UNBOX_NativeString(@@@))"
- else if n == once "atoi".to_symbol then
- s = "TAG_Int(atoi(UNBOX_NativeString(@@@)))"
- else if n == once "[]".to_symbol then
- s = "TAG_Char(UNBOX_NativeString(@@@)[UNTAG_Int(@@@)])"
- else if n == once "[]=".to_symbol then
- s = "UNBOX_NativeString(@@@)[UNTAG_Int(@@@)]=UNTAG_Char(@@@);"
- else if n == once "copy_to".to_symbol then
- var t = p[0]
- p[0] = p[1]
- p[1] = p[4]
- p[4] = p[2]
- p[2] = t
- s = "(void)memcpy(UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNTAG_Int(@@@));"
- end
- else if n == once "object_id".to_symbol then
- s = "TAG_Int((bigint)((obj_t)@@@)[1].object_id)"
- else if n == once "sys".to_symbol then
- s = "(G_sys)"
- else if n == once "is_same_type".to_symbol then
- s = "TAG_Bool((VAL2VFT(@@@)==VAL2VFT(@@@)))"
- else if n == once "exit".to_symbol then
- p[0] = p[1]
- s = "exit(UNTAG_Int(@@@));"
- else if n == once "calloc_array".to_symbol then
- p[0] = p[1]
- s = "NEW_NativeArray(UNTAG_Int(@@@), sizeof(val_t))"
- else if n == once "calloc_string".to_symbol then
- p[0] = p[1]
- s = "BOX_NativeString((char*)raw_alloc((UNTAG_Int(@@@) * sizeof(char))))"
- end
- if s == null then
- v.visitor.error(self, "Fatal error: unknown intern method {method.full_name}.")
- s = "NIT_NULL"
- end
+ var params = v.iroutine.params
var rtype = method.signature.return_type
if rtype != null then
- v.add_return_value(v.expr(new INative(s, p), rtype))
+ v.add_return_value(v.expr(new INative(method, params), rtype))
else
- v.stmt(new INative(s, p))
+ v.stmt(new INative(method, params))
end
end
end
if ne != null then
v.add_assignment(v.return_value.as(not null), v.generate_expr(ne))
end
- v.stmt(new IEscape(v.return_seq.as(not null)))
+ v.add_escape(v.return_seq.as(not null))
return null
end
end
if ne != null then
v.add_assignment(escapable.break_value.as(not null), v.generate_expr(ne))
end
- v.stmt(new IEscape(escapable.break_seq.as(not null)))
+ v.add_escape(escapable.break_seq.as(not null))
return null
end
end
if ne != null then
v.add_assignment(escapable.continue_value.as(not null), v.generate_expr(ne))
end
- v.stmt(new IEscape(escapable.continue_seq.as(not null)))
+ v.add_escape(escapable.continue_seq.as(not null))
return null
end
end
# Process escape (condition is false)
v.seq = iif.else_seq
- v.stmt(new IEscape(iloop))
+ v.add_escape(iloop)
v.seq = seq_old
return null
redef class AForExpr
redef fun generate_icode(v)
do
- var expr_type = n_expr.stype
-
- # Get iterator
- var meth_iterator = v.visitor.get_method(expr_type, once "iterator".to_symbol)
-
- var iter_type = meth_iterator.signature_for(expr_type).return_type.as(not null)
- var ireg_iter = v.expr(new ICall(meth_iterator, [v.generate_expr(n_expr)]), iter_type)
-
- # Enter loop
- var seq_old = v.seq
- var iloop = new ILoop
- v.stmt(iloop)
- escapable.break_seq = iloop
- v.seq = iloop
-
- # Condition evaluation
- var meth_is_ok = v.visitor.get_method(iter_type, once ("is_ok".to_symbol))
- var ireg_isok = v.expr(new ICall(meth_is_ok, [ireg_iter]), v.visitor.type_bool)
- var iif = new IIf(ireg_isok)
+ var ne = n_expr
+ var expr_type = ne.stype
+ var tint = v.visitor.type_int
+ var meth # The method that call the closure
+ var args # The arguments of meth
+
+ if ne isa ARangeExpr and expr_type == v.visitor.type_range(tint) then
+ # Shortcut. No Range[Int] object allocated.
+ # 'for x in [y..z] do' become 'y.enumerate_to(z) !each(x) do'
+ # 'for x in [y..z[ do' become 'y.enumerate_before(z) !each(x) do'
+ # And both methods may be inlined
+ args = [v.generate_expr(ne.n_expr), v.generate_expr(ne.n_expr2)]
+ if ne isa ACrangeExpr then
+ meth = v.visitor.get_method(tint, once "enumerate_to".to_symbol)
+ else
+ assert ne isa AOrangeExpr
+ meth = v.visitor.get_method(tint, once "enumerate_before".to_symbol)
+ end
+ else
+ # Standard way.
+ # 'for x in e do' become 'e.iterate !each(x) do'
+ # Some iterate methods may be inlined (eg. the Array one)
+ meth = v.visitor.get_method(expr_type, once "iterate".to_symbol)
+ args = [v.generate_expr(n_expr)]
+ end
- # Process insite the loop (condition is true)
- v.stmt(iif)
- v.seq = iif.then_seq
- escapable.continue_seq = iif.then_seq
+ # Build closure
+ var iclos = meth.signature.closures.first.signature.generate_empty_iclosuredef(v)
+ var old_seq = v.seq
- # Automatic variable assignment
- var meth_item = v.visitor.get_method(iter_type, once ("item".to_symbol))
- var va_stype = variable.stype.as(not null)
- var ireg_item = v.expr(new ICall(meth_item, [ireg_iter]), va_stype)
- var ireg_va = v.variable(variable)
- v.add_assignment(ireg_va, ireg_item)
+ var seq = new ISeq
+ v.stmt(seq)
+ v.seq = seq
+ escapable.break_seq = seq
+ escapable.break_value = null
- # Body evaluation
+ v.seq = iclos.body
+ escapable.continue_seq = iclos.body
+ escapable.continue_value = null
+ for i in [0..variables.length[ do
+ v.stmt(new IMove(v.variable(variables[i]), iclos.params[i]))
+ end
v.generate_stmt(n_block)
- # Exit contition (condition is false)
- v.seq = iif.else_seq
- v.stmt(new IEscape(iloop))
-
- # Next step
- var meth_next = v.visitor.get_method(iter_type, once ("next".to_symbol))
- v.seq = iloop
- v.stmt(new ICall(meth_next, [ireg_iter]))
+ # Call closure
+ v.seq = seq
+ v.add_call(meth, args, [iclos])
- v.seq = seq_old
+ v.seq = old_seq
return null
end
end
if id == null then
v.add_abort("Assert failed")
else
- v.add_abort("Assert %s failed", id.to_s)
+ v.add_abort("Assert '%s' failed", id.text.to_s)
end
v.seq = seq_old
return null
end
end
+redef class AOrElseExpr
+ redef fun generate_icode(v)
+ do
+ # Compute left operand
+ var e = v.generate_expr(n_expr)
+
+ # Prepare result
+ var reg = v.new_register(stype)
+
+ # Compare left and null
+ var n = v.lit_null_reg
+ var c = v.expr(new IIs(e, n), v.mmmodule.type_bool)
+ var iif = new IIf(c)
+ v.stmt(iif)
+ var old_seq = v.seq
+
+ # if equal, result = right opr
+ v.seq = iif.then_seq
+ v.add_assignment(reg, v.generate_expr(n_expr2))
+
+ # else, result = left operand
+ v.seq = iif.else_seq
+ v.add_assignment(reg, e)
+
+ v.seq = old_seq
+
+ return reg
+ end
+end
+
redef class AIsaExpr
redef fun generate_icode(v)
do
var e = v.generate_expr(n_expr)
- return v.expr(new ITypeCheck(e, n_type.stype), stype)
+ return v.expr(new ITypeCheck(v.selfreg.as(not null), e, n_type.stype), stype)
end
end
redef class AIntExpr
redef fun generate_icode(v)
do
- return v.expr(new INative("TAG_Int({n_number.text})", null), stype)
+ return v.expr(new IIntValue(n_number.text), stype)
end
end
redef class AFloatExpr
redef fun generate_icode(v)
do
- return v.expr(new INative("BOX_Float({n_float.text})", null), stype)
+ return v.expr(new IFloatValue(n_float.text), stype)
end
end
redef class ACharExpr
redef fun generate_icode(v)
do
- return v.expr(new INative("TAG_Char({n_char.text})", null), stype)
+ return v.expr(new ICharValue(n_char.text), stype)
end
end
var ionce = new IOnce
var reg = v.expr(ionce, stype)
v.seq = ionce.body
- var ns = v.expr(new INative("BOX_NativeString(\"{_cstring}\")", null), v.visitor.type_nativestring)
- var ni = v.expr(new INative("TAG_Int({_cstring_length})", null), v.visitor.type_int)
+ var ns = v.expr(new IStringValue(_cstring.as(not null)), v.visitor.type_nativestring)
+ var ni = v.expr(new IIntValue(_cstring_length.to_s), v.visitor.type_int)
var prop = v.visitor.get_method(stype, once "with_native".to_symbol)
var e = v.expr(new INew(stype, prop, [ns, ni]), stype)
v.add_assignment(reg, e)
redef class AArrayExpr
redef fun generate_icode(v)
do
- var recv = v.add_new_array(stype, n_exprs.length)
- for ne in n_exprs do
+ var nes = n_exprs.n_exprs
+ var recv = v.add_new_array(stype, nes.length)
+ for ne in nes do
var e = v.generate_expr(ne)
v.add_call_array_add(recv, e)
end
end
var args = new Array[IRegister].with_capacity(arity + 1)
args.add(v.iroutine.params[0])
- if n_args.length != arity then
+ var nas = n_args.n_exprs
+ if nas.length != arity then
for i in [0..arity[ do
args.add(v.iroutine.params[i + 1])
end
else
- for na in n_args do
+ for na in nas do
args.add(v.generate_expr(na))
end
end
v.generate_stmt(n_expr)
+ # Add a final break in case of break block witout value
+ if closure.is_break and escapable.break_value == null then
+ v.add_escape(escapable.break_seq.as(not null))
+ end
+
v.seq = seq_old
_iclosure_def = iclos
return iclos
return r
end
end
+
+redef class ADebugTypeExpr
+ redef fun generate_icode(v)
+ do
+ # Do nothing.
+ return null
+ end
+end