示例#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
示例#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
示例#3
0
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
示例#4
0
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()
示例#5
0
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
示例#6
0
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
示例#7
0
  def per_cls(sup_flds, cls):

    # keep mappings from original subclasses to the representative
    # so that subclasses can refer to the representative
    # e.g., for C < B < A, { B : A, C : A }
    cname = util.sanitize_ty(cls.name)
    if cname != cls_v.name: # exclude the root of this family
      logging.debug("{} => {}".format(cname, cls_v.name))
      _ty[cname] = cls_v.name
      if cls.is_inner: # to handle inner class w/ outer class name
        logging.debug("{} => {}".format(repr(cls), cls_v.name))
        _ty[unicode(repr(cls))] = cls_v.name

    # if this class implements an interface which has constants,
    # then copy those constants
    for itf in cls.itfs:
      cls_i = class_lookup(itf)
      if not cls_i or not cls_i.flds: continue
      for fld in cls_i.flds:
        sup_flds[fld.name] = fld

    # also, keep mappings from original member fields to newer ones
    # so that usage of old fields can be replaced accordingly
    # e.g., for A.f1 and B.f2, { A.f1 : f1_A, B.f1 : f1_A, B.f2 : f2_B }
    for sup_fld in sup_flds.keys():
      fld = sup_flds[sup_fld]
      fname = unicode(repr(fld))
      fid = '.'.join([cname, sup_fld])
      logging.debug("{} => {}".format(fid, fname))
      if fld.is_static: _s_flds[fid] = fname
      else: _flds[fid] = fname # { ..., B.f1 : f1_A }

    cur_flds = cp.deepcopy(sup_flds) # { f1 : f1_A }
    @takes(Field)
    @returns(nothing)
    def cp_fld(fld):
      cur_flds[fld.name] = fld # { ..., f2 : f2_B }

      fname = unicode(repr(fld))
      fld_v = cp.deepcopy(fld)
      fld_v.clazz = cls_v
      fld_v.name = fname
      cls_v.flds.append(fld_v)

      def upd_flds(cname):
        fid = '.'.join([cname, fld.name])
        # if A.f1 exists and B redefines f1, then B.f1 : f1_A
        # except for enum, which can (re)define its own fields
        # e.g., SwingConstands.LEADING vs. GroupLayout.Alignment.LEADING
        if not cls.is_enum and (fid in _s_flds or fid in _flds): return
        logging.debug("{} => {}".format(fid, fname))
        if fld.is_static: _s_flds[fid] = fname
        else: _flds[fid] = fname # { ..., B.f2 : f2_B }

      upd_flds(cname)

    map(cp_fld, cls.flds)

    map(partial(per_cls, cur_flds), cls.subs)
示例#8
0
  def marker(cname):
    cls = class_lookup(cname)
    if not cls: return
    if is_marked(cls): return
    mark(cls)

    if cls.sup: marker(cls.sup)
    for itf in cls.itfs: marker(itf)
    for fld in cls.flds: marker(fld.typ)
    for mtd in cls.mtds:
      marker(mtd.typ)
      for ty, _ in mtd.params: marker(ty)
示例#9
0
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()
示例#10
0
    def marker(cname):
        cls = class_lookup(cname)
        if not cls: return
        if is_marked(cls): return
        mark(cls)

        if cls.sup: marker(cls.sup)
        for itf in cls.itfs:
            marker(itf)
        for fld in cls.flds:
            marker(fld.typ)
        for mtd in cls.mtds:
            marker(mtd.typ)
            for ty, _ in mtd.params:
                marker(ty)
