def trans_mname(cname, mname, arg_typs=[]): global _mtds r_mtd = mname mid = u'_'.join([cname, mname] + arg_typs) # use memoized method name conversion if mid in _mtds: return _mtds[mid] # methods of Java collections elif util.is_collection(cname): _arg_typs = map(trans_ty, arg_typs) r_mtd = u'_'.join([mname, trans_ty(cname)] + _arg_typs) else: if is_replaced(cname): tr_name = trans_ty(cname) cls = class_lookup(tr_name) if cls and cls.is_aux: cname = tr_name mtds = find_mtds_by_sig(cname, mname, arg_typs) if mtds and 1 == len(mtds): r_mtd = unicode(repr(mtds[0])) else: # ambiguous or not found r_mtd = '_'.join([mname, util.sanitize_ty(cname)]) r_mtd = sanitize_mname(r_mtd) _mtds[mid] = r_mtd return r_mtd
def trans_e(mtd, e): curried = partial(trans_e, mtd) buf = cStringIO.StringIO() if e.kind == C.E.GEN: if e.es: buf.write("{| ") buf.write(" | ".join(map(curried, e.es))) buf.write(" |}") else: buf.write(C.T.HOLE) elif e.kind == C.E.ID: if hasattr(e, "ty"): buf.write(trans_ty(e.ty) + ' ') fld = None if mtd and e.id not in mtd.param_vars: fld = find_fld(mtd.clazz.name, e.id) if fld: # fname -> self.new_fname (unless the field is static) new_fname = trans_fname(fld.clazz.name, e.id, fld.is_static) if fld.is_static: # access to the static field inside the same class if fld.clazz.name == mtd.clazz.name: buf.write(e.id) # o.w., e.g., static constant in an interface, call the accessor else: buf.write(new_fname + "()") else: buf.write('.'.join([C.SK.self, new_fname])) elif e.id in [C.J.THIS, C.J.SUP]: buf.write(C.SK.self) elif util.is_str(e.id): # constant string, such as "Hello, World" str_init = trans_mname(C.J.STR, C.J.STR, [u"char[]", C.J.i, C.J.i]) s_hash = hash(e.id) % 256 # hash string value itself buf.write("{}(new Object(hash={}), {}, 0, {})".format(str_init, s_hash, e.id, len(e.id))) else: buf.write(e.id) elif e.kind == C.E.UOP: buf.write(' '.join([e.op, curried(e.e)])) elif e.kind == C.E.BOP: buf.write(' '.join([curried(e.le), e.op, curried(e.re)])) elif e.kind == C.E.DOT: # with package names, e.g., javax.swing.SwingUtilities if util.is_class_name(e.re.id) and class_lookup(e.re.id): buf.write(curried(e.re)) elif e.re.id == C.J.THIS: # ClassName.this buf.write(C.SK.self) else: rcv_ty = typ_of_e(mtd, e.le) fld = find_fld(rcv_ty, e.re.id) new_fname = trans_fname(rcv_ty, e.re.id, fld.is_static) if fld.is_static: # access to the static field inside the same class if mtd and rcv_ty == mtd.clazz.name: buf.write(e.re.id) # o.w., e.g., static constant in an interface, call the accessor else: buf.write(new_fname + "()") else: buf.write('.'.join([curried(e.le), new_fname])) elif e.kind == C.E.IDX: buf.write(curried(e.e) + '[' + curried(e.idx) + ']') elif e.kind == C.E.NEW: if e.e.kind == C.E.CALL: ty = typ_of_e(mtd, e.e.f) cls = class_lookup(ty) if cls and cls.has_init: arg_typs = map(partial(typ_of_e, mtd), e.e.a) mname = trans_mname(cls.name, cls.name, arg_typs) obj = "alloc@log({})".format(cls.id) args = [obj] + map(unicode, map(curried, e.e.a)) buf.write("{}({})".format(mname, ", ".join(args))) else: # collection or Object buf.write(C.J.NEW + ' ' + trans_ty(ty) + "()") else: # o.w., array initialization, e.g., new int[] { ... } buf.write(str(e.init)) elif e.kind == C.E.CALL: arg_typs = map(partial(typ_of_e, mtd), e.a) def trans_call(callee, rcv_ty, rcv): if callee.is_static: rcv = None args = util.rm_none([rcv] + map(curried, e.a)) mid = trans_mname(rcv_ty, callee.name, arg_typs) return u"{}({})".format(mid, ", ".join(args)) def dynamic_dispatch(rcv_ty, rcv, acc, callee): _dispatched = trans_call(callee, callee.clazz.name, rcv) _guarded = "{}.__cid == {} ? {}".format(rcv, callee.clazz.id, _dispatched) return "({} : {})".format(_guarded, acc) if e.f.kind == C.E.DOT: # rcv.mid rcv_ty = typ_of_e(mtd, e.f.le) rcv = curried(e.f.le) mname = e.f.re.id mtd_callees = find_mtds_by_sig(rcv_ty, mname, arg_typs) if mtd_callees and 1 < len(mtd_callees): # needs dynamic dispatch curried_dispatch = partial(dynamic_dispatch, rcv_ty, rcv) # TODO: use least upper bound? default_v = util.default_value(mtd_callees[0].typ) buf.write(reduce(curried_dispatch, mtd_callees, default_v)) elif mtd_callees and 1 == len(mtd_callees): mtd_callee = mtd_callees[0] buf.write(trans_call(mtd_callee, rcv_ty, rcv)) else: # unresolved, maybe library method mid = trans_mname(rcv_ty, mname, arg_typs) args = util.rm_none([rcv] + map(curried, e.a)) buf.write("{}({})".format(mid, ", ".join(args))) else: # mid mname = e.f.id # pre-defined meta information or Sketch primitive functions if mname in C.typ_arrays + [u"minimize"]: mid = mname rcv = None args = util.rm_none([rcv] + map(curried, e.a)) buf.write("{}({})".format(mid, ", ".join(args))) elif mname == C.J.SUP and mtd.is_init: # super(...) inside <init> sup = class_lookup(mtd.clazz.sup) mid = trans_mname(sup.name, sup.name, arg_typs) rcv = C.SK.self args = util.rm_none([rcv] + map(curried, e.a)) buf.write("{}({})".format(mid, ", ".join(args))) else: # member methods mtd_callees = find_mtds_by_sig(mtd.clazz.name, mname, arg_typs) if mtd_callees and 1 < len(mtd_callees): # needs dynamic dispatch curried_dispatch = partial(dynamic_dispatch, mtd.clazz.name, C.SK.self) # TODO: use least upper bound? default_v = util.default_value(mtd_callees[0].typ) buf.write(reduce(curried_dispatch, mtd_callees, default_v)) elif mtd_callees and 1 == len(mtd_callees): mtd_callee = mtd_callees[0] buf.write(trans_call(mtd_callee, mtd.clazz.name, C.SK.self)) else: # unresolved, maybe library method mid = trans_mname(mtd.clazz.name, mname, arg_typs) args = util.rm_none([rcv] + map(curried, e.a)) buf.write("{}({})".format(mid, ", ".join(args))) elif e.kind == C.E.CAST: # since a family of classes is merged, simply ignore the casting buf.write(curried(e.e)) elif e.kind == C.E.INS_OF: ty = typ_of_e(mtd, e.ty) cls = class_lookup(ty) if cls: buf.write(curried(e.e) + ".__cid == " + str(cls.id)) else: logging.debug("unknown type: {}".format(ty)) buf.write("0") else: buf.write(str(e)) return buf.getvalue()
def trans_e(mtd, e): curried = partial(trans_e, mtd) buf = cStringIO.StringIO() if e.kind == C.E.ANNO: anno = e.anno if anno.name == C.A.NEW: pass # TODO elif anno.name == C.A.OBJ: buf.write("retrieve_{}@log({})".format(util.sanitize_ty(anno.typ), anno.idx)) # @Compare(exps) => {| exps[0] (< | <= | == | != | >= | >) exps[1] |} # @CompareString(exps) => exps[0].eqauls(exps[1]) elif anno.name in [C.A.CMP, C.A.CMP_STR]: le = curried(anno.exps[0]) re = curried(anno.exps[1]) if anno.name == C.A.CMP: buf.write("{| " + le + " (< | <= | == | != | >= | >) " + re + " |}") else: buf.write("{}({},{})".format(trans_mname(C.J.STR, u"equals"), le, re)) elif e.kind == C.E.GEN: if e.es: buf.write("{| ") buf.write(" | ".join(map(curried, e.es))) buf.write(" |}") else: buf.write(C.T.HOLE) elif e.kind == C.E.ID: if hasattr(e, "ty"): buf.write(trans_ty(e.ty) + ' ') fld = None if mtd and e.id not in mtd.param_vars: fld = find_fld(mtd.clazz.name, e.id) if fld: # fname -> self.new_fname (unless the field is static) new_fname = trans_fname(fld.clazz.name, e.id, fld.is_static) if fld.is_static: # access to the static field inside the same class if fld.clazz.name == mtd.clazz.name: buf.write(e.id) # o.w., e.g., static constant in an interface, call the accessor else: buf.write(new_fname + "()") else: buf.write('.'.join([C.SK.self, new_fname])) elif e.id in [C.J.THIS, C.J.SUP]: buf.write(C.SK.self) elif util.is_str(e.id): # constant string, such as "Hello, World" str_init = trans_mname(C.J.STR, C.J.STR, [u"char[]", C.J.i, C.J.i]) s_hash = hash(e.id) % 256 # hash string value itself buf.write("{}(new Object(hash={}), {}, 0, {})".format(str_init, s_hash, e.id, len(e.id))) else: buf.write(e.id) elif e.kind == C.E.UOP: buf.write(' '.join([e.op, curried(e.e)])) elif e.kind == C.E.BOP: buf.write(' '.join([curried(e.le), e.op, curried(e.re)])) elif e.kind == C.E.DOT: # with package names, e.g., javax.swing.SwingUtilities if util.is_class_name(e.re.id) and class_lookup(e.re.id): buf.write(curried(e.re)) elif e.re.id == C.J.THIS: # ClassName.this buf.write(C.SK.self) else: rcv_ty = typ_of_e(mtd, e.le) fld = find_fld(rcv_ty, e.re.id) new_fname = trans_fname(rcv_ty, e.re.id, fld.is_static) if fld.is_static: # access to the static field inside the same class if mtd and rcv_ty == mtd.clazz.name: buf.write(e.re.id) # o.w., e.g., static constant in an interface, call the accessor else: buf.write(new_fname + "()") else: buf.write('.'.join([curried(e.le), new_fname])) elif e.kind == C.E.IDX: buf.write(curried(e.e) + '[' + curried(e.idx) + ']') elif e.kind == C.E.NEW: if e.e.kind == C.E.CALL: ty = typ_of_e(mtd, e.e.f) cls = class_lookup(ty) if cls and cls.has_init: arg_typs = map(partial(typ_of_e, mtd), e.e.a) mname = trans_mname(cls.name, cls.name, arg_typs) obj = "alloc@log({})".format(cls.id) args = [obj] + map(unicode, map(curried, e.e.a)) buf.write("{}({})".format(mname, ", ".join(args))) else: # collection or Object buf.write(C.J.NEW + ' ' + trans_ty(ty) + "()") else: # o.w., array initialization, e.g., new int[] { ... } buf.write(str(e.init)) elif e.kind == C.E.CALL: arg_typs = map(partial(typ_of_e, mtd), e.a) def trans_call(callee, rcv_ty, rcv): if callee.is_static: rcv = None logging = None if not util.is_collection(callee.clazz.name): logging = str(check_logging(mtd, callee)).lower() args = util.rm_none([rcv] + map(curried, e.a) + [logging]) mid = trans_mname(rcv_ty, callee.name, arg_typs) return u"{}({})".format(mid, ", ".join(args)) def dynamic_dispatch(rcv_ty, rcv, acc, callee): _dispatched = trans_call(callee, callee.clazz.name, rcv) _guarded = "{}.__cid == {} ? {}".format(rcv, callee.clazz.id, _dispatched) return "({} : {})".format(_guarded, acc) if e.f.kind == C.E.DOT: # rcv.mid rcv_ty = typ_of_e(mtd, e.f.le) rcv = curried(e.f.le) mname = e.f.re.id mtd_callees = find_mtds_by_sig(rcv_ty, mname, arg_typs) if mtd_callees and 1 < len(mtd_callees): # needs dynamic dispatch curried_dispatch = partial(dynamic_dispatch, rcv_ty, rcv) # TODO: use least upper bound? default_v = util.default_value(mtd_callees[0].typ) buf.write(reduce(curried_dispatch, mtd_callees, default_v)) elif mtd_callees and 1 == len(mtd_callees): mtd_callee = mtd_callees[0] buf.write(trans_call(mtd_callee, rcv_ty, rcv)) else: # unresolved, maybe library method mid = trans_mname(rcv_ty, mname, arg_typs) args = util.rm_none([rcv] + map(curried, e.a)) buf.write("{}({})".format(mid, ", ".join(args))) else: # mid mname = e.f.id # pre-defined meta information or Sketch primitive functions if mname in C.typ_arrays + [u"minimize"]: mid = mname rcv = None args = util.rm_none([rcv] + map(curried, e.a)) buf.write("{}({})".format(mid, ", ".join(args))) elif mname == C.J.SUP and mtd.is_init: # super(...) inside <init> sup = class_lookup(mtd.clazz.sup) mid = trans_mname(sup.name, sup.name, arg_typs) rcv = C.SK.self args = util.rm_none([rcv] + map(curried, e.a)) buf.write("{}({})".format(mid, ", ".join(args))) else: # member methods mtd_callees = find_mtds_by_sig(mtd.clazz.name, mname, arg_typs) if mtd_callees and 1 < len(mtd_callees): # needs dynamic dispatch curried_dispatch = partial(dynamic_dispatch, mtd.clazz.name, C.SK.self) # TODO: use least upper bound? default_v = util.default_value(mtd_callees[0].typ) buf.write(reduce(curried_dispatch, mtd_callees, default_v)) elif mtd_callees and 1 == len(mtd_callees): mtd_callee = mtd_callees[0] buf.write(trans_call(mtd_callee, mtd.clazz.name, C.SK.self)) else: # unresolved, maybe library method mid = trans_mname(mtd.clazz.name, mname, arg_typs) args = util.rm_none([rcv] + map(curried, e.a)) buf.write("{}({})".format(mid, ", ".join(args))) elif e.kind == C.E.CAST: # since a family of classes is merged, simply ignore the casting buf.write(curried(e.e)) elif e.kind == C.E.INS_OF: ty = typ_of_e(mtd, e.ty) cls = class_lookup(ty) if cls: buf.write(curried(e.e) + ".__cid == " + str(cls.id)) else: logging.debug("unknown type: {}".format(ty)) buf.write("0") else: buf.write(str(e)) return buf.getvalue()