Esempio n. 1
0
def sanitize_id(dot_id):
  pkg, cls, mtd = util.explode_mname(dot_id)
  if cls and util.is_class_name(cls) and class_lookup(cls):
    clazz = class_lookup(cls)
    if clazz.pkg and pkg and clazz.pkg != pkg: # to avoid u'' != None
      raise Exception("wrong package", pkg, clazz.pkg)
    return '.'.join([cls, mtd])

  return dot_id
Esempio n. 2
0
def sanitize_id(dot_id):
  pkg, cls, mtd = util.explode_mname(dot_id)
  if cls and util.is_class_name(cls) and class_lookup(cls):
    clazz = class_lookup(cls)
    if clazz.pkg and pkg and clazz.pkg != pkg: # to avoid u'' != None
      raise Exception("wrong package", pkg, clazz.pkg)
    return '.'.join([cls, mtd])

  return dot_id
Esempio n. 3
0
def log_param( (ty, nm) ):
  ty = trans_ty(ty)
  if util.is_class_name(ty):
    if nm == C.J.N:
      return (u'', u'')
    else:
      nm_hash = nm + u"_hash"
      retrival = u"""
        int {nm_hash} = 0;
        if ({nm} != null) {{ {nm_hash} = {nm}.hash; }}
      """.format(**locals())
      return (retrival, nm_hash)
  elif ty in [C.SK.z] + C.primitives:
    return (u'', nm)
  else:
    return (u'', u'')
Esempio n. 4
0
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()
Esempio n. 5
0
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())
Esempio n. 6
0
def to_sk(pgr, sk_dir):
  # clean up result directory
  if os.path.isdir(sk_dir): util.clean_dir(sk_dir)
  else: os.makedirs(sk_dir)

  # reset global variables so that we can run this encoding phase per demo
  reset()

  # update global constants
  # TODO: conservative analysis of possible length of collections
  # TODO: counting .add() calls or something?
  magic_S = 7

  global _const
  _const = u"""
    int S = {}; // length of arrays for Java collections
  """.format(magic_S)

  # type.sk
  logging.info("building class hierarchy")
  pgr.consist()
  # merge all classes and interfaces, except for primitive types
  clss, _ = util.partition(lambda c: util.is_class_name(c.name), classes())
  bases = rm_subs(clss)
  gen_type_sk(sk_dir, bases)

  # cls.sk
  cls_sks = []
  for cls in pgr.classes:
    # skip the collections, which will be encoded at type.sk
    if repr(cls).split('_')[0] in C.collections: continue
    cls_sk = gen_cls_sk(sk_dir, cls)
    if cls_sk: cls_sks.append(cls_sk)

  # log.sk
  gen_log_sk(sk_dir, pgr)

  # main.sk that imports all the other sketch files
  buf = cStringIO.StringIO()

  # --bnd-cbits: the number of bits for integer holes
  bits = max(5, int(math.ceil(math.log(len(methods()), 2))))
  buf.write("pragma options \"--bnd-cbits {}\";\n".format(bits))

  # --bnd-unroll-amnt: the unroll amount for loops
  unroll_amnt = None # use a default value if not set
  unroll_amnt = magic_S # TODO: other criteria?
  if unroll_amnt:
    buf.write("pragma options \"--bnd-unroll-amnt {}\";\n".format(unroll_amnt))

  # --bnd-inline-amnt: bounds inlining to n levels of recursion
  inline_amnt = None # use a default value if not set
  # setting it 1 means there is no recursion
  if inline_amnt:
    buf.write("pragma options \"--bnd-inline-amnt {}\";\n".format(inline_amnt))
    buf.write("pragma options \"--bnd-bound-mode CALLSITE\";\n")

  sks = ["log.sk", "type.sk"] + cls_sks
  for sk in sks:
    buf.write("include \"{}\";\n".format(sk))

  # TODO: make harness (if not exists)

  with open(os.path.join(sk_dir, "main.sk"), 'w') as f:
    f.write(buf.getvalue())
    logging.info("encoding " + f.name)
  buf.close()
Esempio n. 7
0
def find_setter(smpls, typs, Fname):
  mtds_ent_typs = find_mtds_ent_typs(smpls, typs)
  mtds_w_fname = filter(lambda mtd: Fname in mtd, mtds_ent_typs)
  mtds = filter(lambda mtd: not util.is_class_name(mtd), mtds_w_fname)
  if any(mtds): return mtds.pop()
  else: return "set" + Fname
Esempio n. 8
0
def find_getter(smpls, typs, Fname, prefix="get"):
  mtds_ext_typs = find_mtds_ext_typs(smpls, typs)
  mtds_w_fname = filter(lambda mtd: Fname in mtd, mtds_ext_typs)
  mtds = filter(lambda mtd: not util.is_class_name(mtd), mtds_w_fname)
  if any(mtds): return mtds.pop()
  else: return prefix + Fname