示例#11
0
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()
示例#12
0
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()
示例#13
0
def main(cmd, smpl_paths, tmpl_paths, patterns, out_dir, log_lv=logging.DEBUG):
    ## logging configuration
    logging.config.fileConfig(os.path.join(pwd, "logging.conf"))
    logging.getLogger().setLevel(log_lv)

    ## check custom codegen was built
    codegen_jar = os.path.join("codegen", "lib", "codegen.jar")
    if not os.path.isfile(codegen_jar):
        raise Exception("can't find " + codegen_jar)

    if cmd == "android":
        tmpl_paths.append(adr_tmpl)
    elif cmd == "gui":
        tmpl_paths.append(gui_tmpl)

    if cmd == "pattern":
        _patterns = patterns[:]
    else:  ## android or gui
        _patterns = [C.P.ACCA, C.P.ACCU, C.P.ACCM, C.P.ADP, C.P.BLD, C.P.FAC, C.P.SNG, C.P.PRX, C.P.OBS, C.P.STA]

    opts = []  ## sketch options
    if conf["verbose"]:
        opts.extend(["-V", "10"])
    if conf["timeout"]:
        opts.extend(["--fe-timeout", str(conf["timeout"])])
        opts.extend(["--slv-timeout", str(conf["timeout"])])
    # place to keep sketch's temporary files
    opts.extend(["--fe-tempdir", out_dir])
    opts.append("--fe-keep-tmp")

    tmpls = []
    output_paths = []
    for p in patterns:  ## for each pattern or demo
        logging.info("demo: " + p)
        _smpl_paths = smpl_paths[:]
        _tmpl_paths = tmpl_paths[:]

        _smpl_paths.append(os.path.join(smpl_dir, cmd, p))
        if cmd == "pattern":
            client_path = os.path.join(tmpl_dir, cmd, p)
        else:  ## android or gui
            client_path = os.path.join(tmpl_dir, app, cmd, p)
        _tmpl_paths.append(client_path)

        ## (smpl|tmpl)_path is either a single file or a folder containing files

        ## read and parse templates
        tmpl_files = []
        for tmpl_path in _tmpl_paths:
            tmpl_files.extend(util.get_files_from_path(tmpl_path, "java"))

        ast = util.toAST(tmpl_files)

        ## convert AST to meta data
        tmpl = Template(ast)

        ## mark client-side classes
        client_files = util.get_files_from_path(client_path, "java")
        for client in client_files:
            base = os.path.basename(client)
            cname = os.path.splitext(base)[0]
            cls = class_lookup(cname)
            cls.client = True

        ## read and parse samples
        smpl_files = []
        for smpl_path in _smpl_paths:
            smpl_files.extend(util.get_files_from_path(smpl_path, "txt"))

        sample.reset()
        smpls = []
        for fname in smpl_files:
            smpl = Sample(fname, tmpl.is_event)
            smpls.append(smpl)

        ## make harness
        harness.mk_harnesses(cmd, tmpl, smpls)

        ## pattern rewriting
        rewrite.visit(cmd, smpls, tmpl, _patterns)
        java_sk_dir = os.path.join(out_dir, "_".join(["java_sk", p]))
        decode.dump(cmd, java_sk_dir, tmpl)

        ## clean up templates
        # reducer.reduce_anno(smpls, tmpl)
        # reducer.remove_cls(smpls, tmpl)

        tmpl.freeze()
        tmpls.append(tmpl)

        ## encode (rewritten) templates into sketch files
        sk_dir = os.path.join(out_dir, "_".join(["sk", p]))
        if conf["encoding"]:
            encoder.to_sk(cmd, smpls, tmpl, sk_dir)
        else:  # not encoding
            logging.info("pass the encoding phase; rather use previous files")

        ## run sketch
        output_path = os.path.join(out_dir, "output", "{}.txt".format(p))
        output_paths.append(output_path)
        if conf["sketch"]:
            if os.path.exists(output_path):
                os.remove(output_path)

            # custom codegen
            _opts = opts[:]
            _opts.extend(["--fe-custom-codegen", codegen_jar])

            if conf["randassign"] or conf["parallel"]:
                _opts.append("--slv-randassign")
                _opts.extend(["--bnd-dag-size", "16000000"])  # 16M ~> 8G memory

            sketch.set_default_option(_opts)

            if conf["parallel"]:
                ## Python implementation as a CEGIS (sketch-backend) wrapper
                # _, r = sketch.be_p_run(sk_dir, output_path)
                # Java implementation inside sketch-frontend
                _opts.append("--slv-parallel")
                if conf["p_cpus"]:
                    _opts.extend(["--slv-p-cpus", str(conf["p_cpus"])])
                if conf["ntimes"]:
                    _opts.extend(["--slv-ntimes", str(conf["ntimes"])])
                if conf["randdegree"]:  # assume FIXED strategy
                    _opts.extend(["--slv-randdegree", str(conf["randdegree"])])
                else:  # adaptive concretization
                    _opts.extend(["--slv-strategy", "WILCOXON"])
                _, r = sketch.run(sk_dir, output_path)
            else:
                _, r = sketch.run(sk_dir, output_path)
            # if sketch fails, halt the process here
            if not r:
                sys.exit(1)

            ## run sketch again to obtain control-flows
            sketch.set_default_option(opts)
            r = sketch.ctrl_flow_run(sk_dir, output_path, out_dir)
            if not r:
                sys.exit(1)

        else:  # not running sketch
            logging.info("pass sketch; rather read: {}".format(output_path))

        ## end of loop (per pattern/demo)

    ## generate compilable model
    java_dir = os.path.join(out_dir, "java")
    decode.to_java(cmd, java_dir, tmpls, output_paths, _patterns)
    logging.info("synthesis done")

    return 0
