def trans_ty(tname): _tname = util.sanitize_ty(tname.strip()) array_regex = r"([^ \[\]]+)((\[\])+)" m = re.match(array_regex, _tname) global _ty r_ty = _tname # to avoid primitive types that Sketch doesn't support if _tname == C.J.z: r_ty = C.SK.z elif _tname in [C.J.b, C.J.s, C.J.j]: r_ty = C.J.i # unboxing primitive Classes, e.g., Character -> char elif _tname in C.autoboxing: r_ty = util.unboxing(_tname) # TODO: parameterize len? elif _tname in [C.J.c+"[]"]: r_ty = u"{}[51]".format(C.J.c) elif _tname in [C.J.B, C.J.S, C.J.J, C.J.I]: r_ty = C.J.i # array bounds elif m: r_ty = trans_ty(m.group(1)) + \ "[{}]".format(len(methods())) * len(re.findall(r"\[\]", m.group(2))) # use memoized type conversion elif _tname in _ty: r_ty = _ty[_tname] # convert Java collections into an appropriate struct name # Map<K,V> / List<T> / ... -> Map_K_V / List_T / ... elif util.is_collection(_tname): r_ty = '_'.join(util.of_collection(_tname)) logging.debug("{} => {}".format(_tname, r_ty)) _ty[_tname] = r_ty return r_ty
def __call__(self, environ, start_response): try: # create http request request = HttpRequest(environ) (re_url, url, func_callback) = self.__find_mapped_func(request) resp_mimetype = func_callback.produces if "application/json" == resp_mimetype.lower(): response = HttpJSonResponse(output = {}, content_type = resp_mimetype) else: response = HttpResponse(content_type = resp_mimetype) opt_func_out = func_callback(request, response) # call the web-mapped-function # developer can directly manipulate the response, or return objects|string as ouput if opt_func_out is not None and opt_func_out: if isinstance(opt_func_out, basestring): response.set_output_body( str(opt_func_out) ) elif util.is_collection(opt_func_out): # is collection response.set_output_body( util.to_json(str(opt_func_out)) ) return response.send(start_response) except (KeyboardInterrupt, SystemExit, MemoryError): raise InternalServerError("Request failed due to an Internal Server Error.") except Exception, e: return self.__handle_error(e, (environ, start_response))
def trans_init(cls_name, arg_typs, args): buf = cStringIO.StringIO() cls = class_lookup(cls_name) if util.is_collection(cls_name) or not cls: buf.write(trans_ty(cls_name) + "()") elif is_replaced(cls_name): buf.write(trans_ty(cls_name) + "(hash=nonce())") else: add_on = [] if args: # NOTE: assume the order of arguments is same as that of fields # NOTE: for missing fields, just call default constructors # TODO: use template.sig_match kwargs = zip(cls.flds, args) if kwargs: assigned, _ = zip(*kwargs) else: assigned = [] not_assigned = [fld for fld in cls.flds if fld not in assigned] if not_assigned: def default_init(fld): if util.is_class_name(fld.typ): return C.J.NEW + ' ' + trans_init(fld.typ, [], []) else: return '0' add_on = map(default_init, not_assigned) # else: # means, default constructor flds = ["hash"] + map(op.attrgetter("name"), cls.flds) vals = ["nonce()"] + args + add_on kwargs = map(lambda (f, v): "{}={}".format(f, v), zip(flds, vals)) buf.write('_'.join([cls_name] + arg_typs)) buf.write('(' + ", ".join(kwargs) + ')') return buf.getvalue()
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_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 gen_log_sk(sk_dir, pgr): buf = cStringIO.StringIO() buf.write("package log;\n") buf.write(_const) buf.write(""" // distinct hash values for runtime objects int obj_cnt = 0; int nonce () { return obj_cnt++; } """) # factory of Object buf.write(""" // factory of Object Object alloc(int ty) {{ Object {0} = new Object(hash=nonce(), __cid=ty); return {0}; }} """.format(C.SK.self)) global _ty; _clss = [] for ty in _ty.keys(): if util.is_collection(ty): continue if util.is_array(ty): continue cls = class_lookup(ty) if not cls: continue # to avoid None definition # inner class may appear twice: w/ and w/o outer class name if cls not in _clss: _clss.append(cls) buf.write("\n// distinct class IDs\n") for cls in _clss: buf.write("int {cls!r} () {{ return {cls.id}; }}\n".format(**locals())) buf.write("\n// distinct method IDs\n") for cls in pgr.classes: mtds = collect_decls(cls, "mtds") if not mtds: continue for mtd in mtds: mname = sanitize_mname(unicode(repr(mtd))) buf.write(""" int {mname}_ent () {{ return {mtd.id}; }} int {mname}_ext () {{ return -{mtd.id}; }} """.format(**locals())) with open(os.path.join(sk_dir, "log.sk"), 'w') as f: f.write(buf.getvalue()) logging.info("encoding " + f.name) buf.close()
def rm_subs(clss): # { cname: Clazz(cname, ...), ... } decls = { cls.name: cls for cls in clss } # remove subclasses for cname in decls.keys(): if util.is_collection(cname): continue cls = class_lookup(cname) if not cls.is_class: continue for sub in cls.subs: if sub.name in decls: logging.debug("{} < {}".format(sub.name, cname)) del decls[sub.name] for sup in util.ffilter([cls.sup]): if sup in decls and cname in decls: logging.debug("{} < {}".format(cname, sup)) del decls[cname] return decls.values()
def rm_subs(clss): # { cname: Clazz(cname, ...), ... } decls = { cls.name: cls for cls in clss } # remove subclasses for cname in decls.keys(): if util.is_collection(cname): continue cls = class_lookup(cname) if not cls.is_class: continue if cls.is_aux: continue # virtual relations; don't remove sub classes for sub in cls.subs: if sub.name in decls: logging.debug("{} < {}".format(sub.name, cname)) del decls[sub.name] for sup in util.ffilter([cls.sup]): if sup in decls and cname in decls: logging.debug("{} < {}".format(cname, sup)) del decls[cname] return decls.values()
def gen_type_sk(sk_dir, bases): buf = cStringIO.StringIO() buf.write("package type;\n") buf.write(_const) cols, decls = util.partition(lambda c: util.is_collection(c.name), bases) decls = filter(lambda c: not util.is_array(c.name), decls) itfs, clss = util.partition(op.attrgetter("is_itf"), decls) logging.debug("# interface(s): {}".format(len(itfs))) logging.debug("# class(es): {}".format(len(clss))) # convert interfaces first, then usual classes buf.write('\n'.join(util.ffilter(map(to_struct, itfs)))) buf.write('\n'.join(util.ffilter(map(to_struct, clss)))) # convert collections at last logging.debug("# collection(s): {}".format(len(cols))) buf.write('\n'.join(map(col_to_struct, cols))) # argument number of methods arg_num = map(lambda mtd: len(mtd.params), methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id) {{ return _{0}[id]; }} """.format(C.typ.argNum, ", ".join(map(str, arg_num)))) # argument types of methods def get_args_typ(mtd): def get_arg_typ(param): return str(class_lookup(param[0]).id) return '{' + ", ".join(map(get_arg_typ, mtd.params)) + '}' args_typ = map(get_args_typ, methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id, int idx) {{ return _{0}[id][idx]; }} """.format(C.typ.argType, ", ".join(args_typ))) # return type of methods def get_ret_typ(mtd): cls = class_lookup(mtd.typ) if cls: return cls.id else: return -1 ret_typ = map(get_ret_typ, methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id) {{ return _{0}[id]; }} """.format(C.typ.retType, ", ".join(map(str, ret_typ)))) # belonging class of methods belongs = map(lambda mtd: mtd.clazz.id, methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id) {{ return _{0}[id]; }} """.format(C.typ.belongsTo, ", ".join(map(str, belongs)))) subcls = \ map(lambda cls_i: '{' + ", ".join( \ map(lambda cls_j: str(cls_i <= cls_j).lower(), classes()) \ ) + '}', classes()) buf.write(""" #define _{0} {{ {1} }} bit {0}(int i, int j) {{ return _{0}[i][j]; }} """.format(C.typ.subcls, ", ".join(subcls))) ## sub type relations #subcls = [] #for cls_i in classes(): # row = [] # for cls_j in classes(): # row.append(int(cls_i <= cls_j)) # subcls.append(row) ## sub type relations in yale format #_, IA, JA = util.yale_format(subcls) #li, lj = len(IA), len(JA) #si = ", ".join(map(str, IA)) #sj = ", ".join(map(str, JA)) #buf.write(""" # #define _iA {{ {si} }} # #define _jA {{ {sj} }} # int iA(int i) {{ # return _iA[i]; # }} # int jA(int j) {{ # return _jA[j]; # }} # bit subcls(int i, int j) {{ # int col_i = iA(i); # int col_j = iA(i+1); # for (int col = col_i; col < col_j; col++) {{ # if (j == jA(col)) return true; # }} # return false; # }} #""".format(**locals())) with open(os.path.join(sk_dir, "type.sk"), 'w') as f: f.write(buf.getvalue()) logging.info("encoding " + f.name) buf.close()
def trans_s(mtd, s): curried_e = partial(trans_e, mtd) curried_s = partial(trans_s, mtd) buf = cStringIO.StringIO() if s.kind == C.S.IF: e = curried_e(s.e) t = '\n'.join(map(curried_s, s.t)) f = '\n'.join(map(curried_s, s.f)) buf.write("if (" + e + ") {\n" + t + "\n}") if f: buf.write("\nelse {\n" + f + "\n}") elif s.kind == C.S.WHILE: e = curried_e(s.e) b = '\n'.join(map(curried_s, s.b)) buf.write("while (" + e + ") {\n" + b + "\n}") elif s.kind == C.S.REPEAT: e = curried_e(s.e) b = '\n'.join(map(curried_s, s.b)) if e == "??": buf.write("minrepeat {\n" + b + "\n}") else: buf.write("repeat (" + e + ") {\n" + b + "\n}") elif s.kind == C.S.MINREPEAT: b = '\n'.join(map(curried_s, s.b)) buf.write("minrepeat {\n" + b + "\n}") elif s.kind == C.S.FOR: # assume "for" is used for List<T> and LinkedList<T> only col = mtd.vars[s.init.id] if not util.is_collection(col) or \ util.of_collection(col)[0] not in [C.J.LST, C.J.LNK]: raise Exception("not iterable type", col) # if this is about observers, let sketch choose iteration direction is_obs = hasattr(class_lookup(util.of_collection(col)[1]), "obs") s_init = curried_e(s.init) if is_obs: init = "{{| 0 | {}.idx - 1 |}}".format(s_init) else: init = '0' buf.write(" int idx = {};".format(init)) s_i_typ = trans_ty(s.i.ty) buf.write(""" while (0 <= idx && idx < S && {s_init}.elts[idx] != null) {{ {s_i_typ} {s.i.id} = {s_init}.elts[idx]; """.format(**locals())) buf.write('\n'.join(map(curried_s, s.b))) if is_obs: upd = "{| idx (+ | -) 1 |}" else: upd = "idx + 1" buf.write(""" idx = {}; }} """.format(upd)) elif s.kind == C.S.TRY: # NOTE: no idea how to handle catch blocks # at this point, just walk through try/finally blocks buf.write('\n'.join(map(curried_s, s.b + s.fs))) else: buf.write(s.__str__(curried_e)) return buf.getvalue()
def gen_type_sk(sk_dir, bases): buf = cStringIO.StringIO() buf.write("package type;\n") buf.write(_const) buf.write(trans_lib()) buf.write('\n') cols, decls = util.partition(lambda c: util.is_collection(c.name), bases) decls = filter(lambda c: not util.is_array(c.name), decls) itfs, clss = util.partition(op.attrgetter("is_itf"), decls) logging.debug("# interface(s): {}".format(len(itfs))) logging.debug("# class(es): {}".format(len(clss))) # convert interfaces first, then usual classes buf.write('\n'.join(util.ffilter(map(to_struct, itfs)))) buf.write('\n'.join(util.ffilter(map(to_struct, clss)))) # convert collections at last logging.debug("# collection(s): {}".format(len(cols))) buf.write('\n'.join(map(col_to_struct, cols))) # argument number of methods arg_num = map(lambda mtd: len(mtd.params), methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id) {{ return _{0}[id]; }} """.format(C.typ.argNum, ", ".join(map(str, arg_num)))) # argument types of methods def get_args_typ(mtd): def get_arg_typ(param): return str(class_lookup(param[0]).id) return '{' + ", ".join(map(get_arg_typ, mtd.params)) + '}' args_typ = map(get_args_typ, methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id, int idx) {{ return _{0}[id][idx]; }} """.format(C.typ.argType, ", ".join(args_typ))) # return type of methods def get_ret_typ(mtd): cls = class_lookup(mtd.typ) if cls: return cls.id else: return -1 ret_typ = map(get_ret_typ, methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id) {{ return _{0}[id]; }} """.format(C.typ.retType, ", ".join(map(str, ret_typ)))) # belonging class of methods belongs = map(lambda mtd: mtd.clazz.id, methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id) {{ return _{0}[id]; }} """.format(C.typ.belongsTo, ", ".join(map(str, belongs)))) subcls = \ map(lambda cls_i: '{' + ", ".join( \ map(lambda cls_j: str(cls_i <= cls_j).lower(), classes()) \ ) + '}', classes()) buf.write(""" #define _{0} {{ {1} }} bit {0}(int i, int j) {{ return _{0}[i][j]; }} """.format(C.typ.subcls, ", ".join(subcls))) ## sub type relations #subcls = [] #for cls_i in classes(): # row = [] # for cls_j in classes(): # row.append(int(cls_i <= cls_j)) # subcls.append(row) ## sub type relations in yale format #_, IA, JA = util.yale_format(subcls) #li, lj = len(IA), len(JA) #si = ", ".join(map(str, IA)) #sj = ", ".join(map(str, JA)) #buf.write(""" # #define _iA {{ {si} }} # #define _jA {{ {sj} }} # int iA(int i) {{ # return _iA[i]; # }} # int jA(int j) {{ # return _jA[j]; # }} # bit subcls(int i, int j) {{ # int col_i = iA(i); # int col_j = iA(i+1); # for (int col = col_i; col < col_j; col++) {{ # if (j == jA(col)) return true; # }} # return false; # }} #""".format(**locals())) with open(os.path.join(sk_dir, "type.sk"), 'w') as f: f.write(buf.getvalue()) logging.info("encoding " + f.name) buf.close()
def gen_log_sk(sk_dir, tmpl): buf = cStringIO.StringIO() buf.write("package log;\n") buf.write(_const) global max_objs buf.write("int O = {}; // # of objects\n".format(max_objs + 1)) buf.write(""" int log_cnt = 0; int[P][N] ev; int[O] obj; // to enforce the length of logs int get_log_cnt() { return log_cnt; } // after writing logs, reset the cursor in order to check logs in order void reset_log_cnt() { log_cnt = 0; } // to clean up the logs totally void clear_log() { reset_log_cnt(); ev = {}; obj = {}; } // to write the log from samples void write_log (int[P] params) { ev[log_cnt++] = params; } // to check whether control-flow conforms to the samples @Native("{ std::cout << \\\"log::check_log::\\\" << params[0] << std::endl; }") void check_log (int[P] params) { assert params[0] == ev[log_cnt][0]; // check mid for (int i = 1; i < P; i++) { if (ev[log_cnt][i] != 0) { if (obj[ev[log_cnt][i]] == 0) { // not set yet obj[ev[log_cnt][i]] = params[i]; } else { // o.w. check obj eq. assert obj[ev[log_cnt][i]] == params[i]; } } } log_cnt++; // advance } // distinct hash values for runtime objects int obj_cnt = 0; int nonce () { return obj_cnt++; } """) global _inits reg_codes = [] for ty in _inits: cls = class_lookup(ty) if not cls: continue buf.write(""" int obj_{0}_cnt = 0; {1}[O] obj_{0}; // to register runtime instances of {0} void register_{0} ({1} {2}) {{ if (obj_{0}_cnt < O) {{ obj_{0}[obj_{0}_cnt++] = {2}; }} }} // to access to a certain instance of {0} {1} retrieve_{0} (int idx) {{ if (0 <= idx && idx < obj_{0}_cnt) {{ return obj_{0}[idx]; }} else {{ return null; }} }} """.format(ty, trans_ty(ty), ty.lower())) reg_code = "if (ty == {0}) register_{1}@log({2});".format(cls.id, repr(cls), C.SK.self) reg_codes.append(reg_code) # factory of Object buf.write(""" // factory of Object Object alloc(int ty) {{ Object {0} = new Object(hash=nonce(), __cid=ty); {1} return {0}; }} """.format(C.SK.self, "\nelse ".join(reg_codes))) global _ty; _clss = [] for ty in _ty.keys(): if util.is_collection(ty): continue if util.is_array(ty): continue cls = class_lookup(ty) if not cls: continue # to avoid None definition # inner class may appear twice: w/ and w/o outer class name if cls not in _clss: _clss.append(cls) buf.write("\n// distinct class IDs\n") for cls in _clss: buf.write("int {cls!r} () {{ return {cls.id}; }}\n".format(**locals())) buf.write("\n// distinct method IDs\n") for cls in tmpl.classes: mtds = collect_decls(cls, "mtds") if not mtds: continue for mtd in mtds: mname = sanitize_mname(unicode(repr(mtd))) buf.write(""" int {mname}_ent () {{ return {mtd.id}; }} int {mname}_ext () {{ return -{mtd.id}; }} """.format(**locals())) with open(os.path.join(sk_dir, "log.sk"), 'w') as f: f.write(buf.getvalue()) logging.info("encoding " + f.name) buf.close()