예제 #1
0
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
예제 #2
0
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
예제 #3
0
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()
예제 #4
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()
예제 #5
0
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()
예제 #6
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()