示例#14
0
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()
示例#15
0
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
示例#16
0
  def per_cls(sup_flds, cls):
    aux_name = None
    # if this class is suppose to be replaced (due to pattern rewriting)
    # apply that replacement first, and then replace that aux type as well
    if not cls.is_aux and cls.name in _ty:
      aux_name = _ty[cls.name]
      logging.debug("{} => {}".format(aux_name, cls_v.name))
      # check that aux type is already involved in this family
      if aux_name not in _ty: _ty[aux_name] = cls_v.name

    # keep mappings from original subclasses to the representative
    # so that subclasses can refer to the representative
    # e.g., for C < B < A, { B : A, C : A }
    cname = util.sanitize_ty(cls.name)
    if cname != cls_v.name: # exclude the root of this family
      logging.debug("{} => {}".format(cname, cls_v.name))
      _ty[cname] = cls_v.name
      if cls.is_inner: # to handle inner class w/ outer class name
        logging.debug("{} => {}".format(repr(cls), cls_v.name))
        _ty[unicode(repr(cls))] = cls_v.name

    # if this class implements an interface which has constants,
    # then copy those constants
    for itf in cls.itfs:
      cls_i = class_lookup(itf)
      if not cls_i or not cls_i.flds: continue
      for fld in cls_i.flds:
        sup_flds[fld.name] = fld

    # also, keep mappings from original member fields to newer ones
    # so that usage of old fields can be replaced accordingly
    # e.g., for A.f1 and B.f2, { A.f1 : f1_A, B.f1 : f1_A, B.f2 : f2_B }
    for sup_fld in sup_flds.keys():
      fld = sup_flds[sup_fld]
      fname = unicode(repr(fld))
      fid = '.'.join([cname, sup_fld])
      logging.debug("{} => {}".format(fid, fname))
      if fld.is_static: _s_flds[fid] = fname
      else: _flds[fid] = fname # { ..., B.f1 : f1_A }

    cur_flds = cp.deepcopy(sup_flds) # { f1 : f1_A }
    @takes(Field)
    @returns(nothing)
    def cp_fld(fld):
      cur_flds[fld.name] = fld # { ..., f2 : f2_B }

      fname = unicode(repr(fld))
      fld_v = cp.deepcopy(fld)
      fld_v.clazz = cls_v
      fld_v.name = fname
      cls_v.flds.append(fld_v)

      def upd_flds(cname):
        fid = '.'.join([cname, fld.name])
        # if A.f1 exists and B redefines f1, then B.f1 : f1_A
        # except for enum, which can (re)define its own fields
        # e.g., SwingConstands.LEADING vs. GroupLayout.Alignment.LEADING
        if not cls.is_enum and (fid in _s_flds or fid in _flds): return
        logging.debug("{} => {}".format(fid, fname))
        if fld.is_static: _s_flds[fid] = fname
        else: _flds[fid] = fname # { ..., B.f2 : f2_B }

      upd_flds(cname)
      if aux_name: upd_flds(aux_name)

    map(cp_fld, cls.flds)

    # subclass relations of aux types are virtual, so do not visit further
    if not cls.is_aux:
      map(partial(per_cls, cur_flds), cls.subs)
示例#17
0
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])
示例#18
0
 def get_arg_typ(param): return str(class_lookup(param[0]).id)
 return '{' + ", ".join(map(get_arg_typ, mtd.params)) + '}'
示例#19
0
 def get_ret_typ(mtd):
   cls = class_lookup(mtd.typ)
   if cls: return cls.id
   else: return -1
示例#20
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()
示例#21
0
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()
示例#22
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()
示例#23
0
 def get_ret_typ(mtd):
   cls = class_lookup(mtd.typ)
   if cls: return cls.id
   else: return -1
