X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index 2e34fbc..31dfcc4 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -651,6 +651,8 @@ abstract class AbstractCompiler self.header.add_decl("#include ") self.header.add_decl("#include ") self.header.add_decl("#include ") + # longjmp ! + self.header.add_decl("#include \n") self.header.add_decl("#include \n") self.header.add_decl("#include \n") self.header.add_decl("#include \n") @@ -679,6 +681,7 @@ abstract class AbstractCompiler compile_header_structs compile_nitni_structs + compile_catch_stack var gccd_disable = modelbuilder.toolcontext.opt_no_gcc_directive.value if gccd_disable.has("noreturn") or gccd_disable.has("all") then @@ -707,6 +710,17 @@ abstract class AbstractCompiler self.header.add_decl("extern val *glob_sys;") end + # Stack stocking environment for longjumps + protected fun compile_catch_stack do + self.header.add_decl """ +struct catch_stack_t { + int cursor; + jmp_buf envs[100]; +}; +extern struct catch_stack_t catchStack; +""" + end + # Declaration of structures for live Nit types protected fun compile_header_structs is abstract @@ -790,6 +804,7 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); v.add_decl("int glob_argc;") v.add_decl("char **glob_argv;") v.add_decl("val *glob_sys;") + v.add_decl("struct catch_stack_t catchStack;") if self.modelbuilder.toolcontext.opt_typing_test_metrics.value then for tag in count_type_test_tags do @@ -878,6 +893,7 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); v.add("signal(SIGPIPE, SIG_IGN);") v.add("glob_argc = argc; glob_argv = argv;") + v.add("catchStack.cursor = -1;") v.add("initialize_gc_option();") v.add "initialize_nitni_global_refs();" @@ -1273,17 +1289,21 @@ abstract class AbstractCompilerVisitor do mtype = self.anchor(mtype) var valmtype = value.mcasttype + + # Do nothing if useless autocast if valmtype.is_subtype(self.compiler.mainmodule, null, mtype) then return value end + # Just as_not_null if the target is not nullable. + # + # eg `nullable PreciseType` adapted to `Object` gives precisetype. if valmtype isa MNullableType and valmtype.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then - var res = new RuntimeVariable(value.name, valmtype, valmtype.mtype) - return res - else - var res = new RuntimeVariable(value.name, valmtype, mtype) - return res + mtype = valmtype.mtype end + + var res = new RuntimeVariable(value.name, value.mtype, mtype) + return res end # Generate a super call from a method definition @@ -1351,13 +1371,18 @@ abstract class AbstractCompilerVisitor # Checks + # Can value be null? (according to current knowledge) + fun maybenull(value: RuntimeVariable): Bool + do + return value.mcasttype isa MNullableType or value.mcasttype isa MNullType + end + # Add a check and an abort for a null receiver if needed fun check_recv_notnull(recv: RuntimeVariable) do if self.compiler.modelbuilder.toolcontext.opt_no_check_null.value then return - var maybenull = recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType - if maybenull then + if maybenull(recv) then self.add("if (unlikely({recv} == NULL)) \{") self.add_abort("Receiver is null") self.add("\}") @@ -1602,6 +1627,18 @@ abstract class AbstractCompilerVisitor return res end + # Generates a NativeString instance fully escaped in C-style \xHH fashion + fun native_string_instance(ns: NativeString, len: Int): RuntimeVariable do + var mtype = mmodule.native_string_type + var nat = new_var(mtype) + var byte_esc = new Buffer.with_cap(len * 4) + for i in [0 .. len[ do + byte_esc.append("\\x{ns[i].to_s.substring_from(2)}") + end + self.add("{nat} = \"{byte_esc}\";") + return nat + end + # Generate a string value fun string_instance(string: String): RuntimeVariable do @@ -1710,6 +1747,9 @@ abstract class AbstractCompilerVisitor # used by aborts, asserts, casts, etc. fun add_abort(message: String) do + self.add("if(catchStack.cursor >= 0)\{") + self.add("longjmp(catchStack.envs[catchStack.cursor], 1);") + self.add("\}") self.add("PRINT_ERROR(\"Runtime error: %s\", \"{message.escape_to_c}\");") add_raw_abort end @@ -3096,7 +3136,18 @@ redef class AAttrPropdef v.assign(v.frame.returnvar.as(not null), res) else if mpropdef == mwritepropdef then assert arguments.length == 2 - v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1]) + var recv = arguments.first + var arg = arguments[1] + if is_optional and v.maybenull(arg) then + var value = v.new_var(self.mpropdef.static_mtype.as(not null)) + v.add("if ({arg} == NULL) \{") + v.assign(value, evaluate_expr(v, recv)) + v.add("\} else \{") + v.assign(value, arg) + v.add("\}") + arg = value + end + v.write_attribute(self.mpropdef.mproperty, arguments.first, arg) if is_lazy then var ret = self.mtype var useiset = not ret.is_c_primitive and not ret isa MNullableType @@ -3339,8 +3390,19 @@ end redef class ADoExpr redef fun stmt(v) do - v.stmt(self.n_block) - v.add_escape_label(break_mark) + if self.n_catch != null then + v.add("catchStack.cursor += 1;") + v.add("if(!setjmp(catchStack.envs[catchStack.cursor]))\{") + v.stmt(self.n_block) + v.add("catchStack.cursor -= 1;") + v.add("\}else \{") + v.add("catchStack.cursor -= 1;") + v.stmt(self.n_catch) + v.add("\}") + else + v.stmt(self.n_block) + end + v.add_escape_label(break_mark) end end @@ -3509,6 +3571,9 @@ redef class AOrElseExpr do var res = v.new_var(self.mtype.as(not null)) var i1 = v.expr(self.n_expr, null) + + if not v.maybenull(i1) then return i1 + v.add("if ({i1}!=NULL) \{") v.assign(res, i1) v.add("\} else \{") @@ -3538,7 +3603,11 @@ redef class AFloatExpr end redef class ACharExpr - redef fun expr(v) do return v.char_instance(self.value.as(not null)) + redef fun expr(v) do + if is_ascii then return v.byte_instance(value.as(not null).ascii) + if is_code_point then return v.int_instance(value.as(not null).code_point) + return v.char_instance(self.value.as(not null)) + end end redef class AArrayExpr @@ -3559,14 +3628,75 @@ redef class AArrayExpr end end +redef class AugmentedStringFormExpr + # Factorize the making of a `Regex` object from a literal prefixed string + protected fun make_re(v: AbstractCompilerVisitor, rs: RuntimeVariable): nullable RuntimeVariable do + var re = to_re + assert re != null + var res = v.compile_callsite(re, [rs]) + if res == null then + print "Cannot call property `to_re` on {self}" + abort + end + for i in suffix.chars do + if i == 'i' then + var ign = ignore_case + assert ign != null + v.compile_callsite(ign, [res, v.bool_instance(true)]) + continue + end + if i == 'm' then + var nl = newline + assert nl != null + v.compile_callsite(nl, [res, v.bool_instance(true)]) + continue + end + if i == 'b' then + var ext = extended + assert ext != null + v.compile_callsite(ext, [res, v.bool_instance(false)]) + continue + end + # Should not happen, this needs to be updated + # along with the addition of new suffixes + abort + end + return res + end +end + redef class AStringFormExpr - redef fun expr(v) do return v.string_instance(self.value.as(not null)) + redef fun expr(v) do return v.string_instance(value) +end + +redef class AStringExpr + redef fun expr(v) do + var s = v.string_instance(value) + if is_string then return s + if is_bytestring then + var ns = v.native_string_instance(bytes.items, bytes.length) + var ln = v.int_instance(bytes.length) + var cs = to_bytes_with_copy + assert cs != null + var res = v.compile_callsite(cs, [ns, ln]) + assert res != null + s = res + else if is_re then + var res = make_re(v, s) + assert res != null + s = res + else + print "Unimplemented prefix or suffix for {self}" + abort + end + return s + end end redef class ASuperstringExpr redef fun expr(v) do - var type_string = mtype.as(not null) + var type_string = v.mmodule.string_type # Collect elements of the superstring var array = new Array[AExpr] @@ -3620,10 +3750,14 @@ redef class ASuperstringExpr # Fast join the native string to get the result var res = v.send(v.get_property("native_to_s", a.mtype), [a]) + assert res != null + + if is_re then res = make_re(v, res) # We finish to work with the native array, # so store it so that it can be reused v.add("{varonce} = {a};") + return res end end @@ -3691,7 +3825,7 @@ redef class AAsNotnullExpr var i = v.expr(self.n_expr, null) if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i - if i.mtype.is_c_primitive then return i + if not v.maybenull(i) then return i v.add("if (unlikely({i} == NULL)) \{") v.add_abort("Cast failed")