def reduce_anno_mtd(smpls, tmpl, cls, mtd): if not mtd.annos: return mname = mtd.name for _anno in mtd.annos: ## ## @Error void mname() ## if _anno.name == C.A.ERR: if not hasattr(cls, "state"): raise ReduceError("no state variable") setattr(cls.state, "error", mtd) state = cls.state.name body = T("${state} = ??;").safe_substitute(locals()) mtd.body = st.to_statements(mtd, body) + mtd.body ## ## @Assemble typ mname(...) ## ## ## @CFG(other_mname) typ mname(...) ## elif _anno.name == C.A.CFG: # find the designated method _, cls_c_name, mtd_c_name = util.explode_mname(_anno.mid) if cls_c_name: mtd_c = class_lookup(cls_c_name).mtd_by_name(mtd_c_name) else: mtd_c = cls.mtd_by_name(mtd_c_name) # and then copy its body if mtd_c: mtd.body = mtd_c[0].body
def add_getter(cls, fld, mname): mtd_g = Method(clazz=cls, mods=fld.mods, typ=fld.typ, name=mname) fname = fld.name body = T("return ${fname};").safe_substitute(locals()) mtd_g.body = st.to_statements(mtd_g, body) cls.mtds.append(mtd_g) # to replace annotation @Get(e) in expressions # or to encode static fields into sketch setattr(fld, "getter", mtd_g)
def mk_harness_pattern(tmpl, cls, smpl): harness = mk_harness(cls, smpl) buf = cStringIO.StringIO() call_stack = [] objs = {} # { @Object(typ, idx): obj_typ_idx, ... } def lkup_obj(v): if type(kind(v)) is unicode: return objs[v] else: return v def to_obj(v): _anno = to_expression(v).anno rep = u"obj_{}_{}".format(_anno.typ, _anno.idx) objs[v] = rep return rep for i, log in enumerate(smpl.logs): if isinstance(log, CallEnt): call_stack.append(log) if len(call_stack) > 1: continue if log.is_init: rcv = to_obj(smpl.logs[i + 1].vals[0]) args = ", ".join(map(lkup_obj, log.vals)) buf.write("{0} {1} = new {0}({2});\n".format( log.cls, rcv, args)) else: # normal call try: args = map(lkup_obj, log.vals) if log.vals and type(kind(log.vals[0])) is unicode: args_mod_rcv = ", ".join(args[1:]) buf.write("{}.{}({});\n".format( args[0], log.mtd, args_mod_rcv)) else: buf.write("{}({});\n".format(log.mtd, ", ".join(args))) except KeyError: continue # means, unknown obj (Evt) occurs elif isinstance(log, CallExt): call_stack.pop() if len(call_stack) > 0: continue else: # Evt buf.write("@React;\n") harness.body = to_statements(harness, unicode(buf.getvalue())) cls.add_mtds([harness])
def mk_harness_pattern(tmpl, cls, smpl): harness = mk_harness(cls, smpl) buf = cStringIO.StringIO() call_stack = [] objs = {} # { @Object(typ, idx): obj_typ_idx, ... } def lkup_obj(v): if type(kind(v)) is unicode: return objs[v] else: return v def to_obj(v): _anno = to_expression(v).anno rep = u"obj_{}_{}".format(_anno.typ, _anno.idx) objs[v] = rep return rep for i, log in enumerate(smpl.logs): if isinstance(log, CallEnt): call_stack.append(log) if len(call_stack) > 1: continue if log.is_init: rcv = to_obj(smpl.logs[i+1].vals[0]) args = ", ".join(map(lkup_obj, log.vals)) buf.write("{0} {1} = new {0}({2});\n".format(log.cls, rcv, args)) else: # normal call try: args = map(lkup_obj, log.vals) if log.vals and type(kind(log.vals[0])) is unicode: args_mod_rcv = ", ".join(args[1:]) buf.write("{}.{}({});\n".format(args[0], log.mtd, args_mod_rcv)) else: buf.write("{}({});\n".format(log.mtd, ", ".join(args))) except KeyError: continue # means, unknown obj (Evt) occurs elif isinstance(log, CallExt): call_stack.pop() if len(call_stack) > 0: continue else: # Evt buf.write("@React;\n") harness.body = to_statements(harness, unicode(buf.getvalue())) cls.add_mtds([harness])
def mk_harness_gui(tmpl, cls, smpl): harness = mk_harness(cls, smpl) buf = cStringIO.StringIO() # initialize Toolkit/EventQueue buf.write("{0} t = {0}.{1}{0}();\n".format(C.GUI.TOOL, "getDefault")) buf.write("{0} q = t.{1}{0}();\n".format(C.GUI.QUE, "getSystem")) # run main() in the client main_cls = tmpl.main # TODO: passing proper parameters buf.write("{}.{}();\n".format(main_cls.clazz.name, main_cls.name)) buf.write("@React;\n") # to handle InvokeEvent # post events in the sample to Toolkit's EventQueue post = u"q.postEvent" evts = smpl.evts ev_name = C.GUI.EVT logging.debug("# event(s) in {}: {}".format(smpl.name, len(evts))) for i, evt in enumerate(evts): e_i = "e{}".format(i) init = str(evt) buf.write(""" {ev_name} {e_i} = new {init}; """.format(**locals())) e_kind = tmpl.get_event_id(evt.kind) buf.write(""" {e_i}.kind = {e_kind}; {post}({e_i}); @React; """.format(**locals())) harness.body = to_statements(harness, unicode(buf.getvalue())) cls.add_mtds([harness])
def mk_harness_android(tmpl, cls, smpl): harness = mk_harness(cls, smpl) buf = cStringIO.StringIO() # TODO: launch resource managers # TODO: post an Intent for AUT to ActivityManager # XXX: rather, start and post the Intent to the global Context directly main_cls = tmpl.main # SystemServer.main # TODO: passing proper parameters buf.write("{}.{}();\n".format(main_cls.clazz.name, main_cls.name)) # global variables, sort of singletons buf.write(""" {0} l = {0}.getMain{0}(); {1} q = l.myQueue(); {2} t = {2}.current{2}(); // global Context """.format(C.ADR.LOOP, C.ADR.QUE, C.ADR.ACTT)) # generate an Intent to trigger the main Activity # TODO: how to figure out the *main* Activity? # XXX: assume there is only one Activity acts = tmpl.find_cls_kind(C.ADR.ACT) if not acts: raise Exception("no Activity at all?") elif len(acts) > 1: raise Exception("no idea what to start among multiple Activity's", acts) main_act = acts[0] buf.write(""" {0} c = new {0}(\"{1}\", \"{2}\"); {3} i = new {3}(c); """.format(C.ADR.CMP, "DONT_CARE_PKG_NAME", main_act.name, C.ADR.INTT)) post = u"q.enqueue{}".format(C.ADR.MSG) # TODO: use ActivityManager's Handler # XXX: use the main UI thread's Handler buf.write(""" {0} h = t.get{0}(); {1} m = new {1}(h); m.obj = i; m.what = -1; // Intent {2}(m, 0); @React; """.format(C.ADR.HDL, C.ADR.MSG, post)) # additional global variable(s) buf.write(""" {0} a = t.get{0}(); """.format(C.ADR.ACT)) cls_ievt = class_lookup(u"InputEvent") # post events in the sample to the main Looper's MessageQueue evts = smpl.evts _hdl = C.ADR.HDL _msg = C.ADR.MSG logging.debug("# event(s) in {}: {}".format(smpl.name, len(evts))) for i, evt in enumerate(evts): cls_evt = class_lookup(evt.kind) if not cls_evt: logging.debug("undeclared event sort: {}".format(evt.kind)) continue e_i = "e{}".format(i) init = str(evt) buf.write(""" {evt.kind} {e_i} = new {init}; """.format(**locals())) # generate a message by wrapping the event h_i = "h{}".format(i) if cls_evt <= cls_ievt: # InputEvent, KeyEvent, MotionEvent # TODO: use Window(Manager)'s Handler # XXX: use the source View's Handler at the moment s_i = "s{}".format(i) v_i = "v{}".format(i) buf.write(""" int {s_i} = {e_i}.getSource(); View {v_i} = a.findViewById({s_i}); {_hdl} {h_i} = {v_i}.get{_hdl}(); """.format(**locals())) else: # TODO: how to retrieve an appropriate Handler in general? buf.write(""" {_hdl} {h_i} = ...; """.format(**locals())) m_i = "m{}".format(i) e_kind = tmpl.get_event_id(evt.kind) buf.write(""" {_msg} {m_i} = new {_msg}({h_i}); {m_i}.obj = {e_i}; {m_i}.what = {e_kind}; """.format(**locals())) # post that message (to the main Looper's MessageQueue) buf.write(""" {post}({m_i}, 0); @React; """.format(**locals())) harness.body = to_statements(harness, unicode(buf.getvalue())) cls.add_mtds([harness])
def reduce_anno_e(tmpl, cls, mtd, e, pe=None): curried = partial(reduce_anno_e, tmpl, cls, mtd) if e.kind == C.E.ANNO: _anno = e.anno ## ## Getters ## if _anno.name in [C.A.STATE, C.A.GET]: args = [] if _anno.name == C.A.STATE: # @State(this) -> this.getter() if _anno.accessed == C.J.THIS: mtd_g = cls.state.getter f = st.gen_E_id(mtd_g.name) # @State(var) -> var.getter() else: var = _anno.accessed tname = mtd.vars[var] mtd_g = class_lookup(tname).state.getter f = st.gen_E_dot(st.gen_E_id(var), st.gen_E_id(mtd_g.name)) # @Get(var.fname, args?) -> var.getFname(args?) elif _anno.name == C.A.GET: var, fname = _anno.fid.split('.') tname = mtd.vars[var] mtd_g = class_lookup(tname).fld_by_name(fname).getter f = st.gen_E_dot(st.gen_E_id(var), st.gen_E_id(mtd_g.name)) if hasattr(_anno, "args"): args = _anno.args return st.gen_E_call(f, args) ## ## Setter ## # @Update(var) -> var.setter(??) elif _anno.name == C.A.UPDATE: var, fname = _anno.fid.split('.') tname = mtd.vars[var] mtd_s = class_lookup(tname).fld_by_name(fname).setter f = st.gen_E_dot(st.gen_E_id(var), st.gen_E_id(mtd_s.name)) return st.gen_E_call(f, [st.gen_E_hole()]) ## ## Generator ## elif _anno.name in [C.A.ALL, C.A.TAG]: if _anno.name == C.A.ALL: tag_g = u"gen_all" else: tag_g = u"gen_" + _anno.tag # assume tag name is unique # (var.)? @anno if not pe: cls_g = cls else: cls_g = class_lookup(mtd.vars[unicode(pe.le)]) if hasattr(cls_g, tag_g): mtd_g = getattr(cls_g, tag_g) else: # introduce generator if _anno.name == C.A.ALL: mtds = cls_g.mtds else: # C.A.TAG find_tag = partial(anno.by_attr, {"tag": _anno.tag}) mtds = cls_g.mtds_w_anno(find_tag) mtd_g = Method(clazz=cls_g, mods=[C.mod.GN], name=tag_g) body = "int t = ??;\n" for i, mtd in enumerate(mtds): mid = mtd.name case = T("if (t == ${i}) { ${mid}(); }\n").safe_substitute( locals()) body = body + case body = body + "assert t <= {};".format(len(mtds)) mtd_g.body = st.to_statements(mtd_g, body) cls_g.mtds.append(mtd_g) setattr(cls_g, tag_g, mtd_g) # @Tag("tag") | @All -> gen_tag | gen_all return st.gen_E_id(mtd_g.name) ## ## Reflection ## # @New should be handled differently # e.g., for "ClassName".@New({ args }) # Sketch: new ClassName(args); # Java: (ClassName)(Class.forName("ClassName").newInstance(args)); elif _anno.name == C.A.NEW: pass ## ## Comparator ## # @Compare will be encoded into a regex generator in Sketch # and then will be replaced with a proper operator in Java elif _anno.name in [C.A.CMP, C.A.CMP_STR]: pass ## ## Observers ## # event sending elif _anno.name == C.A.EVENT: pass # TODO # a list that maintains the registered observers elif _anno.name == C.A.OBSS: if not hasattr(cls, "obs"): cls_o_name, _ = find_observer_at_cls(tmpl, cls) add_obs(cls, cls_o_name) return st.gen_E_id(cls.obs.name) # invoke the @Notified method elif _anno.name == C.A.NOTI: mtd_noti = find_noti(tmpl, cls) rcv = _anno.args[0] call_noti = st.gen_E_dot(rcv, st.gen_E_id(mtd_noti.name)) return st.gen_E_call(call_noti, _anno.args[1:]) elif e.kind in [C.E.BOP, C.E.DOT]: e.le = curried(e.le, e) e.re = curried(e.re, e) elif e.kind == C.E.NEW: e.e = curried(e.e) elif e.kind == C.E.CALL: e.f = curried(e.f) map(curried, e.a) return e
def reduce_anno_fld(smpls, tmpl, cls, fld): if not fld.annos: return cname = cls.name fname = fld.name Fname = util.cap_1st_only(fname) for _anno in fld.annos: ## ## @State(@Tag(...) | @All) int _state ## if _anno.name == C.A.STATE: setattr(cls, "state", fld) # find all the methods involved in this state variable where = _anno.accessed if where.name == C.A.ALL: mtds = cls.mtds[:] # quick copy, since mtds will be modified below elif where.name == C.A.TAG: find_tag = partial(anno.by_attr, {"tag": where.tag}) mtds = cls.mtds_w_anno(find_tag) else: mtds = cls.mtd_by_name(where) # exclude setter to avoid a recursive call if hasattr(fld, "setter"): mtds.remove(fld.setter) # exclude error, if exists, to avoid redundant state update find_err = partial(anno.by_name, C.A.ERR) errs = cls.mtds_w_anno(find_err) if errs: if len(errs) > 1: raise ReduceError("ambiguous error state") err = errs[0] mtds.remove(err) # then add a statement to update this state variable into those methods for mtd in mtds: # TODO: currently, @Set should be reduced before @State if hasattr(fld, "setter"): # use setter if exists f_setter = fld.setter.name upd = "${f_setter}(??);" else: upd = "${fname} = ??;" if errs and err: e_name = err.name trans = "if (??) { " + upd + " } else { ${e_name}(); }" else: trans = upd body_tmpl = "repeat(??) { if (${fname} == ??) { " + trans + " } }" body = T(body_tmpl).safe_substitute(locals()) mtd.body = st.to_statements(mtd, body) + mtd.body # introduce getter to replace @State in expressions later name = "get" + Fname mtd_g = Method(clazz=cls, typ=fld.typ, name=name) body = T("return ${fname};").safe_substitute(locals()) mtd_g.body = st.to_statements(mtd, body) cls.mtds.append(mtd_g) setattr(fld, "getter", mtd_g) ## ## @Multiton({typ_v, ...})? Map<key,value> fname ## elif _anno.name == C.A.MULTI: # assume fld.typ is Map<key,value> m, key, value = util.extract_generics(fld.typ) if hasattr(_anno, "values"): values = _anno.values elif C.J.MAP in fld.typ: values = [value] # add a getter mname = sample.find_getter(smpls, values, Fname) params = [(key, u"key")] mtd_g = Method(clazz=cls, typ=value, name=mname, params=params) cls.mtds.append(mtd_g) # usage 1: Map<String,Object> systemService if len(values) > 1: pass # TODO: collect key-value mappings occurred at the samples # TODO: then add code to initialize those mappings into the constructor # usage 2: Map<int,View> viewById else: # i.e. values = [value] body = T(""" boolean chk = ${fname}.containsKey(key); if (chk != true) { ${fname}.put(key, new ${value}(key)); } return ${fname}.get(key); """).safe_substitute(locals()) mtd_g.body = st.to_statements(mtd_g, body) setattr(fld, "getter", mtd_g) # initialize this field cname = cls.name init = cls.mtd_by_sig(cname) if not init: init = cls.add_default_init() fld_typ = fld.typ body = T("${fname} = new ${fld_typ}();").safe_substitute(locals()) init.body.extend(st.to_statements(init, body)) ## ## @Get typ fname ## @Is typ fname ## elif _anno.name in [C.A.GET, C.A.IS]: # special case: Map<String, Object> _elements; if C.J.MAP in fld.typ: pass # TODO: collect get$T$ occurrences, where $T$ is any types # TODO: then add all those getters which look like below: # TODO: $T$ get$T$(String key) { return _elements.get(k); } ## ## @Has typ fname ## elif _anno.name == C.A.HAS: # add a checker, along with a boolean field, say "_setFname" name = "_set" + Fname fld_h = Field(clazz=cls, typ=C.J.z, name=name) cls.flds.append(fld_h) mname = sample.find_getter(smpls, [C.J.z], Fname, "has") mtd_h = Method(clazz=cls, typ=C.J.z, name=mname) body = T("return ${name};").safe_substitute(locals()) mtd_h.body = st.to_statements(mtd_h, body) # find the setter and add a statement: _setFname := true if hasattr(fld, "setter"): mtd_s = fld.setter body = T("${name} = true;").safe_substitute(locals()) mtd_s.body.extend(st.to_statements(mtd_s, body)) ## ## @Put(typ_b) typ fname ## elif _anno.name == C.A.PUT: # special case: Map<String, Object> _elements; if C.J.MAP in fld.typ: pass # TODO: collect put$T$ occurrences, where $T$ is any types # TODO: then add all those putters which look like below: # TODO: void put$T$(String k, $T$ v) { _elements.put(k, v); } else: pass
def reduce_anno_fld(smpls, tmpl, cls, fld): if not fld.annos: return cname = cls.name fname = fld.name Fname = util.cap_1st_only(fname) for _anno in fld.annos: ## ## @State(@Tag(...) | @All) int _state ## if _anno.name == C.A.STATE: setattr(cls, "state", fld) # find all the methods involved in this state variable where = _anno.accessed if where.name == C.A.ALL: mtds = cls.mtds[:] # quick copy, since mtds will be modified below elif where.name == C.A.TAG: find_tag = partial(anno.by_attr, {"tag": where.tag}) mtds = cls.mtds_w_anno(find_tag) else: mtds = cls.mtd_by_name(where) # exclude setter to avoid a recursive call if hasattr(fld, "setter"): mtds.remove(fld.setter) # exclude error, if exists, to avoid redundant state update find_err = partial(anno.by_name, C.A.ERR) errs = cls.mtds_w_anno(find_err) if errs: if len(errs) > 1: raise ReduceError("ambiguous error state") err = errs[0] mtds.remove(err) # then add a statement to update this state variable into those methods for mtd in mtds: # TODO: currently, @Set should be reduced before @State if hasattr(fld, "setter"): # use setter if exists f_setter = fld.setter.name upd = "${f_setter}(??);" else: upd = "${fname} = ??;" if errs and err: e_name = err.name trans = "if (??) { " + upd + " } else { ${e_name}(); }" else: trans = upd body_tmpl = "repeat(??) { if (${fname} == ??) { " + trans + " } }" body = T(body_tmpl).safe_substitute(locals()) mtd.body = st.to_statements(mtd, body) + mtd.body # introduce getter to replace @State in expressions later name = "get" + Fname mtd_g = Method(clazz=cls, typ=fld.typ, name=name) body = T("return ${fname};").safe_substitute(locals()) mtd_g.body = st.to_statements(mtd, body) cls.mtds.append(mtd_g) setattr(fld, "getter", mtd_g) ## ## @Multiton({typ_v, ...})? Map<key,value> fname ## elif _anno.name == C.A.MULTI: # assume fld.typ is Map<key,value> m, key, value = util.extract_generics(fld.typ) if hasattr(_anno, "values"): values = _anno.values elif C.J.MAP in fld.typ: values = [value] # add a getter mname = sample.find_getter(smpls, values, Fname) params = [ (key, u"key") ] mtd_g = Method(clazz=cls, typ=value, name=mname, params=params) cls.mtds.append(mtd_g) # usage 1: Map<String,Object> systemService if len(values) > 1: pass # TODO: collect key-value mappings occurred at the samples # TODO: then add code to initialize those mappings into the constructor # usage 2: Map<int,View> viewById else: # i.e. values = [value] body = T(""" boolean chk = ${fname}.containsKey(key); if (chk != true) { ${fname}.put(key, new ${value}(key)); } return ${fname}.get(key); """).safe_substitute(locals()) mtd_g.body = st.to_statements(mtd_g, body) setattr(fld, "getter", mtd_g) # initialize this field cname = cls.name init = cls.mtd_by_sig(cname) if not init: init = cls.add_default_init() fld_typ = fld.typ body = T("${fname} = new ${fld_typ}();").safe_substitute(locals()) init.body.extend(st.to_statements(init, body)) ## ## @Get typ fname ## @Is typ fname ## elif _anno.name in [C.A.GET, C.A.IS]: # special case: Map<String, Object> _elements; if C.J.MAP in fld.typ: pass # TODO: collect get$T$ occurrences, where $T$ is any types # TODO: then add all those getters which look like below: # TODO: $T$ get$T$(String key) { return _elements.get(k); } ## ## @Has typ fname ## elif _anno.name == C.A.HAS: # add a checker, along with a boolean field, say "_setFname" name = "_set" + Fname fld_h = Field(clazz=cls, typ=C.J.z, name=name) cls.flds.append(fld_h) mname = sample.find_getter(smpls, [C.J.z], Fname, "has") mtd_h = Method(clazz=cls, typ=C.J.z, name=mname) body = T("return ${name};").safe_substitute(locals()) mtd_h.body = st.to_statements(mtd_h, body) # find the setter and add a statement: _setFname := true if hasattr(fld, "setter"): mtd_s = fld.setter body = T("${name} = true;").safe_substitute(locals()) mtd_s.body.extend(st.to_statements(mtd_s, body)) ## ## @Put(typ_b) typ fname ## elif _anno.name == C.A.PUT: # special case: Map<String, Object> _elements; if C.J.MAP in fld.typ: pass # TODO: collect put$T$ occurrences, where $T$ is any types # TODO: then add all those putters which look like below: # TODO: void put$T$(String k, $T$ v) { _elements.put(k, v); } else: pass
def reduce_anno_e(tmpl, cls, mtd, e, pe=None): curried = partial(reduce_anno_e, tmpl, cls, mtd) if e.kind == C.E.ANNO: _anno = e.anno ## ## Getters ## if _anno.name in [C.A.STATE, C.A.GET]: args = [] if _anno.name == C.A.STATE: # @State(this) -> this.getter() if _anno.accessed == C.J.THIS: mtd_g = cls.state.getter f = st.gen_E_id(mtd_g.name) # @State(var) -> var.getter() else: var = _anno.accessed tname = mtd.vars[var] mtd_g = class_lookup(tname).state.getter f = st.gen_E_dot(st.gen_E_id(var), st.gen_E_id(mtd_g.name)) # @Get(var.fname, args?) -> var.getFname(args?) elif _anno.name == C.A.GET: var, fname = _anno.fid.split('.') tname = mtd.vars[var] mtd_g = class_lookup(tname).fld_by_name(fname).getter f = st.gen_E_dot(st.gen_E_id(var), st.gen_E_id(mtd_g.name)) if hasattr(_anno, "args"): args = _anno.args return st.gen_E_call(f, args) ## ## Setter ## # @Update(var) -> var.setter(??) elif _anno.name == C.A.UPDATE: var, fname = _anno.fid.split('.') tname = mtd.vars[var] mtd_s = class_lookup(tname).fld_by_name(fname).setter f = st.gen_E_dot(st.gen_E_id(var), st.gen_E_id(mtd_s.name)) return st.gen_E_call(f, [st.gen_E_hole()]) ## ## Generator ## elif _anno.name in [C.A.ALL, C.A.TAG]: if _anno.name == C.A.ALL: tag_g = u"gen_all" else: tag_g = u"gen_" + _anno.tag # assume tag name is unique # (var.)? @anno if not pe: cls_g = cls else: cls_g = class_lookup(mtd.vars[unicode(pe.le)]) if hasattr(cls_g, tag_g): mtd_g = getattr(cls_g, tag_g) else: # introduce generator if _anno.name == C.A.ALL: mtds = cls_g.mtds else: # C.A.TAG find_tag = partial(anno.by_attr, {"tag": _anno.tag}) mtds = cls_g.mtds_w_anno(find_tag) mtd_g = Method(clazz=cls_g, mods=[C.mod.GN], name=tag_g) body = "int t = ??;\n" for i, mtd in enumerate(mtds): mid = mtd.name case = T("if (t == ${i}) { ${mid}(); }\n").safe_substitute(locals()) body = body + case body = body + "assert t <= {};".format(len(mtds)) mtd_g.body = st.to_statements(mtd_g, body) cls_g.mtds.append(mtd_g) setattr(cls_g, tag_g, mtd_g) # @Tag("tag") | @All -> gen_tag | gen_all return st.gen_E_id(mtd_g.name) ## ## Reflection ## # @New should be handled differently # e.g., for "ClassName".@New({ args }) # Sketch: new ClassName(args); # Java: (ClassName)(Class.forName("ClassName").newInstance(args)); elif _anno.name == C.A.NEW: pass ## ## Comparator ## # @Compare will be encoded into a regex generator in Sketch # and then will be replaced with a proper operator in Java elif _anno.name in [C.A.CMP, C.A.CMP_STR]: pass ## ## Observers ## # event sending elif _anno.name == C.A.EVENT: pass # TODO # a list that maintains the registered observers elif _anno.name == C.A.OBSS: if not hasattr(cls, "obs"): cls_o_name, _ = find_observer_at_cls(tmpl, cls) add_obs(cls, cls_o_name) return st.gen_E_id(cls.obs.name) # invoke the @Notified method elif _anno.name == C.A.NOTI: mtd_noti = find_noti(tmpl, cls) rcv = _anno.args[0] call_noti = st.gen_E_dot(rcv, st.gen_E_id(mtd_noti.name)) return st.gen_E_call(call_noti, _anno.args[1:]) elif e.kind in [C.E.BOP, C.E.DOT]: e.le = curried(e.le, e) e.re = curried(e.re, e) elif e.kind == C.E.NEW: e.e = curried(e.e) elif e.kind == C.E.CALL: e.f = curried(e.f) map(curried, e.a) return e