示例#24
0
def main(cmd, smpl_paths, tmpl_paths, patterns, out_dir, log_lv=logging.DEBUG):
    ## logging configuration
    logging.config.fileConfig(os.path.join(pwd, "logging.conf"))
    logging.getLogger().setLevel(log_lv)

    ## check custom codegen was built
    codegen_jar = os.path.join("codegen", "lib", "codegen.jar")
    if not os.path.isfile(codegen_jar):
        raise Exception("can't find " + codegen_jar)

    if cmd == "android":
        tmpl_paths.append(adr_tmpl)
    elif cmd == "gui":
        tmpl_paths.append(gui_tmpl)

    if cmd == "pattern":
        _patterns = patterns[:]
    else:  ## android or gui
        _patterns = [C.P.ACCA, C.P.ACCU, C.P.ACCM, C.P.ADP, \
            C.P.BLD, C.P.FAC, C.P.SNG, C.P.PRX, C.P.OBS, C.P.STA]

    opts = []  ## sketch options
    if conf["verbose"]:
        opts.extend(["-V", "10"])
    if conf["timeout"]:
        opts.extend(["--fe-timeout", str(conf["timeout"])])
        opts.extend(["--slv-timeout", str(conf["timeout"])])
    # place to keep sketch's temporary files
    opts.extend(["--fe-tempdir", out_dir])
    opts.append("--fe-keep-tmp")

    tmpls = []
    output_paths = []
    for p in patterns:  ## for each pattern or demo
        logging.info("demo: " + p)
        _smpl_paths = smpl_paths[:]
        _tmpl_paths = tmpl_paths[:]

        _smpl_paths.append(os.path.join(smpl_dir, cmd, p))
        if cmd == "pattern":
            client_path = os.path.join(tmpl_dir, cmd, p)
        else:  ## android or gui
            client_path = os.path.join(tmpl_dir, app, cmd, p)
        _tmpl_paths.append(client_path)

        ## (smpl|tmpl)_path is either a single file or a folder containing files

        ## read and parse templates
        tmpl_files = []
        for tmpl_path in _tmpl_paths:
            tmpl_files.extend(util.get_files_from_path(tmpl_path, "java"))

        ast = util.toAST(tmpl_files)

        ## convert AST to meta data
        tmpl = Template(ast)

        ## mark client-side classes
        client_files = util.get_files_from_path(client_path, "java")
        for client in client_files:
            base = os.path.basename(client)
            cname = os.path.splitext(base)[0]
            cls = class_lookup(cname)
            cls.client = True

        ## read and parse samples
        smpl_files = []
        for smpl_path in _smpl_paths:
            smpl_files.extend(util.get_files_from_path(smpl_path, "txt"))

        sample.reset()
        smpls = []
        for fname in smpl_files:
            smpl = Sample(fname, tmpl.is_event)
            smpls.append(smpl)

        ## make harness
        harness.mk_harnesses(cmd, tmpl, smpls)

        ## pattern rewriting
        rewrite.visit(cmd, smpls, tmpl, _patterns)
        java_sk_dir = os.path.join(out_dir, '_'.join(["java_sk", p]))
        decode.dump(cmd, java_sk_dir, tmpl)

        ## clean up templates
        #reducer.reduce_anno(smpls, tmpl)
        #reducer.remove_cls(smpls, tmpl)

        tmpl.freeze()
        tmpls.append(tmpl)

        ## encode (rewritten) templates into sketch files
        sk_dir = os.path.join(out_dir, '_'.join(["sk", p]))
        if conf["encoding"]:
            encoder.to_sk(cmd, smpls, tmpl, sk_dir)
        else:  # not encoding
            logging.info("pass the encoding phase; rather use previous files")

        ## run sketch
        output_path = os.path.join(out_dir, "output", "{}.txt".format(p))
        output_paths.append(output_path)
        if conf["sketch"]:
            if os.path.exists(output_path): os.remove(output_path)

            # custom codegen
            _opts = opts[:]
            _opts.extend(["--fe-custom-codegen", codegen_jar])

            if conf["randassign"] or conf["parallel"]:
                _opts.append("--slv-randassign")
                _opts.extend(["--bnd-dag-size",
                              "16000000"])  # 16M ~> 8G memory

            sketch.set_default_option(_opts)

            if conf["parallel"]:
                ## Python implementation as a CEGIS (sketch-backend) wrapper
                #_, r = sketch.be_p_run(sk_dir, output_path)
                # Java implementation inside sketch-frontend
                _opts.append("--slv-parallel")
                if conf["p_cpus"]:
                    _opts.extend(["--slv-p-cpus", str(conf["p_cpus"])])
                if conf["ntimes"]:
                    _opts.extend(["--slv-ntimes", str(conf["ntimes"])])
                if conf["randdegree"]:  # assume FIXED strategy
                    _opts.extend(["--slv-randdegree", str(conf["randdegree"])])
                else:  # adaptive concretization
                    _opts.extend(["--slv-strategy", "WILCOXON"])
                _, r = sketch.run(sk_dir, output_path)
            else:
                _, r = sketch.run(sk_dir, output_path)
            # if sketch fails, halt the process here
            if not r: sys.exit(1)

            ## run sketch again to obtain control-flows
            sketch.set_default_option(opts)
            r = sketch.ctrl_flow_run(sk_dir, output_path, out_dir)
            if not r: sys.exit(1)

        else:  # not running sketch
            logging.info("pass sketch; rather read: {}".format(output_path))

        ## end of loop (per pattern/demo)

    ## generate compilable model
    java_dir = os.path.join(out_dir, "java")
    decode.to_java(cmd, java_dir, tmpls, output_paths, _patterns)
    logging.info("synthesis done")

    return 0
示例#25
0
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()
示例#26
0
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
示例#27
0
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])
示例#28
0
 def get_arg_typ(param): return str(class_lookup(param[0]).id)
 return '{' + ", ".join(map(get_arg_typ, mtd.params)) + '}'