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 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 col_to_struct(cls): buf = cStringIO.StringIO() cname = cls.name sname = trans_ty(cname) global _collections if sname in _collections: logging.debug("collection: {} (duplicated)".format(cname)) return u'' else: _collections.add(sname) logging.debug("collection: " + cname) buf.write("struct ${sname} {\n int idx;\n") if C.J.MAP in cname: _, k, v = util.of_collection(cname) k = trans_ty(k) v = trans_ty(v) # Map<K,V> -> struct Map_K_V { int idx; K[S] key; V[S] val; } buf.write(" ${k}[S] key;\n ${v}[S] val;\n}\n") # Map<K,V>.containsKey -> containsKey_Map_K_V buf.write(""" bit {} (${{sname}} map, ${{k}} k) {{ int i; for (i = 0; map.val[i] != null && i < S; i++) {{ if (map.key[i] == k) return 1; }} return 0; }} """.format(trans_mname(cname, u"containsKey", [k]))) # Map<K,V>.get -> get_Map_K_V buf.write(""" ${{v}} {} (${{sname}} map, ${{k}} k) {{ int i; for (i = 0; map.val[i] != null && i < S; i++) {{ if (map.key[i] == k) return map.val[i]; }} return null; }} """.format(trans_mname(cname, u"get", [k]))) # Map<K,V>.put -> put_Map_K_V buf.write(""" void {} (${{sname}} map, ${{k}} k, ${{v}} v) {{ map.key[map.idx] = k; map.val[map.idx] = v; map.idx = (map.idx + 1) % S; }} """.format(trans_mname(cname, u"put", [k, v]))) # Map<K,V>.clear -> clear_Map_K_V if util.is_class_name(k): default_k = "null" else: default_k = "0" buf.write(""" void {} (${{sname}} map) {{ map.idx = 0; for (int i = 0; i < S; i++) {{ map.key[i] = {}; map.val[i] = null; }} }} """.format(trans_mname(cname, u"clear", []), default_k)) else: collection, t = util.of_collection(cname) t = trans_ty(t) if C.J.QUE in collection: buf.write(" int head;\n") # Collection<T> -> struct Collection_T { int idx; T[S] elts; } buf.write(" ${t}[S] elts;\n}\n") if C.J.STK in collection: # Stack<T>.peek -> peek_Stack_T buf.write(""" ${{t}} {} (${{sname}} stk) {{ if (stk.idx == 0) return null; ${{t}} top = stk.elts[stk.idx - 1]; return top; }} """.format(trans_mname(cname, u"peek", []))) # Stack<T>.push -> push_Stack_T buf.write(""" ${{t}} {} (${{sname}} stk, ${{t}} elt) {{ stk.elts[stk.idx] = elt; stk.idx = (stk.idx + 1) % S; return elt; }} """.format(trans_mname(cname, u"push", [t]))) # Stack<T>.pop -> pop_Stack_T buf.write(""" ${{t}} {} (${{sname}} stk) {{ if (stk.idx == 0) return null; stk.idx = stk.idx - 1; ${{t}} top = stk.elts[stk.idx]; stk.elts[stk.idx] = null; return top; }} """.format(trans_mname(cname, u"pop", []))) elif C.J.QUE in collection: # Queue<T>.add -> add_Queue_T buf.write(""" bit {} (${{sname}} que, ${{t}} elt) {{ que.elts[que.idx] = elt; que.idx = (que.idx + 1) % S; return true; }} """.format(trans_mname(cname, u"add", [t]))) # Queue<T>.remove -> remove_Queue_T buf.write(""" ${{t}} {} (${{sname}} que) {{ if (que.head == que.idx) return null; ${{t}} top = que.elts[que.head]; que.elts[que.head] = null; que.head = (que.head + 1) % S; return top; }} """.format(trans_mname(cname, u"remove", []))) # Queue<T>.isEmpty -> isEmpty_Queue_T buf.write(""" bit {} (${{sname}} que) {{ return que.head == que.idx; }} """.format(trans_mname(cname, u"isEmpty", []))) elif C.J.LST in collection: # List<T>.add -> add_List_T buf.write(""" bit {} (${{sname}} lst, ${{t}} elt) {{ lst.elts[lst.idx] = elt; lst.idx = (lst.idx + 1) % S; return true; }} """.format(trans_mname(cname, u"add", [t]))) # List<T>.remove(T) -> remove_List_T_T buf.write(""" bit {} (${{sname}} lst, ${{t}} elt) {{ int i; for (i = 0; lst.elts[i] != null && i < S; i++) {{ if (lst.elts[i] == elt) {{ lst.elts[i] = null; int j; for (j = i + 1; lst.elts[j] != null && j < lst.idx; j++) {{ lst.elts[j-1] = lst.elts[j]; }} lst.idx = (lst.idx - 1) % S; return true; }} }} return false; }} """.format(trans_mname(cname, u"remove", [t]))) # List<T>.remove(int) -> remove_List_T_int buf.write(""" ${{t}} {} (${{sname}} lst, int index) {{ ${{t}} res = null; if (0 <= index && index < lst.idx) {{ res = lst.elts[index]; lst.elts[index] = null; int i; for (i = index + 1; lst.elts[i] != null && i < lst.idx; i++) {{ lst.elts[i-1] = lst.elts[i]; }} lst.idx = (lst.idx - 1) % S; }} return res; }} """.format(trans_mname(cname, u"remove", [C.J.i]))) # List<T>.get -> get_List_T buf.write(""" ${{t}} {} (${{sname}} lst, int index) {{ ${{t}} res = null; if (0 <= index && index < lst.idx) {{ res = lst.elts[index]; }} return res; }} """.format(trans_mname(cname, u"get", [C.J.i]))) # List<T>.isEmpty -> isEmpty_List_T buf.write(""" bit {} (${{sname}} lst) {{ return lst.idx == 0; }} """.format(trans_mname(cname, u"isEmpty", []))) return T(buf.getvalue()).safe_substitute(locals())