X-Git-Url: http://nitlanguage.org diff --git a/src/transform.nit b/src/transform.nit index 2a8dda2..ebe2c73 100644 --- a/src/transform.nit +++ b/src/transform.nit @@ -17,11 +17,22 @@ module transform import astbuilder -import auto_super_init import astvalidation +import semantize +intrude import semantize::scope +intrude import semantize::typing redef class ToolContext var transform_phase: Phase = new TransformPhase(self, [typing_phase, auto_super_init_phase]) + + # --no-shortcut-range + var opt_no_shortcut_range: OptionBool = new OptionBool("Always instantiate a range and its iterator on 'for' loops", "--no-shortcut-range") + + redef init + do + super + self.option_context.add_option(self.opt_no_shortcut_range) + end end private class TransformPhase @@ -31,7 +42,9 @@ private class TransformPhase do var val - var v = new TransformVisitor(self, npropdef) + var m = npropdef.mpropdef + if m == null then return + var v = new TransformVisitor(self, m) v.enter_visit(npropdef) val = new ASTValidationVisitor @@ -43,15 +56,13 @@ private class TransformVisitor super Visitor var phase: TransformPhase - var mmodule: MModule - var mclassdef: MClassDef + var mmodule: MModule is noinit + var mclassdef: MClassDef is noinit var mpropdef: MPropDef - var builder: ASTBuilder + var builder: ASTBuilder is noinit - init(phase: TransformPhase, npropdef: APropdef) + init do - self.phase = phase - self.mpropdef = npropdef.mpropdef.as(not null) self.mclassdef = mpropdef.mclassdef self.mmodule = mclassdef.mmodule self.builder = new ASTBuilder(mmodule, mpropdef.mclassdef.bound_mtype) @@ -60,14 +71,7 @@ private class TransformVisitor redef fun visit(node) do if node isa AAnnotations then return - node.visit_all(self) - node.accept_transform_visitor(self) - end - - # Get a primitive class or display a fatal error on `location`. - fun get_class(location: AExpr, name: String): MClass - do - return mmodule.get_primitive_class(name) + node.full_transform_visitor(self) end # Get a primitive method or display a fatal error on `location`. @@ -78,11 +82,40 @@ private class TransformVisitor end redef class ANode + private fun full_transform_visitor(v: TransformVisitor) + do + visit_all(v) + accept_transform_visitor(v) + end private fun accept_transform_visitor(v: TransformVisitor) do end end +redef class AExpr + redef fun full_transform_visitor(v: TransformVisitor) + do + var na = comprehension + if na != null then + # We are building a comprehension array `array` + # Replace `self` with `array.push(self)` + var place = detach_with_placeholder + var recv = na.nnew.make_var_read + var nadd = v.builder.make_call(recv, na.push_callsite.as(not null), [self]) + place.replace_with(nadd) + end + super + end + + redef fun replace_with(other) + do + super + if other isa AExpr then + if other.implicit_cast_to == null then other.implicit_cast_to = implicit_cast_to + end + end +end + redef class AVardeclExpr # `var x = y` is replaced with `x = y` # @@ -151,82 +184,205 @@ end redef class AWhileExpr redef fun accept_transform_visitor(v) do - # TODO + var nloop = v.builder.make_loop + var nif = v.builder.make_if(n_expr, null) + nloop.add nif + + var nblock = n_block + if nblock != null then nif.n_then.add nblock + + var escapemark = self.break_mark.as(not null) + var nbreak = v.builder.make_break(escapemark) + nif.n_else.add nbreak + + nloop.break_mark = self.break_mark + nloop.continue_mark = self.continue_mark + + replace_with(nloop) end end redef class AForExpr redef fun accept_transform_visitor(v) do - # TODO + var escapemark = self.break_mark + assert escapemark != null + + var nblock = v.builder.make_block + + var nexpr = n_expr + + # Shortcut on explicit range + # Avoid the instantiation of the range and the iterator + if self.variables.length == 1 and nexpr isa ARangeExpr and not v.phase.toolcontext.opt_no_shortcut_range.value then + var variable = variables.first + nblock.add v.builder.make_var_assign(variable, nexpr.n_expr) + var to = nexpr.n_expr2 + nblock.add to + + var nloop = v.builder.make_loop + nloop.break_mark = escapemark + nblock.add nloop + + var is_ok = v.builder.make_call(v.builder.make_var_read(variable, variable.declared_type.as(not null)), method_lt.as(not null), [to.make_var_read]) + + var nif = v.builder.make_if(is_ok, null) + nloop.add nif + + var nthen = nif.n_then + var ndo = v.builder.make_do + ndo.break_mark = escapemark.continue_mark + nthen.add ndo + + ndo.add self.n_block.as(not null) + + var one = v.builder.make_int(1) + var succ = v.builder.make_call(v.builder.make_var_read(variable, variable.declared_type.as(not null)), method_successor.as(not null), [one]) + nthen.add v.builder.make_var_assign(variable, succ) + + var nbreak = v.builder.make_break(escapemark) + nif.n_else.add nbreak + + replace_with(nblock) + return + end + + nblock.add nexpr + + var iter = v.builder.make_call(nexpr.make_var_read, method_iterator.as(not null), null) + nblock.add iter + + var nloop = v.builder.make_loop + nloop.break_mark = escapemark + nblock.add nloop + + var is_ok = v.builder.make_call(iter.make_var_read, method_is_ok.as(not null), null) + + var nif = v.builder.make_if(is_ok, null) + nloop.add nif + + var nthen = nif.n_then + var ndo = v.builder.make_do + ndo.break_mark = escapemark.continue_mark + nthen.add ndo + + if self.variables.length == 1 then + var item = v.builder.make_call(iter.make_var_read, method_item.as(not null), null) + ndo.add v.builder.make_var_assign(variables.first, item) + else if self.variables.length == 2 then + var key = v.builder.make_call(iter.make_var_read, method_key.as(not null), null) + ndo.add v.builder.make_var_assign(variables[0], key) + var item = v.builder.make_call(iter.make_var_read, method_item.as(not null), null) + ndo.add v.builder.make_var_assign(variables[1], item) + else + abort + end + + ndo.add self.n_block.as(not null) + + nthen.add v.builder.make_call(iter.make_var_read, method_next.as(not null), null) + + var nbreak = v.builder.make_break(escapemark) + nif.n_else.add nbreak + + var method_finish = self.method_finish + if method_finish != null then + nblock.add v.builder.make_call(iter.make_var_read, method_finish, null) + end + + replace_with(nblock) end end -redef class AArrayExpr - # `[x,y]` is replaced with +redef class AWithExpr + # is replaced with a do/end and injected calls to `start` and `finish` # - # var t = new Array[X].with_capacity(2) - # t.add(x) - # t.add(y) - # t + # Basically, the following + # + # ~~~nitish + # with expr do + # block + # end label l + # ~~~ + # + # is transformed into + # + # ~~~nitish + # var x = expr + # do + # x.start + # block + # end label l + # x.finish + # ~~~ + # + # The point is that `finish` is called even if the block is escaped. redef fun accept_transform_visitor(v) do - var mtype = self.mtype.as(MClassType) + var escapemark = self.break_mark + assert escapemark != null + var nblock = v.builder.make_block - var meth = v.get_method(self, "with_capacity", mtype.mclass) - var nnew = v.builder.make_new(mtype, meth, [v.builder.make_int(n_exprs.n_exprs.length)]) - nblock.add nnew + var nexpr = n_expr - var madd = v.get_method(self, "push", mtype.mclass) - for nexpr in self.n_exprs.n_exprs do - var nadd = v.builder.make_call(nnew.make_var_read, madd, [nexpr]) - nblock.add nadd - end - var nres = nnew.make_var_read - nblock.add nres + nblock.add nexpr + + var ndo = v.builder.make_do + ndo.break_mark = escapemark + + var start = v.builder.make_call(nexpr.make_var_read, method_start.as(not null), null) + + ndo.add start + + ndo.add self.n_block.as(not null) + + nblock.add ndo + + nblock.add v.builder.make_call(nexpr.make_var_read, method_finish.as(not null), null) replace_with(nblock) end end -redef class ASuperstringExpr - # `"x{y}z"` is replaced with +redef class AArrayExpr + # `[x,y]` is replaced with # - # var t = new Array[Object].with_capacity(3) - # t.add("x") - # t.add(y) - # t.add("z") - # t.to_s - redef fun accept_transform_visitor(v) + # ~~~nitish + # var t = new Array[X].with_capacity(2) + # t.add(x) + # t.add(y) + # t + # ~~~ + redef fun full_transform_visitor(v) do var nblock = v.builder.make_block - var arraytype = v.get_class(self, "Array").get_mtype([v.get_class(self, "Object").mclass_type]) - var meth = v.get_method(self, "with_capacity", arraytype.mclass) - var nnew = v.builder.make_new(arraytype, meth, [v.builder.make_int(n_exprs.length)]) + var nnew = v.builder.make_new(with_capacity_callsite.as(not null), [v.builder.make_int(n_exprs.length)]) + self.nnew = nnew + nblock.add nnew - var madd = v.get_method(self, "add", arraytype.mclass) + super + for nexpr in self.n_exprs do - var nadd = v.builder.make_call(nnew.make_var_read, madd, [nexpr]) - nblock.add nadd + nblock.add nexpr end - - var mtos = v.get_method(self, "to_s", arraytype.mclass) - var ntos = v.builder.make_call(nnew.make_var_read, mtos, null) - nblock.add ntos + var nres = nnew.make_var_read + nblock.add nres replace_with(nblock) end + + private var nnew: ANewExpr is noinit end redef class ACrangeExpr # `[x..y]` is replaced with `new Range[X](x,y)` redef fun accept_transform_visitor(v) do - var mtype = self.mtype.as(MClassType) - replace_with(v.builder.make_new(mtype, init_callsite.mproperty, [n_expr, n_expr2])) + if parent isa AForExpr then return # to permit shortcut ranges + replace_with(v.builder.make_new(init_callsite.as(not null), [n_expr, n_expr2])) end end @@ -234,8 +390,8 @@ redef class AOrangeExpr # `[x..y[` is replaced with `new Range[X].without_last(x,y)` redef fun accept_transform_visitor(v) do - var mtype = self.mtype.as(MClassType) - replace_with(v.builder.make_new(mtype, init_callsite.mproperty, [n_expr, n_expr2])) + if parent isa AForExpr then return # to permit shortcut ranges + replace_with(v.builder.make_new(init_callsite.as(not null), [n_expr, n_expr2])) end end @@ -250,11 +406,15 @@ end redef class ASendReassignFormExpr # `x.foo(y)+=z` is replaced with # - # x.foo(y) = x.foo(y) + z + # ~~~nitish + # x.foo(y) = x.foo(y) + z + # ~~~ # # witch is, in reality: # - # x."foo="(y, x.foo(y)."+"(z)) + # ~~~nitish + # x."foo="(y, x.foo(y)."+"(z)) + # ~~~ redef fun accept_transform_visitor(v) do var nblock = v.builder.make_block @@ -262,18 +422,18 @@ redef class ASendReassignFormExpr var read_args = new Array[AExpr] var write_args = new Array[AExpr] - for a in raw_arguments.as(not null) do + for a in raw_arguments do nblock.add(a) read_args.add(a.make_var_read) write_args.add(a.make_var_read) end - var nread = v.builder.make_call(n_expr.make_var_read, callsite.mproperty, read_args) + var nread = v.builder.make_call(n_expr.make_var_read, callsite.as(not null), read_args) - var nnewvalue = v.builder.make_call(nread, reassign_callsite.mproperty, [n_value]) + var nnewvalue = v.builder.make_call(nread, reassign_callsite.as(not null), [n_value]) write_args.add(nnewvalue) - var nwrite = v.builder.make_call(n_expr.make_var_read, write_callsite.mproperty, write_args) + var nwrite = v.builder.make_call(n_expr.make_var_read, write_callsite.as(not null), write_args) nblock.add(nwrite) replace_with(nblock) @@ -288,7 +448,7 @@ redef class AVarReassignExpr var nread = v.builder.make_var_read(variable, read_type.as(not null)) - var nnewvalue = v.builder.make_call(nread, reassign_callsite.mproperty, [n_value]) + var nnewvalue = v.builder.make_call(nread, reassign_callsite.as(not null), [n_value]) var nwrite = v.builder.make_var_assign(variable, nnewvalue) replace_with(nwrite) @@ -304,7 +464,7 @@ redef class AAttrReassignExpr var attribute = self.mproperty.as(not null) var nread = v.builder.make_attr_read(n_expr.make_var_read, attribute) - var nnewvalue = v.builder.make_call(nread, reassign_callsite.mproperty, [n_value]) + var nnewvalue = v.builder.make_call(nread, reassign_callsite.as(not null), [n_value]) var nwrite = v.builder.make_attr_assign(n_expr.make_var_read, attribute, nnewvalue) nblock.add(nwrite)