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
# 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("\}")
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
assert arguments.length == 2
var recv = arguments.first
var arg = arguments[1]
- if is_optional then
+ 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))
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 \{")
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]
# 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
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")
return instance
end
+ # Return a new native string initialized with `txt`
+ fun native_string_instance_from_ns(txt: NativeString, len: Int): Instance
+ do
+ var instance = native_string_instance_len(len)
+ var val = instance.val
+ txt.copy_to(val, len, 0, 0)
+
+ return instance
+ end
+
# Return a new native string initialized of `length`
fun native_string_instance_len(length: Int): PrimitiveInstance[NativeString]
do
return v.int32_instance(recvval.to_i32)
else if pname == "to_u32" then
return v.uint32_instance(recvval.to_u32)
- else if pname == "rand" then
- var res = recvval.rand
- return v.int_instance(res)
end
else if cname == "Byte" then
var recvval = args[0].to_b
return v.float_instance(args[0].to_f.log)
else if pname == "pow" then
return v.float_instance(args[0].to_f.pow(args[1].to_f))
- else if pname == "rand" then
- return v.float_instance(args[0].to_f.rand)
else if pname == "abs" then
return v.float_instance(args[0].to_f.abs)
else if pname == "hypot_with" then
v.callsite(method_start, [expr])
v.stmt(self.n_block)
v.is_escape(self.break_mark) # Clear the break
+
+ # Execute the finally without an escape
+ var old_mark = v.escapemark
+ v.escapemark = null
v.callsite(method_finish, [expr])
+ # Restore the escape unless another escape was provided
+ if v.escapemark == null then v.escapemark = old_mark
end
end
end
end
+ redef class AugmentedStringFormExpr
+ # Factorize the making of a `Regex` object from a literal prefixed string
+ fun make_re(v: NaiveInterpreter, rs: Instance): nullable Instance do
+ var tore = to_re
+ assert tore != null
+ var res = v.callsite(tore, [rs])
+ if res == null then
+ print "Cannot call property `to_re` on {self}"
+ abort
+ end
+ for j in suffix.chars do
+ if j == 'i' then
+ var prop = ignore_case
+ assert prop != null
+ v.callsite(prop, [res, v.bool_instance(true)])
+ continue
+ end
+ if j == 'm' then
+ var prop = newline
+ assert prop != null
+ v.callsite(prop, [res, v.bool_instance(true)])
+ continue
+ end
+ if j == 'b' then
+ var prop = extended
+ assert prop != null
+ v.callsite(prop, [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
- var txt = self.value.as(not null)
- return v.string_instance(txt)
+ 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_from_ns(bytes.items, bytes.length)
+ var ln = v.int_instance(bytes.length)
+ var prop = to_bytes_with_copy
+ assert prop != null
+ var res = v.callsite(prop, [ns, ln])
+ if res == null then
+ print "Cannot call property `to_bytes` on {self}"
+ abort
+ end
+ 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
var i = v.array_instance(array, v.mainmodule.object_type)
var res = v.send(v.force_get_primitive_method("plain_to_s", i.mtype), [i])
assert res != null
+ if is_re then res = make_re(v, res)
return res
end
end