Esempio n. 9
0
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()
Esempio n. 10
0
 def default_init(fld):
   if util.is_class_name(fld.typ):
     return C.J.NEW + ' ' + trans_init(fld.typ, [], [])
   else: return '0'
Esempio n. 11
0
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())
Esempio n. 12
0
def to_sk(cmd, smpls, tmpl, sk_dir):
  # clean up result directory
  if os.path.isdir(sk_dir): util.clean_dir(sk_dir)
  else: os.makedirs(sk_dir)

  # reset global variables so that we can run this encoding phase per demo
  reset()

  # update global constants
  def logged(mtd):
    if mtd.is_init: return False
    clss = util.flatten_classes([mtd.clazz], "subs")
    return sample.mtd_appears(smpls, clss, mtd.name)
  mtds = filter(logged, methods())
  if mtds:
    n_params = 2 + max(map(len, map(op.attrgetter("params"), mtds)))
  else: # no meaningful logs in the sample?
    n_params = 2

  n_evts = sample.max_evts(smpls)
  if cmd == "android":
    n_views = sample.max_views(smpls)
    magic_S = max(3, n_evts + 1, n_views)
  else:
    magic_S = max(5, n_evts + 1) # at least 5, just in case

  n_ios = sample.max_IOs(smpls)

  global _const
  _const = u"""
    int P = {}; // length of parameters (0: (>|<)mid, 1: receiver, 2...)
    int S = {}; // length of arrays for Java collections
    int N = {}; // length of logs
  """.format(n_params, magic_S, n_ios)

  # type.sk
  logging.info("building class hierarchy")
  tmpl.consist()
  # merge all classes and interfaces, except for primitive types
  clss, _ = util.partition(lambda c: util.is_class_name(c.name), classes())
  bases = rm_subs(clss)
  gen_type_sk(sk_dir, bases)

  # cls.sk
  cls_sks = []
  for cls in tmpl.classes:
    # skip the collections, which will be encoded at type.sk
    if repr(cls).split('_')[0] in C.collections: continue
    cls_sk = gen_cls_sk(sk_dir, smpls, cls)
    if cls_sk: cls_sks.append(cls_sk)

  # sample_x.sk
  smpl_sks = []
  for smpl in smpls:
    smpl_sk = "sample_" + smpl.name + ".sk"
    smpl_sks.append(smpl_sk)
    sk_path = os.path.join(sk_dir, smpl_sk)
    gen_smpl_sk(sk_path, smpl, tmpl, tmpl.harness(smpl.name))

  # log.sk
  gen_log_sk(sk_dir, tmpl)

  # sample.sk that imports all the other sketch files
  buf = cStringIO.StringIO()

  # deprecated as we use regex generator for class/method roles
  ## --bnd-cbits: the number of bits for integer holes
  #bits = max(5, int(math.ceil(math.log(len(methods()), 2))))
  #buf.write("pragma options \"--bnd-cbits {}\";\n".format(bits))

  # --bnd-unroll-amnt: the unroll amount for loops
  unroll_amnt = max(n_params, magic_S)
  buf.write("pragma options \"--bnd-unroll-amnt {}\";\n".format(unroll_amnt))

  # --bnd-inline-amnt: bounds inlining to n levels of recursion
  inline_amnt = None # use a default value if not set
  if cmd == "android":
    #inline_amnt = 2 # depth of View hierarchy (at findViewByTraversal)
    inline_amnt = 1 # no recursion for flat Views
  elif cmd == "gui":
    # setting it 1 means there is no recursion
    inline_amnt = 1
  if inline_amnt:
    buf.write("pragma options \"--bnd-inline-amnt {}\";\n".format(inline_amnt))
    buf.write("pragma options \"--bnd-bound-mode CALLSITE\";\n")

  sks = ["log.sk", "type.sk"] + cls_sks + smpl_sks
  for sk in sks:
    buf.write("include \"{}\";\n".format(sk))
  with open(os.path.join(sk_dir, "sample.sk"), 'w') as f:
    f.write(buf.getvalue())
    logging.info("encoding " + f.name)
  buf.close()
Esempio n. 13
0
def find_setter(smpls, typs, Fname):
    mtds_ent_typs = find_mtds_ent_typs(smpls, typs)
    mtds_w_fname = filter(lambda mtd: Fname in mtd, mtds_ent_typs)
    mtds = filter(lambda mtd: not util.is_class_name(mtd), mtds_w_fname)
    if any(mtds): return mtds.pop()
    else: return "set" + Fname
Esempio n. 14
0
def find_getter(smpls, typs, Fname, prefix="get"):
    mtds_ext_typs = find_mtds_ext_typs(smpls, typs)
    mtds_w_fname = filter(lambda mtd: Fname in mtd, mtds_ext_typs)
    mtds = filter(lambda mtd: not util.is_class_name(mtd), mtds_w_fname)
    if any(mtds): return mtds.pop()
    else: return prefix + Fname