end
redef class ModelBuilder
+ # Entry point to performs a global compilation on the AST of a complete program.
+ # `mainmodule` is the main module of the program
+ # `runtime_type_analysis` is a already computer type analysis.
fun run_global_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
do
var time0 = get_time
v.add_decl("#include <string.h>")
# TODO: Better way to activate the GC
- #v.add_decl("#include <gc/gc.h>")
- v.add_decl("#define GC_MALLOC(x) calloc(1, (x))")
+ v.add_decl("#include <gc/gc.h>")
+ #v.add_decl("#define GC_MALLOC(x) calloc(1, (x))")
- # Declare structure for each live type
+ # Declaration of structures the live Nit types
+ # Each live type is generated as an independent C `struct' type.
+ # They only share a common first field `classid` used to implement the polymorphism.
+ # Usualy, all C variables that refers to a Nit object are typed on the abstract struct `val' that contains only the `classid` field.
- v.add_decl("typedef struct \{int classid;\} val;")
+ v.add_decl("typedef struct \{int classid;\} val; /* general C type representing a Nit instance. */")
for t in runtime_type_analysis.live_types do
compiler.declare_runtimeclass(v, t)
end
+ # Global variable used by the legacy native interface
+
v.add_decl("extern int glob_argc;")
v.add_decl("extern char **glob_argv;")
v.add_decl("extern val *glob_sys;")
# Init instance code (allocate and init-arguments)
for t in runtime_type_analysis.live_types do
- if t.ctype != "val*" then continue
- compiler.generate_init_instance(t)
+ if t.ctype == "val*" then
+ compiler.generate_init_instance(t)
+ else
+ compiler.generate_box_instance(t)
+ end
end
# The main function of the C
if main_method != null then
v.send(main_method, [glob_sys])
end
+ v.add("return 0;")
v.add("\}")
# Compile until all runtime_functions are visited
while not compiler.todos.is_empty do
var m = compiler.todos.shift
- self.toolcontext.info("Compile {m.mmethoddef} for {m.recv} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3)
- m.mmethoddef.compile_to_c(compiler, self, m.recv)
+ self.toolcontext.info("Compile {m} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3)
+ m.compile_to_c(compiler)
end
self.toolcontext.info("Total methods to compile to C: {compiler.visitors.length}", 2)
+ var time1 = get_time
+ self.toolcontext.info("*** END VISITING: {time1-time0} ***", 2)
+ write_and_make(compiler)
+ end
+
+ protected fun write_and_make(compiler: GlobalCompiler)
+ do
+ var mainmodule = compiler.mainmodule
+
# Generate the .h and .c files
+ # A single C file regroups many compiled rumtime functions
+ # Note that we do not try to be clever an a small change in a Nit source file may change the content of all the generated .c files
+ var time0 = get_time
var outname = self.toolcontext.opt_output.value
if outname == null then
makefile.write("all: {outname}\n\n")
var ofiles = new Array[String]
+ # Compile each generated file
for f in cfiles do
var o = f.strip_extension(".c") + ".o"
- makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) -I .nit_compile -I ../clib -c -o {o} {f}\n\n")
+ makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) -D NONITCNI -c -o {o} {f}\n\n")
ofiles.add(o)
end
-
- makefile.write("{outname}: {ofiles.join(" ")} {compiler.extern_bodies.join(" ")}\n\t$(CC) -Wl,--warn-unresolved-symbols $(CFLAGS) $(LDFLAGS) $(LDLIBS) -I .nit_compile -I ../clib -o {outname} {ofiles.join(" ")} {compiler.extern_bodies.join(" ")}\n\n")
+ # Compile each required extern body into a specific .o
+ for f in compiler.extern_bodies do
+ i += 1
+ var o = ".nit_compile/{mainmodule.name}.{i}.o"
+ makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) -D NONITCNI -c -o {o} {f}\n\n")
+ ofiles.add(o)
+ end
+ # Link edition
+ makefile.write("{outname}: {ofiles.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outname} {ofiles.join(" ")} $(LDLIBS)\n\n")
+ # Clean
+ makefile.write("clean:\n\trm {ofiles.join(" ")} 2>/dev/null\n\n")
makefile.close
self.toolcontext.info("Generated makefile: {makename}", 2)
time0 = time1
self.toolcontext.info("*** COMPILING C ***", 1)
- self.toolcontext.info("make -f {makename} -j 4", 2)
+ self.toolcontext.info("make -B -f {makename} -j 4", 2)
var res
if self.toolcontext.verbose_level >= 3 then
- res = sys.system("make -f {makename} -j 4 2>&1")
+ res = sys.system("make -B -f {makename} -j 4 2>&1")
else
- res = sys.system("make -f {makename} -j 4 2>&1 >/dev/null")
+ res = sys.system("make -B -f {makename} -j 4 2>&1 >/dev/null")
end
if res != 0 then
toolcontext.error(null, "make failed! Error code: {res}.")
end
# Singleton that store the knowledge about the compilation process
-private class GlobalCompiler
+class GlobalCompiler
# The main module of the program
var mainmodule: MModule
# The modeulbuilder used to know the model and the AST
var modelbuilder: ModelBuilder
- # Is hardening asked (see --hardening)
+ # Is hardening asked? (see --hardening)
fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value
init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis, modelbuilder: ModelBuilder)
end
# Subset of runtime_type_analysis.live_types that contains only primitive types
+ # Used to implement the equal test
var live_primitive_types: Array[MClassType]
# runtime_functions that need to be compiled
- private var todos: List[RuntimeFunction] = new List[RuntimeFunction]
+ private var todos: List[AbstractRuntimeFunction] = new List[AbstractRuntimeFunction]
# runtime_functions already seen (todo or done)
- private var seen: HashSet[RuntimeFunction] = new HashSet[RuntimeFunction]
- fun todo(m: RuntimeFunction)
+ private var seen: HashSet[AbstractRuntimeFunction] = new HashSet[AbstractRuntimeFunction]
+ fun todo(m: AbstractRuntimeFunction)
do
if seen.has(m) then return
todos.add(m)
# Where global declaration are stored (the main .h)
#
# FIXME: should not be a vistor but just somewhere to store lines
- # FIXME: should not have a global .h since its does no helps recompilation
- var header: nullable GlobalCompilerVisitor = null
+ # FIXME: should not have a global .h since it does not help recompilations
+ var header: nullable GlobalCompilerVisitor writable = null
# The list of all associated visitors
# Used to generate .c files
+ # FIXME: should not be vistors but just somewhere to store lines
private var visitors: List[GlobalCompilerVisitor] = new List[GlobalCompilerVisitor]
# List of additional .c files required to compile (native interface)
end
# Cache for classid (computed by declare_runtimeclass)
- private var classids: HashMap[MClassType, String] = new HashMap[MClassType, String]
+ protected var classids: HashMap[MClassType, String] = new HashMap[MClassType, String]
# Declare C structures and identifiers for a runtime class
fun declare_runtimeclass(v: GlobalCompilerVisitor, mtype: MClassType)
var idname = "ID_" + mtype.c_name
self.classids[mtype] = idname
v.add_decl("#define {idname} {idnum} /* {mtype} */")
+
v.add_decl("struct {mtype.c_name} \{")
v.add_decl("int classid; /* must be {idname} */")
+
+ if mtype.mclass.name == "NativeArray" then
+ # NativeArrays are just a instance header followed by an array of values
+ v.add_decl("{mtype.arguments.first.ctype} values[1];")
+ end
+
if mtype.ctype != "val*" then
+ # Is the Nit type is native then the struct is a box with two fields:
+ # * the `classid` to be polymorph
+ # * the `value` that contains the native value.
v.add_decl("{mtype.ctype} value;")
end
+
+ # Collect all attributes and associate them a field in the structure.
+ # Note: we do not try to optimize the order and helps CC to optimize the client code.
for cd in mtype.collect_mclassdefs(self.mainmodule) do
for p in cd.intro_mproperties do
if not p isa MAttribute then continue
assert mtype.ctype == "val*"
var v = new GlobalCompilerVisitor(self)
- self.header.add_decl("{mtype.ctype} NEW_{mtype.c_name}(void);")
+ var is_native_array = mtype.mclass.name == "NativeArray"
+
+ var sig
+ if is_native_array then
+ sig = "int length"
+ else
+ sig = "void"
+ end
+
+ self.header.add_decl("{mtype.ctype} NEW_{mtype.c_name}({sig});")
v.add_decl("/* allocate {mtype} */")
- v.add_decl("{mtype.ctype} NEW_{mtype.c_name}(void) \{")
+ v.add_decl("{mtype.ctype} NEW_{mtype.c_name}({sig}) \{")
var res = v.new_var(mtype)
- v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}));")
+ res.is_exact = true
+ if is_native_array then
+ var mtype_elt = mtype.arguments.first
+ v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}) + length*sizeof({mtype_elt.ctype}));")
+ else
+ v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}));")
+ end
v.add("{res}->classid = {self.classid(mtype)};")
for cd in mtype.collect_mclassdefs(self.mainmodule)
v.add("\}")
end
+ fun generate_box_instance(mtype: MClassType)
+ do
+ assert self.runtime_type_analysis.live_types.has(mtype)
+ assert mtype.ctype != "val*"
+ var v = new GlobalCompilerVisitor(self)
+
+ self.header.add_decl("val* BOX_{mtype.c_name}({mtype.ctype});")
+ v.add_decl("/* allocate {mtype} */")
+ v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
+ v.add("struct {mtype.c_name}*res = GC_MALLOC(sizeof(struct {mtype.c_name}));")
+ v.add("res->classid = {self.classid(mtype)};")
+ v.add("res->value = value;")
+ v.add("return (val*)res;")
+ v.add("\}")
+
+ end
+
# look for a needed .h and .c file for a given .nit source-file
# FIXME: bad API, parameter should be a MModule, not its source-file
fun add_extern(file: String)
if tryfile.file_exists then
self.extern_bodies.add(tryfile)
end
- #(new OFStream.open("{file.basename("")}._nitni.h")).close
end
+
+ private var collect_types_cache: HashMap[MType, Array[MClassType]] = new HashMap[MType, Array[MClassType]]
end
redef class String
else if mclass.name == "NativeString" then
return "char*"
else if mclass.name == "NativeArray" then
- assert self isa MGenericType
- return "{self.arguments.first.ctype}*"
+ #return "{self.arguments.first.ctype}*"
+ return "val*"
else if mclass.kind == extern_kind then
return "void*"
else
end
end
+redef class MParameterType
+ redef fun c_name
+ do
+ var res = self.c_name_cache
+ if res != null then return res
+ res = "FT{self.rank}"
+ self.c_name_cache = res
+ return res
+ end
+end
+
redef class MNullableType
redef fun c_name
do
# A C function associated to a Nit method
# Because of customization, a given Nit method can be compiler more that once
-private class RuntimeFunction
+abstract class AbstractRuntimeFunction
# The associated Nit method
var mmethoddef: MMethodDef
+ # The mangled c name of the runtime_function
+ # Subclasses should redefine `build_c_name` instead
+ fun c_name: String
+ do
+ var res = self.c_name_cache
+ if res != null then return res
+ res = self.build_c_name
+ self.c_name_cache = res
+ return res
+ end
+
+ # Non cached version of `c_name`
+ protected fun build_c_name: String is abstract
+
+ private var c_name_cache: nullable String = null
+
+ # Implements a call of the runtime_function
+ # May inline the body or generate a C function call
+ fun call(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
+
+ # Generate the code for the RuntimeFunction
+ # Warning: compile more than once compilation makes CC unhappy
+ fun compile_to_c(compiler: GlobalCompiler) is abstract
+end
+
+# A runtime function customized on a specific monomrph receiver type
+private class CustomizedRuntimeFunction
+ super AbstractRuntimeFunction
+
# The considered reciever
# (usually is a live type but no strong guarantee)
var recv: MClassType
- # The mangled c name of the runtime_function
- fun c_name: String
+ init(mmethoddef: MMethodDef, recv: MClassType)
+ do
+ super(mmethoddef)
+ self.recv = recv
+ end
+
+ redef fun build_c_name: String
do
var res = self.c_name_cache
if res != null then return res
return res
end
- private var c_name_cache: nullable String = null
-
redef fun ==(o)
# used in the compiler worklist
do
- if not o isa RuntimeFunction then return false
+ if not o isa CustomizedRuntimeFunction then return false
if self.mmethoddef != o.mmethoddef then return false
if self.recv != o.recv then return false
return true
end
end
- # Implements a call of the runtime_function
- # May inline the body
- fun call(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
+ # compile the code customized for the reciever
+ redef fun compile_to_c(compiler)
+ do
+ var recv = self.recv
+ var mmethoddef = self.mmethoddef
+ if not recv.is_subtype(compiler.mainmodule, null, mmethoddef.mclassdef.bound_mtype) then
+ print("problem: why do we compile {self} for {recv}?")
+ abort
+ end
+
+ var v = new GlobalCompilerVisitor(compiler)
+ var selfvar = new RuntimeVariable("self", recv, recv)
+ if compiler.runtime_type_analysis.live_types.has(recv) then
+ selfvar.is_exact = true
+ end
+ var arguments = new Array[RuntimeVariable]
+ var frame = new Frame(v, mmethoddef, recv, arguments)
+ v.frame = frame
+
+ var sig = new Buffer
+ var comment = new Buffer
+ var ret = mmethoddef.msignature.return_mtype
+ if ret != null then
+ ret = v.resolve_for(ret, selfvar)
+ sig.append("{ret.ctype} ")
+ else if mmethoddef.mproperty.is_new then
+ ret = recv
+ sig.append("{ret.ctype} ")
+ else
+ sig.append("void ")
+ end
+ sig.append(self.c_name)
+ sig.append("({recv.ctype} {selfvar}")
+ comment.append("(self: {selfvar}")
+ arguments.add(selfvar)
+ for i in [0..mmethoddef.msignature.arity[ do
+ var mtype = mmethoddef.msignature.mparameters[i].mtype
+ if i == mmethoddef.msignature.vararg_rank then
+ mtype = v.get_class("Array").get_mtype([mtype])
+ end
+ mtype = v.resolve_for(mtype, selfvar)
+ comment.append(", {mtype}")
+ sig.append(", {mtype.ctype} p{i}")
+ var argvar = new RuntimeVariable("p{i}", mtype, mtype)
+ arguments.add(argvar)
+ end
+ sig.append(")")
+ comment.append(")")
+ if ret != null then
+ comment.append(": {ret}")
+ end
+ compiler.header.add_decl("{sig};")
+
+ v.add_decl("/* method {self} for {comment} */")
+ v.add_decl("{sig} \{")
+ #v.add("printf(\"method {self} for {comment}\\n\");")
+ if ret != null then
+ frame.returnvar = v.new_var(ret)
+ end
+ frame.returnlabel = v.get_name("RET_LABEL")
+
+ mmethoddef.compile_inside_to_c(v, arguments)
+
+ v.add("{frame.returnlabel.as(not null)}:;")
+ if ret != null then
+ v.add("return {frame.returnvar.as(not null)};")
+ end
+ v.add("\}")
+ end
+
+ redef fun call(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
do
var ret = self.mmethoddef.msignature.return_mtype
if self.mmethoddef.mproperty.is_new then
- ret = arguments.first.mtype
+ ret = recv
end
if ret != null then
ret = v.resolve_for(ret, arguments.first)
end
end
-# A runtime variable hold a runtime value in C
-# Runtime variables are associated to local variables and intermediate results
-private class RuntimeVariable
+# A runtime variable hold a runtime value in C.
+# Runtime variables are associated to Nit local variables and intermediate results in Nit expressions.
+#
+# The tricky point is that a single C variable can be associated to more than one RuntimeVariable because the static knowledge of the type of an expression can vary in the C code.
+class RuntimeVariable
# The name of the variable in the C code
var name: String
var mtype: MType
# The current casted type of the variable (as known in Nit)
- var mcasttype: MType
+ var mcasttype: MType writable
# If the variable exaclty a mcasttype?
# false (usual value) means that the variable is a mcasttype or a subtype.
- var is_exact: Bool = false
+ var is_exact: Bool writable = false
+
+ init(name: String, mtype: MType, mcasttype: MType)
+ do
+ self.name = name
+ self.mtype = mtype
+ self.mcasttype = mcasttype
+ assert not mtype.need_anchor
+ assert not mcasttype.need_anchor
+ end
redef fun to_s do return name
- redef fun inspect do return "<{inspect_head} {name}:{mtype}({mcasttype})>"
+ redef fun inspect
+ do
+ var exact_str
+ if self.is_exact then
+ exact_str = " exact"
+ else
+ exact_str = ""
+ end
+ var type_str
+ if self.mtype == self.mcasttype then
+ type_str = "{mtype}{exact_str}"
+ else
+ type_str = "{mtype}({mcasttype}{exact_str})"
+ end
+ return "<{name}:{type_str}>"
+ end
end
-# Visit the AST to generate the C code.
+# A visitor on the AST of property definition that generate the C code.
# Because of inlining, a visitor can visit more than one property.
-private class GlobalCompilerVisitor
+class GlobalCompilerVisitor
# The associated compiler
var compiler: GlobalCompiler
# Force to get the primitive property named `name' in the instance `recv' or abort
fun get_property(name: String, recv: MType): MMethod
do
- return self.compiler.mainmodule.force_get_primitive_method(name, recv)
+ return self.compiler.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, recv, self.compiler.mainmodule)
end
# The current Frame
- var frame: nullable Frame
+ var frame: nullable Frame writable
# Anchor a type to the main module and the current receiver
fun anchor(mtype: MType): MType
private var decl_lines: List[String] = new List[String]
# The current visited AST node
- var current_node: nullable AExpr = null
+ var current_node: nullable ANode = null
- # Compile an expression an return its
+ # Compile an expression an return its result
+ # `mtype` is the expected return type, pass null if no specific type is expected.
fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable
do
var old = self.current_node
end
# Unsafely cast a value to a new type
+ # ie the result share the same C variable but my have a different mcasttype
+ # NOTE: if the adaptation is useless then `value' is returned as it.
# ENSURE: return.name == value.name
fun autoadapt(value: RuntimeVariable, mtype: MType): RuntimeVariable
do
mtype = self.anchor(mtype)
- if value.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
+ var valmtype = value.mcasttype
+ if valmtype.is_subtype(self.compiler.mainmodule, null, mtype) then
return value
end
- var valmtype = value.mtype
if valmtype isa MNullableType and valmtype.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
- var res = new RuntimeVariable(value.name, value.mtype, valmtype.mtype)
+ var res = new RuntimeVariable(value.name, valmtype, valmtype.mtype)
return res
else
- var res = new RuntimeVariable(value.name, value.mtype, mtype)
+ var res = new RuntimeVariable(value.name, valmtype, mtype)
return res
end
end
if value.mtype.ctype == mtype.ctype then
return value
else if value.mtype.ctype == "val*" then
- return self.new_expr("((struct {mtype.c_name}*){value})->value /* autounbox from {value.mtype} to {mtype} */", mtype)
+ return self.new_expr("((struct {mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
else if mtype.ctype == "val*" then
var valtype = value.mtype.as(MClassType)
var res = self.new_var(mtype)
self.add("printf(\"Dead code executed!\\n\"); exit(1);")
return res
end
- self.add("{res} = GC_MALLOC(sizeof(struct {valtype.c_name})); /* autobox from {value.mtype} to {mtype} */")
- self.add("{res}->classid = {self.compiler.classid(valtype)};")
- self.add("((struct {valtype.c_name}*){res})->value = {value};")
+ self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
return res
else
- # Bad things will append!
+ # Bad things will appen!
var res = self.new_var(mtype)
self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); exit(1);")
return expr(nexpr, bool_type)
end
- # Compile statement
+ # Compile a statement (if any)
fun stmt(nexpr: nullable AExpr)
do
if nexpr == null then return
self.current_node = old
end
- # Safely show a debug message on the current node and repeat the message in the C code
+ # Safely show a debug message on the current node and repeat the message in the C code as a comment
fun debug(message: String)
do
var node = self.current_node
# Return a new uninitialized local runtime_variable
fun new_var(mtype: MType): RuntimeVariable
do
- if mtype isa MNullType then
- mtype = self.object_type
- else
- mtype = self.anchor(mtype)
- end
+ mtype = self.anchor(mtype)
var name = self.get_name("var")
var res = new RuntimeVariable(name, mtype, mtype)
self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
return res
end
+ # Return a new uninitialized named runtime_variable
+ fun new_named_var(mtype: MType, name: String): RuntimeVariable
+ do
+ mtype = self.anchor(mtype)
+ var res = new RuntimeVariable(name, mtype, mtype)
+ self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
+ return res
+ end
+
# Return a new local runtime_variable initialized with the C expression `cexpr'.
fun new_expr(cexpr: String, mtype: MType): RuntimeVariable
do
private var variables: HashMap[Variable, RuntimeVariable] = new HashMap[Variable, RuntimeVariable]
+ # Return an unique and stable identifier associated with an escapemark
+ fun escapemark_name(e: nullable EscapeMark): String
+ do
+ assert e != null
+ if escapemark_names.has_key(e) then return escapemark_names[e]
+ var name = e.name
+ if name == null then name = "label"
+ name = get_name(name)
+ escapemark_names[e] = name
+ return name
+ end
+
+ private var escapemark_names = new HashMap[EscapeMark, String]
+
# Return a new name based on `s' and unique in the visitor
fun get_name(s: String): String
do
var types = [mtype]
return types
end
- var cache = self.collect_types_cache
+ var cache = self.compiler.collect_types_cache
if cache.has_key(mtype) then
return cache[mtype]
end
return types
end
- private var collect_types_cache: HashMap[MType, Array[MClassType]] = new HashMap[MType, Array[MClassType]]
-
fun resolve_for(mtype: MType, recv: RuntimeVariable): MType
do
if not mtype.need_anchor then return mtype
return res
end
+ fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable])
+ do
+ var elttype = arguments.first.mtype
+ var recv = "((struct {arguments[0].mcasttype.c_name}*){arguments[0]})->values"
+ if pname == "[]" then
+ self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null)))
+ return
+ else if pname == "[]=" then
+ self.add("{recv}[{arguments[1]}]={arguments[2]};")
+ return
+ else if pname == "copy_to" then
+ var recv1 = "((struct {arguments[1].mcasttype.c_name}*){arguments[1]})->values"
+ self.add("memcpy({recv1},{recv},{arguments[2]}*sizeof({elttype.ctype}));")
+ return
+ end
+ end
+
+ fun calloc_array(ret_type: MType, arguments: Array[RuntimeVariable])
+ do
+ self.ret(self.new_expr("NEW_{ret_type.c_name}({arguments[1]})", ret_type))
+ end
+
# Generate a polymorphic send for the method `m' and the arguments `args'
fun send(m: MMethod, args: Array[RuntimeVariable]): nullable RuntimeVariable
do
end
if types.is_empty then
- self.add("/*BUG: no live types for {args.first.mtype} . {m}*/")
+ self.add("/*BUG: no live types for {args.first.inspect} . {m}*/")
return res
end
- self.add("/* send {m} on {args.first}: {args.first.mcasttype} (declared {args.first.mtype}) */")
+ self.add("/* send {m} on {args.first.inspect} */")
if args.first.mtype.ctype != "val*" then
var propdefs = m.lookup_definitions(self.compiler.mainmodule, args.first.mtype)
if propdefs.length == 0 then
- self.add("/* skip {args.first.mcasttype}, no method {m} */")
+ self.add("/* skip, no method {m} */")
return res
end
assert propdefs.length == 1
return res
end
if args.first.mcasttype isa MNullableType then
+ # The reciever is potentially null, so we have to 3 cases: ==, != or NullPointerException
self.add("if ({args.first} == NULL) \{ /* Special null case */")
if m.name == "==" then
assert res != null
- if args[1].mcasttype.ctype == "val*" then
+ if args[1].mcasttype isa MNullableType then
self.add("{res} = ({args[1]} == NULL);")
+ else if args[1].mcasttype isa MNullType then
+ self.add("{res} = 1; /* is null */")
else
- self.add("{res} = 0; /* {args[1]}: {args[1].mcasttype} cannot be null */")
+ self.add("{res} = 0; /* {args[1].inspect} cannot be null */")
end
else if m.name == "!=" then
assert res != null
- if args[1].mcasttype.ctype == "val*" then
+ if args[1].mcasttype isa MNullableType then
self.add("{res} = ({args[1]} != NULL);")
+ else if args[1].mcasttype isa MNullType then
+ self.add("{res} = 0; /* is null */")
else
- self.add("{res} = 1; /* {args[1]}: {args[1].mcasttype} cannot be null */")
+ self.add("{res} = 1; /* {args[1].inspect} cannot be null */")
end
else
self.add_abort("Reciever is null")
self.add("/* skip {t}, no method {m} */")
continue
end
+ if propdefs.length > 1 then
+ self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first")
+ end
var propdef = propdefs.first
if propdef.mclassdef.mclass.name == "Object" and t.ctype == "val*" then
defaultpropdef = propdef
return res
end
+ # Generate a monomorphic send for the method `m', the type `t' and the arguments `args'
+ fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable
+ do
+ assert t isa MClassType
+ var propdefs = m.lookup_definitions(self.compiler.mainmodule, t)
+ if propdefs.length == 0 then
+ abort
+ end
+ if propdefs.length > 1 then
+ self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first")
+ end
+ var propdef = propdefs.first
+ return self.call(propdef, t, args)
+ end
+
fun check_valid_reciever(recvtype: MClassType)
do
if self.compiler.runtime_type_analysis.live_types.has(recvtype) or recvtype.mclass.name == "Object" then return
abort
end
+ # Generate a static call on a method definition
fun call(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
do
check_valid_reciever(recvtype)
vararg.add(rawargs[i+1])
end
# FIXME: its it to late to determine the vararg type, this should have been done during a previous analysis
- var elttype = m.msignature.parameter_mtypes[vararg_rank]
+ var elttype = m.msignature.mparameters[vararg_rank].mtype
elttype = self.resolve_for(elttype, recv)
args.add(self.array_instance(vararg, elttype))
else
args = args.to_a
end
- assert args.length == m.msignature.arity + 1 # because of self
+ if args.length != m.msignature.arity + 1 then # because of self
+ add("printf(\"NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.\\n\"); exit(1);")
+ debug("NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.")
+ return null
+ end
args.first = recv
- var rm = new RuntimeFunction(m, recvtype)
+ var rm = new CustomizedRuntimeFunction(m, recvtype)
return rm.call(self, args)
end
do
var recv = args.first
for i in [0..m.msignature.arity[ do
- var t = m.msignature.parameter_mtypes[i]
+ var t = m.msignature.mparameters[i].mtype
if i == m.msignature.vararg_rank then
t = args[i+1].mtype
end
self.add("fprintf(stderr, \"BTD BUG: Dynamic type is %s, static type is %s\\n\", class_names[{recv}->classid], \"{recv.mcasttype}\");")
end
+ # Generate a polymorphic attribute is_set test
+ fun isset_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable
+ do
+ var types = self.collect_types(recv)
+
+ var res = self.new_var(bool_type)
+
+ if types.is_empty then
+ self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
+ return res
+ end
+ self.add("/* isset {a} on {recv.inspect} */")
+ self.add("switch({recv}->classid) \{")
+ var last = types.last
+ for t in types do
+ if not self.compiler.hardening and t == last then
+ self.add("default: /*{self.compiler.classid(t)}*/")
+ else
+ self.add("case {self.compiler.classid(t)}:")
+ end
+ var recv2 = self.autoadapt(recv, t)
+ var ta = a.intro.static_mtype.as(not null)
+ ta = self.resolve_for(ta, recv2)
+ var attr = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
+ if not ta isa MNullableType then
+ if ta.ctype == "val*" then
+ self.add("{res} = ({attr} != NULL);")
+ else
+ self.add("{res} = 1; /*NOTYET isset on primitive attributes*/")
+ end
+ end
+ self.add("break;")
+ end
+ if self.compiler.hardening then
+ self.add("default: /* Bug */")
+ self.bugtype(recv)
+ end
+ self.add("\}")
+
+ return res
+ end
+
# Generate a polymorphic attribute read
fun read_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable
do
var res = self.new_var(ret)
if types.is_empty then
- self.add("/*BUG: no live types for {recv.mtype} . {a}*/")
+ self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
return res
end
- self.add("/* read {a} on {recv.mcasttype} */")
+ self.add("/* read {a} on {recv.inspect} */")
self.add("switch({recv}->classid) \{")
var last = types.last
for t in types do
var types = self.collect_types(recv)
if types.is_empty then
- self.add("/*BUG: no live types for {recv.mtype} . {a}*/")
+ self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
return
end
- self.add("/* write {a} on {recv.mcasttype} */")
+ self.add("/* write {a} on {recv.inspect} */")
self.add("switch({recv}->classid) \{")
var last = types.last
for t in types do
var res = self.new_var(bool_type)
- self.add("/* isa {mtype} on {value.mcasttype} */")
+ self.add("/* isa {mtype} on {value.inspect} */")
if value.mcasttype isa MNullableType then
self.add("if ({value} == NULL) \{")
if mtype isa MNullableType then
return res
end
+ # Generate the code required to dynamically check if 2 objects share the same runtime type
+ fun is_same_type_test(value1, value2: RuntimeVariable): RuntimeVariable
+ do
+ var res = self.new_var(bool_type)
+ if value2.mtype.ctype == "val*" then
+ if value1.mtype.ctype == "val*" then
+ self.add "{res} = {value1}->classid == {value2}->classid;"
+ else
+ self.add "{res} = {self.compiler.classid(value1.mtype.as(MClassType))} == {value2}->classid;"
+ end
+ else
+ if value1.mtype.ctype == "val*" then
+ self.add "{res} = {value1}->classid == {self.compiler.classid(value2.mtype.as(MClassType))};"
+ else if value1.mcasttype == value2.mcasttype then
+ self.add "{res} = 1;"
+ else
+ self.add "{res} = 0;"
+ end
+ end
+ return res
+ end
+
+ # Return a "const char*" variable associated to the classname of the dynamic type of an object
+ # NOTE: we do not return a RuntimeVariable "NativeString" as the class may not exist in the module/program
+ fun class_name_string(value: RuntimeVariable): String
+ do
+ var res = self.get_name("var_class_name")
+ self.add_decl("const char* {res};")
+ if value.mtype.ctype == "val*" then
+ self.add "{res} = class_names[{value}->classid];"
+ else
+ self.add "{res} = class_names[{self.compiler.classid(value.mtype.as(MClassType))}];"
+ end
+ return res
+ end
+
# Generate a Nit "is" for two runtime_variables
fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable
do
end
# Generate a check-init-instance
- # TODO: is an empty stub currently
fun check_init_instance(recv: RuntimeVariable)
do
+ var mtype = self.anchor(recv.mcasttype)
+ for cd in mtype.collect_mclassdefs(self.compiler.mainmodule)
+ do
+ var n = self.compiler.modelbuilder.mclassdef2nclassdef[cd]
+ for npropdef in n.n_propdefs do
+ if npropdef isa AAttrPropdef then
+ # Force read to check the initialization
+ self.read_attribute(npropdef.mpropdef.mproperty, recv)
+ end
+ end
+ end
end
# Generate an integer value
fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable
do
elttype = self.anchor(elttype)
- var res = self.init_instance(self.get_class("Array").get_mtype([elttype]))
+ var arraytype = self.get_class("Array").get_mtype([elttype])
+ var res = self.init_instance(arraytype)
self.add("\{ /* {res} = array_instance Array[{elttype}] */")
var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
nat.is_exact = true
- self.add("{nat} = GC_MALLOC({array.length} * sizeof({elttype.ctype}));")
+ self.add("{nat} = NEW_{nat.mtype.c_name}({array.length});")
for i in [0..array.length[ do
var r = self.autobox(array[i], elttype)
- self.add("{nat}[{i}] = {r};")
+ self.add("((struct {nat.mtype.c_name}*) {nat})->values[{i}] = {r};")
end
var length = self.int_instance(array.length)
- self.send(self.get_property("with_native", res.mtype), [res, nat, length])
+ self.send(self.get_property("with_native", arraytype), [res, nat, length])
self.check_init_instance(res)
self.add("\}")
return res
# Generate a string value
fun string_instance(string: String): RuntimeVariable
do
+ var mtype = self.get_class("String").mclass_type
+ var name = self.get_name("varonce")
+ self.add_decl("static {mtype.ctype} {name};")
+ var res = self.new_var(mtype)
+ self.add("if ({name}) \{")
+ self.add("{res} = {name};")
+ self.add("\} else \{")
var nat = self.new_var(self.get_class("NativeString").mclass_type)
self.add("{nat} = \"{string.escape_to_c}\";")
- var res = self.init_instance(self.get_class("String").mclass_type)
+ var res2 = self.init_instance(mtype)
+ self.add("{res} = {res2};")
var length = self.int_instance(string.length)
- self.send(self.get_property("with_native", res.mtype), [res, nat, length])
+ self.send(self.get_property("with_native", mtype), [res, nat, length])
self.check_init_instance(res)
+ self.add("{name} = {res};")
+ self.add("\}")
return res
end
fun add_abort(message: String)
do
if self.current_node != null and self.current_node.location.file != null then
- self.add("fprintf(stderr, \"%s (%s:%d)\\n\", \"{message.escape_to_c}\", \"{self.current_node.location.file.filename.escape_to_c}\", {current_node.location.line_start});")
+ self.add("fprintf(stderr, \"Runtime error: %s (%s:%d)\\n\", \"{message.escape_to_c}\", \"{self.current_node.location.file.filename.escape_to_c}\", {current_node.location.line_start});")
else
- self.add("fprintf(stderr, \"%s\\n\", \"{message.escape_to_c}\");")
+ self.add("fprintf(stderr, \"Runtime error: %s\\n\", \"{message.escape_to_c}\");")
end
self.add("exit(1);")
end
end
# A frame correspond to a visited property in a GlobalCompilerVisitor
-private class Frame
+class Frame
# The associated visitor
var visitor: GlobalCompilerVisitor
var arguments: Array[RuntimeVariable]
# The runtime_variable associated to the return (in a function)
- var returnvar: nullable RuntimeVariable = null
+ var returnvar: nullable RuntimeVariable writable = null
# The label at the end of the property
- var returnlabel: nullable String = null
+ var returnlabel: nullable String writable = null
end
redef class MPropDef
redef class MMethodDef
# Can the body be inlined?
- private fun can_inline(v: GlobalCompilerVisitor): Bool
+ fun can_inline(v: GlobalCompilerVisitor): Bool
do
var modelbuilder = v.compiler.modelbuilder
if modelbuilder.mpropdef2npropdef.has_key(self) then
end
# Inline the body in another visitor
- private fun compile_inside_to_c(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
+ fun compile_inside_to_c(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
do
var modelbuilder = v.compiler.modelbuilder
if modelbuilder.mpropdef2npropdef.has_key(self) then
var npropdef = modelbuilder.mpropdef2npropdef[self]
+ var oldnode = v.current_node
+ v.current_node = npropdef
npropdef.compile_to_c(v, self, arguments)
+ v.current_node = oldnode
else if self.mproperty.name == "init" then
var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
+ var oldnode = v.current_node
+ v.current_node = nclassdef
nclassdef.compile_to_c(v, self, arguments)
+ v.current_node = oldnode
else
abort
end
return null
end
-
- # Compile the body in a new visitor
- private fun compile_to_c(compiler: GlobalCompiler, modelbuilder: ModelBuilder, recv: MClassType)
- do
- if not recv.is_subtype(compiler.mainmodule, null, self.mclassdef.bound_mtype) then
- print("problem: why do we compile {self} for {recv}?")
- abort
- end
-
- var v = new GlobalCompilerVisitor(compiler)
- var selfvar = new RuntimeVariable("self", recv, recv)
- var arguments = new Array[RuntimeVariable]
- var frame = new Frame(v, self, recv, arguments)
- v.frame = frame
-
- var sig = new Buffer
- var comment = new Buffer
- var ret = self.msignature.return_mtype
- if ret != null then
- ret = v.resolve_for(ret, selfvar)
- sig.append("{ret.ctype} ")
- else if self.mproperty.is_new then
- ret = recv
- sig.append("{ret.ctype} ")
- else
- sig.append("void ")
- end
- sig.append(self.c_name)
- if recv != self.mclassdef.bound_mtype then
- sig.append("__{recv.c_name}")
- end
- sig.append("({recv.ctype} self")
- comment.append("(self: {recv}")
- arguments.add(selfvar)
- for i in [0..self.msignature.arity[ do
- var mtype = self.msignature.parameter_mtypes[i]
- if i == self.msignature.vararg_rank then
- mtype = v.get_class("Array").get_mtype([mtype])
- end
- mtype = v.resolve_for(mtype, selfvar)
- comment.append(", {mtype}")
- sig.append(", {mtype.ctype} p{i}")
- var argvar = new RuntimeVariable("p{i}", mtype, mtype)
- arguments.add(argvar)
- end
- sig.append(")")
- comment.append(")")
- if ret != null then
- comment.append(": {ret}")
- end
- compiler.header.add_decl("{sig};")
-
- v.add_decl("/* method {self} for {comment} */")
- v.add_decl("{sig} \{")
- #v.add("printf(\"method {self} for {comment}\\n\");")
- if ret != null then
- frame.returnvar = v.new_var(ret)
- end
- frame.returnlabel = v.get_name("RET_LABEL")
-
- if modelbuilder.mpropdef2npropdef.has_key(self) then
- var npropdef = modelbuilder.mpropdef2npropdef[self]
- npropdef.compile_to_c(v, self, arguments)
- else if self.mproperty.name == "init" then
- var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
- nclassdef.compile_to_c(v, self, arguments)
- else
- abort
- end
-
- v.add("{frame.returnlabel.as(not null)}:;")
- if ret != null then
- v.add("return {frame.returnvar.as(not null)};")
- end
- v.add("\}")
- end
end
redef class APropdef
- private fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
+ fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
do
- v.add("printf(\"Not implemented {class_name} {mpropdef} at {location.to_s}\\n\");")
+ v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
debug("Not yet implemented")
end
- private fun can_inline: Bool do return true
+ fun can_inline: Bool do return true
end
redef class AConcreteMethPropdef
end
end
end
-
v.stmt(self.n_block)
end
else if pname == "object_id" then
v.ret(arguments.first)
return
+ else if pname == "+" then
+ v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
+ return
+ else if pname == "-" then
+ v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
+ return
else if pname == "==" then
v.ret(v.equal_test(arguments[0], arguments[1]))
return
return
end
else if cname == "NativeArray" then
- var elttype = arguments.first.mtype
- if pname == "[]" then
- v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
- return
- else if pname == "[]=" then
- v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
- return
- else if pname == "copy_to" then
- v.add("memcpy({arguments[1]},{arguments[0]},{arguments[2]}*sizeof({elttype.ctype}));")
- return
- end
+ v.native_array_def(pname, ret, arguments)
+ return
end
if pname == "exit" then
v.add("exit({arguments[1]});")
v.ret(v.new_expr("(char*)GC_MALLOC({arguments[1]})", ret.as(not null)))
return
else if pname == "calloc_array" then
- var elttype = arguments.first.mtype.supertype_to(v.compiler.mainmodule,arguments.first.mtype.as(MClassType),v.get_class("ArrayCapable")).as(MGenericType).arguments.first
- v.ret(v.new_expr("({elttype.ctype}*)GC_MALLOC({arguments[1]} * sizeof({elttype.ctype}))", ret.as(not null)))
+ v.calloc_array(ret.as(not null), arguments)
return
else if pname == "object_id" then
v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
return
else if pname == "is_same_type" then
- if arguments[0].mtype.ctype == "val*" then
- v.ret(v.new_expr("{arguments[0]}->classid == {arguments[1]}->classid", ret.as(not null)))
- else
- v.ret(v.new_expr("{v.compiler.classid(arguments[0].mtype.as(MClassType))} == {arguments[1]}->classid", ret.as(not null)))
- end
+ v.ret(v.is_same_type_test(arguments[0], arguments[1]))
return
else if pname == "output_class_name" then
- if arguments[0].mtype.ctype == "val*" then
- v.add("printf(\"%s\\n\", class_names[{arguments.first}->classid]);")
- else
- v.add("printf(\"%s\\n\", class_names[{v.compiler.classid(arguments.first.mtype.as(MClassType))}]);")
- end
+ var nat = v.class_name_string(arguments.first)
+ v.add("printf(\"%s\\n\", {nat});")
return
else if pname == "native_class_name" then
- if arguments[0].mtype.ctype == "val*" then
- v.ret(v.new_expr("(char*)(void*)class_names[{arguments.first}->classid]", ret.as(not null)))
- else
- v.ret(v.new_expr("(char*)(void*)class_names[{v.compiler.classid(arguments.first.mtype.as(MClassType))}]", ret.as(not null)))
- end
+ var nat = v.class_name_string(arguments.first)
+ v.ret(v.new_expr("(char*){nat}", ret.as(not null)))
return
end
- v.add("printf(\"Not implemented {class_name}:{mpropdef} at {location.to_s}\\n\");")
+ v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
debug("Not implemented {mpropdef}")
end
end
ret = v.resolve_for(ret, arguments.first)
res = v.new_var(ret)
end
+ v.adapt_signature(mpropdef, arguments)
if res == null then
v.add("{externname}({arguments.join(", ")});")
var file = location.file.filename
v.compiler.add_extern(file)
end
+ v.adapt_signature(mpropdef, arguments)
var ret = arguments.first.mtype
var res = v.new_var(ret)
end
end
- private fun init_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
+ fun init_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
do
var nexpr = self.n_expr
if nexpr != null then
private fun expr(v: GlobalCompilerVisitor): nullable RuntimeVariable
do
debug("Unimplemented expr {class_name}")
- v.add("printf(\"Not implemented {class_name}:{location.to_s}\\n\");")
+ v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{location.to_s}\\n\");")
var mtype = self.mtype
if mtype == null then
return null
redef class AContinueExpr
redef fun stmt(v)
do
- v.add("goto CONTINUE_{self.escapemark.object_id};")
+ v.add("goto CONTINUE_{v.escapemark_name(self.escapemark)};")
end
end
redef class ABreakExpr
redef fun stmt(v)
do
- v.add("goto BREAK_{self.escapemark.object_id};")
+ v.add("goto BREAK_{v.escapemark_name(self.escapemark)};")
end
end
v.stmt(self.n_block)
var escapemark = self.escapemark
if escapemark != null then
- v.add("BREAK_{escapemark.object_id}: (void)0;")
+ v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
end
end
end
var cond = v.expr_bool(self.n_expr)
v.add("if (!{cond}) break;")
v.stmt(self.n_block)
- v.add("CONTINUE_{escapemark.object_id}: (void)0;")
+ v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
v.add("\}")
- v.add("BREAK_{escapemark.object_id}: (void)0;")
+ v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
end
end
do
v.add("for(;;) \{")
v.stmt(self.n_block)
- v.add("CONTINUE_{escapemark.object_id}: (void)0;")
+ v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
v.add("\}")
- v.add("BREAK_{escapemark.object_id}: (void)0;")
+ v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
end
end
redef fun stmt(v)
do
var cl = v.expr(self.n_expr, null)
- var it = v.send(v.get_property("iterator", cl.mtype), [cl])
+ var it_meth = self.method_iterator
+ assert it_meth != null
+ var it = v.send(it_meth, [cl])
assert it != null
v.add("for(;;) \{")
- var ok = v.send(v.get_property("is_ok", it.mtype), [it])
+ var isok_meth = self.method_is_ok
+ assert isok_meth != null
+ var ok = v.send(isok_meth, [it])
assert ok != null
v.add("if(!{ok}) break;")
- var i = v.send(v.get_property("item", it.mtype), [it])
- assert i != null
- v.assign(v.variable(variables.first), i)
+ if self.variables.length == 1 then
+ var item_meth = self.method_item
+ assert item_meth != null
+ var i = v.send(item_meth, [it])
+ assert i != null
+ v.assign(v.variable(variables.first), i)
+ else if self.variables.length == 2 then
+ var key_meth = self.method_key
+ assert key_meth != null
+ var i = v.send(key_meth, [it])
+ assert i != null
+ v.assign(v.variable(variables[0]), i)
+ var item_meth = self.method_item
+ assert item_meth != null
+ i = v.send(item_meth, [it])
+ assert i != null
+ v.assign(v.variable(variables[1]), i)
+ else
+ abort
+ end
v.stmt(self.n_block)
- v.add("CONTINUE_{escapemark.object_id}: (void)0;")
- v.send(v.get_property("next", it.mtype), [it])
+ v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
+ var next_meth = self.method_next
+ assert next_meth != null
+ v.send(next_meth, [it])
v.add("\}")
- v.add("BREAK_{escapemark.object_id}: (void)0;")
+ v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
end
end
redef class AArrayExpr
redef fun expr(v)
do
- var mtype = self.mtype.as(MGenericType).arguments.first
+ var mtype = self.mtype.as(MClassType).arguments.first
var array = new Array[RuntimeVariable]
for nexpr in self.n_exprs.n_exprs do
var i = v.expr(nexpr, mtype)
do
var array = new Array[RuntimeVariable]
for ne in self.n_exprs do
+ if ne isa AStringFormExpr and ne.value == "" then continue # skip empty sub-strings
var i = v.expr(ne, null)
array.add(i)
end
do
var recv = v.expr(self.n_expr, null)
var args = [recv]
- for a in compute_raw_arguments do
+ for a in self.raw_arguments.as(not null) do
args.add(v.expr(a, null))
end
var mproperty = self.mproperty.as(not null)
do
var recv = v.expr(self.n_expr, null)
var args = [recv]
- for a in compute_raw_arguments do
+ for a in self.raw_arguments.as(not null) do
args.add(v.expr(a, null))
end
var value = v.expr(self.n_value, null)
# FIXME: we do not want an ugly static call!
var mpropdefs = mpropdef.mproperty.lookup_super_definitions(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
if mpropdefs.length != 1 then
+ v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
debug("MPRODFEFS for super {mpropdef} for {recv}: {mpropdefs.join(", ")}")
end
mpropdef = mpropdefs.first
end
redef class AIssetAttrExpr
+ redef fun expr(v)
+ do
+ var recv = v.expr(self.n_expr, null)
+ var mproperty = self.mproperty.as(not null)
+ return v.isset_attribute(mproperty, recv)
+ end
end
redef class ADebugTypeExpr