Ejemplo n.º 1
0
    def exportvisit(n):
        if not at_root(n):
            typespace.error(
                "Export statements cannot be within functions or classes", n)

        pi = n.parent.index(n)
        n.parent.remove(n)

        for n2 in n[:]:
            n.remove(n2)
            n.parent.insert(pi, n2)
            pi += 1

        if not n.is_default:
            n2 = js_parse(
                """
        $s = _es6_module.add_export('$s', $s);
      """, [n.name, n.name, n.name])
        else:
            n2 = js_parse(
                """
        $s = _es6_module.set_default_export('$s', $s);
      """, [n.name, n.name, n.name])

        n.parent.insert(pi, n2)
Ejemplo n.º 2
0
 def visit(n):
   if not at_root(n):
     typespace.error("Import statements cannot be within functions or classes", n)
     
   modname = n[0].val
   
   depends.add(modname)
   
   if len(n) == 1: #import module name
     n.parent.replace(n, js_parse("""
       es6_import(_es6_module, '$s');
     """, [modname]));
   else:
     slist = StatementList()
     n.parent.replace(n, slist)
     
     for n2 in n[1:]:
       if n2.name == "*":
         n3 = js_parse("""
           var $s = es6_import(_es6_module, '$s');
         """, [n2.bindname, modname]);
         
         slist.add(n3);
       else:
         n3 = js_parse("""
         var $s = es6_import_item(_es6_module, '$s', '$s');
         """, [n2.bindname, modname, n2.name]);
         
         slist.add(n3)
Ejemplo n.º 3
0
  def frames_validate(frames):
    def gen_frame_validate(frames, tlevel=0):
      s = ""
      tstr = tab(tlevel+1)
      tstr2 = tab(tlevel+2)
      
      for f in frames:
        if type(f) == Frame:
          if f.node != None:
            cs = f.node.children
            f.node.children = f.node.children[:node._startcur]
            f.node.add(ExprNode([]))
            
            c = f.node.gen_js(tlevel+1).split("\n")[0].replace("{", "").replace("\n", "").replace("}", "").strip()
            
            if c.endswith(";"): c = c[:-1]
            
            s += tstr + c + " {\n"
            f.node.children = cs
            
          s += gen_frame_validate(f, tlevel+1)
          if f.node != None:
            s += tstr + "}\n"
        else:
          c = tstr + f.gen_js(tlevel+2)
          s += c
          if c.strip().endswith("}") == 0 and c.strip().endswith(";") == 0:
            s += ";"
          s += "\n"
      
      if tlevel == 0:
        c = node.gen_js(0).split("\n")[0] + "\n"
        s = c + s + "}\n"
      return s
      
    #print(node.gen_js(0))
    #print(scope)
    #print_frames(frames)
    s = gen_frame_validate(frames)
    
    s2 = js_parse(s).gen_js(0).strip()
    s = node.gen_js(0).strip()
    s = js_parse(s, print_stack=False).gen_js(0).strip()
    
    print(s==s2)
    if s != s2:
      import difflib
      print(dir(difflib))
      d = difflib.ndiff(s.split("\n"), s2.split("\n"))
      ds = ""
      for l in d:
        ds += l + "\n"

      #print(ds)
      line_print(s)
      line_print(s2)
Ejemplo n.º 4
0
    def var_transform(self, cls, var, member):
        # print(cls, var, member)
        if type(member) != str:
            member = member.val

        p = cls.childmap[member]
        if type(p) == VarDeclNode:
            arr = -1
            t = p.type
            while type(t) == StaticArrNode:
                t = t[0]

            if type(t) == BuiltinTypeNode:
                if t.type == "int":
                    arr = INT_ARR
                elif t.type == "float":
                    arr = FLOAT_ARR
                elif t.type == "byte":
                    arr = BYTE_ARR

            if arr == -1:
                self.typespace.error("internal error", var)

            off = p.start
            ret = js_parse(var.gen_js(0) + "[%d][%d];" % (arr, off), start_node=ArrayRefNode)
            ret.type = p

            return ret
        elif type(p) in [MethodGetter, MethodSetter]:
            # see if we have a getter
            if member in cls.getters:
                p = cls.getters[member]
                cls = p.parent

                name = cls.name + "_get__" + p.name
                ret = js_parse(name + "($n)", [var], start_node=FuncCallNode)

                ret.src = p
                return ret
            else:
                cls = p.parent

                name = cls.name + "_set__" + p.name
                ret = js_parse(name + "($n)", [var], start_node=FuncCallNode)
                ret.src = p

                return ret
        return IdentNode("[implement me]")
Ejemplo n.º 5
0
def refactor(data):
  result = js_parse(data)
  if result == None: result = StatementList()
  
  """
  def set_smap(n, smap):
    n.smap = smap
    for c in n:
      set_smap(c, smap)
  smap = SourceMap()
  set_smap(result, smap)
  result.gen_js(0)
  #"""
  
  typespace = JSTypeSpace()
  flatten_statementlists(result, typespace)
  
  for c in result:
    if type(c) == FuncCallNode and c[0].gen_js(0).strip() in ["inherit", "create_prototype"]:
      handle_potential_class(result, result.index(c), typespace)
      
  print(len(result))
  
  
  buf = data
  
  return buf, result
Ejemplo n.º 6
0
 def visit_breaks(n):
   wn = n
   
   if n in visit: return
   visit.add(n)
   
   while type(wn) not in [WhileNode, DoWhileNode, ForLoopNode]:
     if type(wn) == SwitchNode:
       typespace.error("Switches in generators not supported yet.", wn);
     wn = wn.parent
   
   if not wn:
     typespace.error("Invalid break statement.", n);
   
   if "frame" not in wn.__dict__:
     return
     
   f = wn.frame
   i = n.parent.index(n)
   
   n2 = js_parse("$s=$s;", ("$__state", f_next(f).label))
   
   if "frame" in n.__dict__:
     n.frame.insert(n.frame.index(n), n2)
   else:
     n.parent.insert(i, n2)
Ejemplo n.º 7
0
 def visit_rets1(n2):
   target = n2[0][0][0].val
   isyield = n2[0][0][1].val
   ni = n2.parent.index(n2)
   
   if target >= f_next(f.parent).label:
     n3 = js_parse("this.trystack.pop();")[0]
     n2.parent.insert(ni, n3)
Ejemplo n.º 8
0
 def varvisit(n, startn):
     return
     n2 = js_parse("""
       _es6_module.add_global('$s', $s);
     """, [n.val, n.val]);
     
     startn.parent.insert(startn.parent.index(startn)+1, n2);
     
     for n2 in n[2:]:
       varvisit(n2, startn);
Ejemplo n.º 9
0
 def exportfromvisit(n):
   n2 = js_parse("""
     import * as _$s1 from '$s1';
     
     for (var k in _$s1) {
       _es6_module.add_export(k, _$s1[k], true);
     }
   """, [n.name.val])
   
   n.parent.replace(n, n2)
Ejemplo n.º 10
0
    def exportfromvisit(n):
        n2 = js_parse(
            """
      import * as _$s1 from '$s1';
      
      for (var k in _$s1) {
        _es6_module.add_export(k, _$s1[k], true);
      }
    """, [n.name.val])

        n.parent.replace(n, n2)
Ejemplo n.º 11
0
 def exportvisit(n):
   if not at_root(n):
     typespace.error("Export statements cannot be within functions or classes", n)
   
   pi = n.parent.index(n)
   n.parent.remove(n)
   
   for n2 in n[:]:
     n.remove(n2)
     n.parent.insert(pi, n2)
     pi += 1
    
   if not n.is_default:
     n2 = js_parse("""
       $s = _es6_module.add_export('$s', $s);
     """, [n.name, n.name, n.name]);
   else: 
     n2 = js_parse("""
       $s = _es6_module.set_default_export('$s', $s);
     """, [n.name, n.name, n.name]);
     
   n.parent.insert(pi, n2)
Ejemplo n.º 12
0
 def handle_yields(node):
   slist = js_parse("""$__ret = this.ret;""");
   
   is_empty = type(node[0]) == ExprNode and len(node[0]) == 0
   
   if is_empty:
     slist.add(js_parse("""$s.value = undefined;""", ["$__ret"], start_node=AssignNode));
   else:
     slist.add(js_parse("""$s.value = $n;""", ["$__ret", node[0]], start_node=AssignNode))
   
   slen = len(slist)
   #print(slist)
   
   if node in node.parent:
     i = node.parent.index(node)
     
     node.parent.remove(node)
     for j in range(slen):
       node.parent.insert(i, slist[slen-j-1])
   
   i = node.frame.index(node)
   node.frame.remove(node)
   for j in range(slen):
     node.frame.insert(i, slist[slen-j-1])
Ejemplo n.º 13
0
    def visit(n):
        args = []
        for c in n[0]:
            n2 = js_parse("""
                _log_types($s1, $s2, $s3, $s4, $s5, $s6, $s7);
            """, ['"'+n.file+'"', str(n.line), '`'+buildkey(n)+'`', '`'+str(c.val)+'`', str(c.val),
            n.lexpos, n.lexpos2]);

            args.append(n2)

        for arg in args:
            if len(n) == 2 and type(n[1]) == StatementList:
                n[1].insert(0, arg)
            else:
                n.insert(1, arg)
Ejemplo n.º 14
0
    def retvisit(n):
        val = None

        if len(n) == 0 or n[0].gen_js(0).strip() == "":
            val = IdentNode("undefined")
        else:
            val = n[0]

        n2 = js_parse("""_log_return($s1, $s2, $s3, $n4, $s5, $s6)""",
                ['"'+n.file+'"', str(n.line), '`'+buildkey(n)+'`', val, n.lexpos, n.lexpos2],
                start_node=FuncCallNode)

        if len(n) == 0:
            n.append(n2)
        else:
            n.replace(n[0], n2)
Ejemplo n.º 15
0
 def visit_rets3(n2):
   p = n2.parent
   while not null_node(p) and p != f.subnode:
     if type(p) in [WhileNode, DoWhileNode, ForLoopNode]: break
     p = p.parent
     
   if p != f.subnode and not null_node(p): return #break corresponds to a loop internal to this frame
   p = find_parent_frame(f, [WhileNode, DoWhileNode, ForLoopNode], True)
     
   if p == None:
     typespace.error("Invalid break statement (switches within generators aren't supported yet)", n2)
   
   
   f2 = f_next(p)
     
   n3 = js_parse("return [$i, undefined];", [f2.label], start_node=ReturnNode);
   n2.parent.replace(n2, n3)
Ejemplo n.º 16
0
 def visit_rets3(n2):
   p = n2.parent
   while not null_node(p) and p != f.subnode:
     if type(p) in [WhileNode, DoWhileNode, ForLoopNode]: break
     p = p.parent
     
   if p != f.subnode and not null_node(p): return #break corresponds to a loop internal to this frame
   p = find_parent_frame(f, [WhileNode, DoWhileNode, ForLoopNode], True)
     
   if p == None:
     typespace.error("Invalid break statement (switches within generators aren't supported yet)", n2)
   
   
   f2 = f_next(p)
     
   n3 = js_parse("return [$i, undefined];", [f2.label], start_node=ReturnNode);
   n2.parent.replace(n2, n3)
Ejemplo n.º 17
0
 def visit_rets3(n2):
   p = n2.parent
   while not null_node(p) and p != f.subnode:
     p = p.parent
     
   if p != f.subnode and not null_node(p): return #continue corresponds to a loop internal to this frame
   p = f.parent
   while p != None:
     if type(p.node) in [WhileNode, DoWhileNode, ForLoopNode]:
       break;
     p = p.parent
     
   if p == None:
     typespace.error("Invalid continue statement")
   
   n3 = js_parse("return [$i, undefined];", [p.label], start_node=ReturnNode);
   n2.parent.replace(n2, n3)
Ejemplo n.º 18
0
 def visit_rets3(n2):
   p = n2.parent
   while not null_node(p) and p != f.subnode:
     p = p.parent
     
   if p != f.subnode and not null_node(p): return #continue corresponds to a loop internal to this frame
   p = f.parent
   while p != None:
     if type(p.node) in [WhileNode, DoWhileNode, ForLoopNode]:
       break;
     p = p.parent
     
   if p == None:
     typespace.error("Invalid continue statement")
   
   n3 = js_parse("return [$i, undefined];", [p.label], start_node=ReturnNode);
   n2.parent.replace(n2, n3)
Ejemplo n.º 19
0
 def visit_continues(n):
   if n in visit: return
   visit.add(n)
   
   wn = n
   while wn != None and (type(wn) not in [WhileNode, DoWhileNode, ForLoopNode]):
     wn = wn.parent
   
   if wn == None:
     typespace.error("Invalid continue statement.", n);
   
   if "frame" not in wn.__dict__:
     return
     
   f = wn.frame
   i = n.parent.index(n)
   n2 = js_parse("$s=$s;", ("$__state", f.label));
   
   n3 = BreakNode();
   visit.add(n3)
   
   n.parent.remove(n)
   n.frame.replace(n, n2)
   n.frame.insert(n.frame.index(n2)+1, n3)
Ejemplo n.º 20
0
 def class_visit(n):
   n2 = js_parse("""
     _es6_module.add_class($s);
   """, [n.name])
   n.parent.insert(n.parent.index(n)+1, n2);
Ejemplo n.º 21
0
 def match(self, matchdata, data=None, start_node=None):
   if data != None:
     self.input(data)
   else:
     data = self.data[:]
   
   for k in self.smap:
     repl = self.smap[k]
     
     k = "$" + k
     f = data.find(k)
     while f >= 0:
       lastf = f
       
       if f < len(data) - len(k):
         if _debug: print(f, data[f+len(k)])
         if is_word_char(data[f+len(k)]):
           lastf = f
           f = data[f+len(k):].find(k)
           
           if f < 0: 
             break
           else: 
             f += lastf + len(k)    
             continue
       
       
       data = data[:f] + repl + data[f+len(k):]
       
       lastf = f
       f = data[f+len(repl):].find(k)
       
       if f < 0: break
       else: f += lastf + len(repl)
   
   match_lexer.input(data)
   """
   t = match_lexer.token()
   while t != None:
     print(t)
     t = match_lexer.token()
   #"""
   ret = ast_match_parser.parse(data, lexer=match_lexer)
   if ret == None: raise MatchError("parse error")
   self.flatten_setnodes(ret)
   
   if _debug: print("\n")
   if _debug: print(data)
   if _debug: print(ret)
   
   def find_mref(n, mref, func):
     if func(n, mref): return True
     
     for c in n:
       ret = find_mref(c, mref, func)
       if ret: return True
     
     return False
   
   def do_mref(n, mref, func):
     ret = True
     try:
       ret = find_mref(n, mref, func)
     except MatchError:
       return False
     
     if ret == False:
       raise RuntimeError("Couldn't find special handler")
       
     return True
   
   self.process(ret)
   if type(matchdata) == str:
     node = js_parse(matchdata, start_node=start_node)
   else:
     node = matchdata
     
   for k in self.variants:
     n = js_parse(k, exit_on_err=False, validate=True)
     refs = self.variants[k]
     
     #print(k)
     if not node_structures_match(node, n): continue
     
     found = True
     for r in refs:
       rfunc = getattr(self, "do_"+r.type)
       if not do_mref(n, r, rfunc):
         found = False
         break
     
     if found: return True
   return False
Ejemplo n.º 22
0
    def build_next(f, parent=None):
        if type(f) != Frame:
            return

        subnode = f.subnode
        if f.label >= 0:  # and f.label < 3:
            n2 = js_parse("this.$s1 = 0;", [f_name(f)], start_node=AssignNode)
            n2.replace(n2[1], f.funcnode)
            f.funcnode.name = "(anonymous)"
            f.funcnode.is_anonymous = True

            node2.add(n2)  #f.funcnode)

        if f.totframes > 0:
            if f.node != None and type(f.node) == WhileNode:
                f2 = f_next(f)
                f2 = f2.label if f2 != -1 else -1
                n = js_parse(
                    """
                     if (!"placeholder") {
                        return [$i1, undefined];
                     }
                     """, [f2])

                if n == None:
                    typespace.error("internal error", subnode)

                n2 = find_node(n, StrLitNode)
                n2.parent.replace(n2, f.node[0])

                subnode.add(n)
                f2 = f_first(f)
                n.add(
                    js_parse("return [$i, undefined];", [f2.label],
                             start_node=ReturnNode))
            elif f.node != None and type(f.node) == TryNode:
                n = StatementList()

                if n == None:
                    typespace.error("internal error", subnode)

                f3 = f_raw_next(f)
                while f3 != -1 and type(f3.node) != CatchNode:
                    f3 = f_raw_next(f3)

                if f3 == -1:
                    typespace.error("Orphaned try block", f.node)

                f3name = "_nfothing"
                if len(f3.node) > 0:
                    f3name = f3.node[0].gen_js(0).replace("scope.", "")

                n.add(
                    js_parse(
                        """
           this.trystack.push([$i, "$s"]);
                        """, [f3.label, f3name]))

                f2 = f_first(f)
                n.add(
                    js_parse("return [$i, undefined];", [f2.label],
                             start_node=ReturnNode))
                subnode.add(n)
                f2.pop_trystack = True
            elif f.node != None and type(f.node) == IfNode:
                f2 = f_first(f)
                f1 = f_raw_next(f)
                while type(
                        f1.node) != ElseNode and f1.label != len(flatframes):
                    f1 = f_raw_next(f1)

                if f1.label == len(flatframes):
                    f1 = f_next(f)

                n = js_parse(
                    """
          if (!("placeholder")) {
            return [$i1, undefined];
          } else {
            return [$i2, undefined];
          }
        """, [f1.label, f2.label])

                n2 = find_node(n, StrLitNode)
                n2.parent.replace(n2, f.node[0].copy())

                if n == None:
                    typespace.error("internal error", subnode)

                f2 = f_first(f)
                n.add(
                    js_parse("return [$i, undefined];", [f2.label],
                             start_node=ReturnNode))
                subnode.add(n)
                f2.pop_trystack = True
            elif f.node != None and type(f.node) == ElseNode:
                f2 = f_first(f)
                f1 = f_raw_next(f)
                while type(
                        f1.node) != ElseNode and f1.label != len(flatframes):
                    f1 = f_raw_next(f1)

                if f1.label == len(flatframes):
                    f1 = f_next(f)

                n = js_parse(
                    """
          return [$i1, undefined];
        """, [f2.label])

                if n == None:
                    typespace.error("internal error", subnode)

                f2 = f_first(f)
                subnode.add(n)
            elif f.node != None and type(f.node) == CatchNode:
                f2 = f_first(f)

                n = js_parse(
                    """
          return [$i1, undefined];
        """, [f2.label])

                if n == None:
                    typespace.error("internal error", subnode)
                subnode.add(n)
            elif f.node != None and type(f.node) == ForLoopNode:
                f2 = f_first(f)
                f3 = f_next(f)

                f3 = f3.label if f2 != -1 else -1
                f2 = f2.label if f2 != -1 else -1

                n = js_parse(
                    """
                     if ($n) {
                      return [$i, undefined];
                     } else {
                      return [$i, undefined];
                     }                       
                     """, [f.node[0][1], f2, f3])

                if n == None:
                    typespace.error("internal error", subnode)

                subnode.add(n)
Ejemplo n.º 23
0
def bleh():
    for frames in flatframes:
        fname = f_name(frames)
        n = js_parse("""
           function $s1(scope) {
            if (_do_frame_debug) console.log("in $s1");

           }""", (fname),
                     start_node=FunctionNode)

        if type(n[1]) != StatementList:
            n.replace(n[1], StatementList())
        n = n[1]

        func = n
        while type(func) != FunctionNode:
            func = func.parent

        excl = (type(frames.node) == StatementList
                and type(frames.parent.node) == FunctionNode)
        if frames.node != None and not excl and type(
                frames.node) != FunctionNode:
            f = frames

            sl = StatementList()
            f.node[f.node._startcur] = sl

        frames.funcnode = func
        frames.subnode = frames.funcnode

        local_frames = "["
        totframes = 0

        for i, f in enumerate(frames):
            if type(f) != Frame:
                frames.subnode.add(f)
                frames.leaf = True

            else:
                frames.leaf = False
                if len(local_frames) > 1: local_frames += ", "
                local_frames += f_ref(f)  #.replace("this.", "")
                totframes += 1
                if f.node != None and type(f.node) != FunctionNode:
                    if len(f.node.children) > f.node._startcur + 1:
                        do_conv(f.node, f)

        if frames.leaf:
            f2 = f_next(frames)
            f2 = f2.label if f2 != -1 else -1
            frames.subnode.add(
                js_parse("return [$i, undefined];", [f2],
                         start_node=ReturnNode))

        local_frames = "%s_frames = " % f_ref(frames) + local_frames + "];"

        frames.frames = js_parse(local_frames)
        frames.totframes = totframes

    def build_next(f, parent=None):
        if type(f) != Frame:
            return

        subnode = f.subnode
        if f.label >= 0:  # and f.label < 3:
            n2 = js_parse("this.$s1 = 0;", [f_name(f)], start_node=AssignNode)
            n2.replace(n2[1], f.funcnode)
            f.funcnode.name = "(anonymous)"
            f.funcnode.is_anonymous = True

            node2.add(n2)  #f.funcnode)

        if f.totframes > 0:
            if f.node != None and type(f.node) == WhileNode:
                f2 = f_next(f)
                f2 = f2.label if f2 != -1 else -1
                n = js_parse(
                    """
                     if (!"placeholder") {
                        return [$i1, undefined];
                     }
                     """, [f2])

                if n == None:
                    typespace.error("internal error", subnode)

                n2 = find_node(n, StrLitNode)
                n2.parent.replace(n2, f.node[0])

                subnode.add(n)
                f2 = f_first(f)
                n.add(
                    js_parse("return [$i, undefined];", [f2.label],
                             start_node=ReturnNode))
            elif f.node != None and type(f.node) == TryNode:
                n = StatementList()

                if n == None:
                    typespace.error("internal error", subnode)

                f3 = f_raw_next(f)
                while f3 != -1 and type(f3.node) != CatchNode:
                    f3 = f_raw_next(f3)

                if f3 == -1:
                    typespace.error("Orphaned try block", f.node)

                f3name = "_nfothing"
                if len(f3.node) > 0:
                    f3name = f3.node[0].gen_js(0).replace("scope.", "")

                n.add(
                    js_parse(
                        """
           this.trystack.push([$i, "$s"]);
                        """, [f3.label, f3name]))

                f2 = f_first(f)
                n.add(
                    js_parse("return [$i, undefined];", [f2.label],
                             start_node=ReturnNode))
                subnode.add(n)
                f2.pop_trystack = True
            elif f.node != None and type(f.node) == IfNode:
                f2 = f_first(f)
                f1 = f_raw_next(f)
                while type(
                        f1.node) != ElseNode and f1.label != len(flatframes):
                    f1 = f_raw_next(f1)

                if f1.label == len(flatframes):
                    f1 = f_next(f)

                n = js_parse(
                    """
          if (!("placeholder")) {
            return [$i1, undefined];
          } else {
            return [$i2, undefined];
          }
        """, [f1.label, f2.label])

                n2 = find_node(n, StrLitNode)
                n2.parent.replace(n2, f.node[0].copy())

                if n == None:
                    typespace.error("internal error", subnode)

                f2 = f_first(f)
                n.add(
                    js_parse("return [$i, undefined];", [f2.label],
                             start_node=ReturnNode))
                subnode.add(n)
                f2.pop_trystack = True
            elif f.node != None and type(f.node) == ElseNode:
                f2 = f_first(f)
                f1 = f_raw_next(f)
                while type(
                        f1.node) != ElseNode and f1.label != len(flatframes):
                    f1 = f_raw_next(f1)

                if f1.label == len(flatframes):
                    f1 = f_next(f)

                n = js_parse(
                    """
          return [$i1, undefined];
        """, [f2.label])

                if n == None:
                    typespace.error("internal error", subnode)

                f2 = f_first(f)
                subnode.add(n)
            elif f.node != None and type(f.node) == CatchNode:
                f2 = f_first(f)

                n = js_parse(
                    """
          return [$i1, undefined];
        """, [f2.label])

                if n == None:
                    typespace.error("internal error", subnode)
                subnode.add(n)
            elif f.node != None and type(f.node) == ForLoopNode:
                f2 = f_first(f)
                f3 = f_next(f)

                f3 = f3.label if f2 != -1 else -1
                f2 = f2.label if f2 != -1 else -1

                n = js_parse(
                    """
                     if ($n) {
                      return [$i, undefined];
                     } else {
                      return [$i, undefined];
                     }                       
                     """, [f.node[0][1], f2, f3])

                if n == None:
                    typespace.error("internal error", subnode)

                subnode.add(n)

    node2.insert(
        1,
        js_parse("""
    this[Symbol.iterator] = function() {
      return this;
    }
  """)[0])
    for f in flatframes:
        build_next(f, f.parent)

    #process returns from within try nodes
    for f in flatframes:
        if f.parent != None and type(f.parent.node) == TryNode:

            def visit_rets1(n2):
                target = n2[0][0][0].val
                isyield = n2[0][0][1].val
                ni = n2.parent.index(n2)

                if target >= f_next(f.parent).label:
                    n3 = js_parse("this.trystack.pop();")[0]
                    n2.parent.insert(ni, n3)

            traverse(f.subnode, ReturnNode, visit_rets1, copy_children=True)

    #process yields
    for f in flatframes:
        f2 = f.parent
        set_yield = None

        def visit_rets2(n2):
            if set_yield != None:
                #print(n2)
                n2[0][0].replace(n2[0][0][1], set_yield)

        set_yield = find_node(f.subnode, YieldNode)
        if set_yield != None:
            set_yield.parent.remove(set_yield)
            set_yield = ArrayLitNode(ExprListNode([set_yield[0]]))

        traverse(f.subnode, ReturnNode, visit_rets2, copy_children=True)

    def find_parent_frame(f, ntypes, include_first=True):
        p = f
        if not include_first:
            p = p.parent

        while p != None:
            if type(p.node) in ntypes:
                return p
            p = p.parent
        return None

    #process breaks
    for f in flatframes:
        f2 = f.parent

        def visit_rets3(n2):
            p = n2.parent
            while not null_node(p) and p != f.subnode:
                if type(p) in [WhileNode, DoWhileNode, ForLoopNode]: break
                p = p.parent

            if p != f.subnode and not null_node(p):
                return  #break corresponds to a loop internal to this frame
            p = find_parent_frame(f, [WhileNode, DoWhileNode, ForLoopNode],
                                  True)

            if p == None:
                typespace.error(
                    "Invalid break statement (switches within generators aren't supported yet)",
                    n2)

            f2 = f_next(p)

            n3 = js_parse("return [$i, undefined];", [f2.label],
                          start_node=ReturnNode)
            n2.parent.replace(n2, n3)

        traverse(f.subnode, BreakNode, visit_rets3, copy_children=True)

    #process continues
    for f in flatframes:
        f2 = f.parent

        def visit_rets3(n2):
            p = n2.parent
            while not null_node(p) and p != f.subnode:
                p = p.parent

            if p != f.subnode and not null_node(p):
                return  #continue corresponds to a loop internal to this frame
            p = f.parent
            while p != None:
                if type(p.node) in [WhileNode, DoWhileNode, ForLoopNode]:
                    break
                p = p.parent

            if p == None:
                typespace.error("Invalid continue statement")

            n3 = js_parse("return [$i, undefined];", [p.label],
                          start_node=ReturnNode)
            n2.parent.replace(n2, n3)

        traverse(f.subnode, ContinueNode, visit_rets3, copy_children=True)

    firstnode = js_parse("if (this.first) {\n}", start_node=IfNode)
    firstnode2 = js_parse("if (this.first) {\n}", start_node=IfNode)
    firstnode.replace(firstnode[1], StatementList())
    firstnode2.replace(firstnode2[1], StatementList())
    flatframes[0].subnode.add(firstnode)
    node2.insert(1, firstnode2[1])

    firstnode = firstnode[1]
    firstnode2 = firstnode2[1]

    args = list(node.children[0])
    for i3 in range(len(args)):
        argn = args[i3]
        while type(argn) not in [IdentNode, VarDeclNode]:
            argn = argn[0]

        args[i3] = argn.val

    scope = {}
    for f in flatframes:
        scope.update(f.scope)

    s = "{"
    j2 = 0
    for j, v in enumerate(scope.keys()):
        if j2 > 0: s += ", "
        j2 += 1

        if v in args:
            s += "%s:%s" % ("%s_%s" % (v, scope[v]), v)
        else:
            s += "%s:undefined" % ("%s_%s" % (v, scope[v]))
    s += "}"

    s = "this.scope = %s;\n" % s
    firstnode2.add(js_parse(s)[0])

    #ensure all frames have returns
    for f in flatframes:
        if not find_node(f.subnode, ReturnNode):
            f.subnode.add(
                js_parse("return [$i, undefined];", [f_next(f).label],
                         start_node=ReturnNode))

    framelist = "["
    for i, f in enumerate(flatframes):
        if i > 0: framelist += ", "
        framelist += "this.frame_%i" % f.label
    framelist = "this.frames = %s];" % framelist
    node2.add(js_parse(framelist))

    node2.add(
        js_parse(
            """
    this.cur = 1;
    this.trystack = new Array();
    
    this.next = function() {
      var ret;
      while (this.cur < this.frames.length) {
        try {
          ret = this.frames[this.cur].call(this, this.scope);
        } catch (_generator_error) {
          if (this.trystack.length > 0) {
            var ts1 = this.trystack.pop();
            
            this.scope[ts1[1]] = _generator_error;
            
            ret = [ts1[0], undefined];
          } else {
            throw _generator_error;
          }
        }
        
        if (ret[0] == this.frames.length) {
          return {done : true, value : undefined};
          break;
        }
        
        if (ret[0] == this.cur) {
          console.trace();
          console.log("YEEK!")
          return {done : true, value : undefined};
        }
        
        this.cur = ret[0];
        
        if (ret[1] != undefined) {
          return {value : ret[1][0], done : false};
        } else {
          return {value : undefined, done : false};
        }
      }
    }
  """, []))

    node.parent.replace(node, node2)
Ejemplo n.º 24
0
def visit_generators(node):
    if not node.is_generator: return

    def _remove_this(n):
        if n.val != "this": return

        if type(n.parent) != BinOpNode or n.parent.op != ".":
            #typespace.error("Can only reference members of 'this' in generators");
            n.val = "__gen_this2"
        else:
            n.val = "__gen_this2"
            #n.parent.parent.replace(n.parent, n.parent[1])

    def set_cur(n):
        if type(n) in [IfNode, WhileNode, DoWhileNode, ForLoopNode, CatchNode]:
            n._cur = 1
            n._startcur = 1
        else:
            n._cur = 0
            n._startcur = 0

        n._start = True
        n._has_yield = node_has_yield(n)

        for c in n:
            set_cur(c)

    def prior_if(n):
        if n.parent == None: return None

        sl = n.parent
        i = sl.children.index(n) - 1
        while 1:
            while i >= 0:
                if type(sl[i]) == IfNode:
                    break
                i -= 1

            if i >= 0 or null_node(n.parent): break

            i = sl.parent.children.index(sl)
            sl = sl.parent

        if i < 0:
            typespace.error("Orphaned else node", n)
            sys.exit(-1)

        return sl[i]

    def prior_try(n):
        if n.parent == None: return None

        sl = n.parent
        i = sl.children.index(n) - 1
        while 1:
            while i >= 0:
                if type(sl[i]) == TryNode:
                    break
                i -= 1

            if i >= 0 or null_node(n.parent): break

            i = sl.parent.children.index(sl)
            sl = sl.parent

        if i < 0:
            typespace.error("Orphaned catch node", n)
            sys.exit(-1)

        return sl[i]

    def is_stype(n):
        ret = type(n) in stypes  # and (n._has_yield or n.parent._has_yield)

        return ret

        if type(n) == CatchNode:
            ret |= prior_try(n)._has_yield
        if type(n) == ElseNode:
            ret |= prior_if(n)._has_yield

        if type(n) in [IfNode, ElseNode]:
            p5 = n.parent
            while not null_node(p5):
                if hasattr(p5, "_has_yield") and p5._has_yield:
                    ret = True
                    break
                p5 = p5.parent

        return ret

    combine_if_else_nodes(node)

    traverse(node,
             ForCNode,
             unpack_for_c_loops,
             exclude=[FunctionNode],
             copy_children=True)
    traverse(node, IdentNode, _remove_this)
    traverse(node, VarDeclNode, _remove_this)

    frames = frame = Frame(node=node)

    stack = [c for c in node.children[1:]]
    stack.reverse()

    stypes = set([
        ForLoopNode, WhileNode, DoWhileNode, IfNode, ElseNode, TryNode,
        CatchNode
    ])

    for c in stack:
        set_cur(c)

    while len(stack) > 0:
        n = stack.pop(-1)

        if is_stype(n) or type(n) == StatementList:
            if n._start:
                if type(n) != StatementList:
                    f = Frame(node=n)
                    frame.append(f)
                    frame = f
                n._start = False

            if n._cur < len(n.children):
                stack.append(n)
                stack.append(n[n._cur])
                n._cur += 1
            elif type(n) != StatementList:
                frame = frame.parent
        else:
            frame.append(n)

    def compact_frames(frames):
        i = 0
        frm = None
        while i < len(frames):
            f1 = frames[i]

            if type(f1) == YieldNode:
                frm = None

            if type(f1) != Frame:
                if frm == None:
                    frm = Frame()
                    frames.insert(i, frm)
                    frm.parent = frames
                    i += 1

                frames.remove(f1)
                i -= 1
                frm.append(f1)
            else:
                compact_frames(f1)
                frm = None

            if type(f1) == YieldNode:
                frm = None

            i += 1

    def label_frames(frames, cur=None):
        if cur == None: cur = [0]

        frames.label = cur[0]
        cur[0] += 1

        for f in frames:
            if type(f) == Frame:
                if f.node != None:
                    f.node.frame = f
                label_frames(f, cur)
            else:
                f.frame = f

    def prop_frame_refs(node, f):
        if hasattr(node, "frame"): f = node.frame
        else: node.frame = f

        for c in node.children:
            prop_frame_refs(c, f)

    def apply_frame_scope(n, scope, frames):
        if type(n) == IdentNode:
            if n.val in scope:
                n.val = "scope.%s_%d" % (n.val, scope[n.val])
            else:
                p = n.parent
                n2 = n
                #check for implicit declarations within catch and loop nodes
                while not null_node(p):
                    if type(p) in [CatchNode, WhileNode, ForLoopNode]: break
                    n2 = p
                    p = p.parent

                if not null_node(p) and n2 == p[0]:
                    scope[n.val] = frames.label
                    n.val = "scope.%s_%d" % (n.val, scope[n.val])

        elif type(n) == VarDeclNode:
            n.local = False
            if "local" in n.modifiers: n.modifiers.remove("local")

            if hasattr(n.parent, "_c_loop_node"):
                frames = n.parent._c_loop_node.frame
                #print("yay", n.parent._c_loop_node.frame.label)

            if n.val not in scope:
                scope[n.val] = frames.label
            if n.val in scope:
                n.val = "scope.%s_%d" % (n.val, scope[n.val])
        for c in n.children:
            #ignore expr functions, but not nested functions?
            if type(c) == FunctionNode and type(c.parent) == AssignNode:
                continue
            if type(n) == BinOpNode and n.op == "." and c == n[1] and type(
                    c) == IdentNode:
                continue
            if type(n) == FuncCallNode and type(c) == IdentNode and c == n[0]:
                continue

            apply_frame_scope(c, scope, frames)

    def frame_scope(frames, scope, depth=0):
        frames.scope = scope

        for f in frames:
            ss = "-"
            fstr = ""
            if type(f) == Frame:
                if f.node != None:
                    fstr = f.node.get_line_str()
                else:
                    if type(f[0]) == Frame: fstr = f[0].node.get_line_str()
                    else: fstr = f[0].get_line_str()

                if f.node != None:
                    ss = "+"
                    scope2 = dict(scope)
                    for i in range(f.node._startcur):
                        apply_frame_scope(f.node[i], scope2, f)

                    frame_scope(f, scope2, depth + 1)
                else:
                    frame_scope(f, scope, depth)
            else:
                fstr = f.get_line_str()
                apply_frame_scope(f, scope, frames)

    scope = {}
    for a in node.children[0]:
        scope[a.val] = 0

    compact_frames(frames)
    label_frames(frames)
    prop_frame_refs(node, frames)
    frame_scope(frames, scope)

    #print_frames(frames)

    def frames_validate(frames):
        def gen_frame_validate(frames, tlevel=0):
            s = ""
            tstr = tab(tlevel + 1)
            tstr2 = tab(tlevel + 2)

            for f in frames:
                if type(f) == Frame:
                    if f.node != None:
                        cs = f.node.children
                        f.node.children = f.node.children[:node._startcur]
                        f.node.add(ExprNode([]))

                        c = f.node.gen_js(tlevel + 1).split("\n")[0].replace(
                            "{", "").replace("\n", "").replace("}",
                                                               "").strip()

                        if c.endswith(";"): c = c[:-1]

                        s += tstr + c + " {\n"
                        f.node.children = cs

                    s += gen_frame_validate(f, tlevel + 1)
                    if f.node != None:
                        s += tstr + "}\n"
                else:
                    c = tstr + f.gen_js(tlevel + 2)
                    s += c
                    if c.strip().endswith("}") == 0 and c.strip().endswith(
                            ";") == 0:
                        s += ";"
                    s += "\n"

            if tlevel == 0:
                c = node.gen_js(0).split("\n")[0] + "\n"
                s = c + s + "}\n"
            return s

        #print(node.gen_js(0))
        #print(scope)
        #print_frames(frames)
        s = gen_frame_validate(frames)

        s2 = js_parse(s).gen_js(0).strip()
        s = node.gen_js(0).strip()
        s = js_parse(s, print_stack=False).gen_js(0).strip()

        print(s == s2)
        if s != s2:
            import difflib
            print(dir(difflib))
            d = difflib.ndiff(s.split("\n"), s2.split("\n"))
            ds = ""
            for l in d:
                ds += l + "\n"

            #print(ds)
            line_print(s)
            line_print(s2)

    #frames_validate(frames)

    flatframes = []

    def flatten_frames(frames):
        flatframes.append(frames)

        for f in frames:
            if type(f) == Frame:
                flatten_frames(f)

    flatten_frames(frames)

    #print([f.label for f in flatframes])

    def frames_transform(frames, node2):
        scope = frames.scope

    node2 = FunctionNode(node.name, node.lineno)
    node2.add(ExprListNode([]))

    for c in node.children[0]:
        node2[0].add(IdentNode(c.val))

    frames2 = frames

    for j, frames in enumerate(flatframes[1:]):
        p = frames.parent
        f = frames

        frames.return_frame = 0
        frames.return_frame_parent = 0

        i = p.index(f)
        while i >= len(p) - 1 and p.parent != None:
            f = p
            p = p.parent
            i = p.index(f)

        if p.parent == None:
            frames.return_frame = 0
            frames.return_frame_parent = p.label
        else:
            frames.return_frame = p[i + 1].label
            frames.return_frame_parent = p.label

    def f_name(f):
        return "frame_%d" % f.label

    def f_ref(f):
        return "this.frame_%d" % f.label

    def f_raw_next(f):
        if f.parent == None:
            f = Frame()
            f.label = len(flatframes)
            return f

        while f.parent != None:
            i = f.parent.index(f) + 1
            while i < len(f.parent):
                if type(f.parent[i]) == Frame:
                    return f.parent[i]
                i += 1

            f = f.parent

        f = Frame()
        f.label = len(flatframes)
        return f

    def f_next(f, ignore_loops=False):
        if f.parent == None:
            if debug_gen:
                print("no f.parent! make frame")

            f = Frame()
            f.label = len(flatframes)
            return f

        while f.parent != None:
            i = f.parent.index(f) + 1

            while i < len(f.parent):
                if type(f.parent[i]) == Frame:
                    if type(f.parent[i].node) not in [CatchNode, ElseNode]:
                        return f.parent[i]
                i += 1

            if not ignore_loops and f.parent != None and \
               type(f.parent.node) in \
               [WhileNode, DoWhileNode, ForLoopNode]:
                if debug_gen:
                    print("looper!", f.label, f.parent.label)
                return f.parent

            f = f.parent

        if debug_gen:
            print("made frame!", len(flatframes))

        f = Frame()
        f.label = len(flatframes)
        return f

    def f_first(f):
        for f2 in f:
            if type(f2) == Frame:
                return f2
        #return f

    def f_last(f):
        return f[-1]

    def has_parent(f, p):
        while f != p and f != None:
            f = f.parent
        return f == p

    def find_exit_points(f, p=None, vset=None):
        stack = []

        if p == None: p = f
        if vset == None: vset = set()

        lst = []
        """
    lst = []
    for f2 in f:
      if type(f2) == Frame:
        for f3 in f2.paths:
          if type(f3) == Frame:
            if not has_parent(f3, p) and f3.label not in vset:
              lst.append(f3)
              vset.add(f3.label)
            lst += find_exit_points(f3, p, vset)
          else:
            continue
    """

        for f2 in f.paths:
            if not has_parent(f2, p) and f2.label not in vset:
                lst.append(f)
                vset.add(f.label)
            else:
                lst += find_exit_points(f2, p, vset)

        for f in lst:
            print(f.label)

        #sys.exit()
        return lst

    tot = len(node) - 1
    for i in range(tot):
        node.pop(1)

    def param_var(k):
        for c in node[0]:
            val = c.gen_js(0)
            val = val.strip()
            k = k.strip()
            if k == val: return True
        return False

    #build generator state data
    scopestr = "{"
    for k in scope:
        if scopestr != "{": scopestr += ", "
        if param_var(k):
            scopestr += "%s_%i : %s" % (k, scope[k], k)
        else:
            scopestr += "%s_%i : %s" % (k, scope[k], "undefined")
    scopestr += "}"

    node.add(js_parse("this.scope = $s;", [scopestr], start_node=AssignNode))
    node.add(
        js_parse("this.ret = {done : false, value : undefined};",
                 start_node=AssignNode))
    node.add(js_parse("this.state = 1;", start_node=AssignNode))
    node.add(js_parse("this.trystack = [];", start_node=AssignNode))

    node.add(
        js_parse("""
    this.next = function() {
      var ret;
      var stack = this.trystack;
      
      try {
        ret = this._next();
      } catch (err) {
        if (stack.length > 0) {
          var item = stack.pop(stack.length-1);
          this.state = item[0];
          this.scope[item[1]] = err;
          
          return this.next();
        } else {
          throw err;
        }
      }
      
      return ret;
    }""",
                 start_node=AssignNode))

    node.add(
        js_parse("""
    this.push_trystack = function(catchstate, catchvar) {
      this.trystack.push([catchstate, catchvar]);
    }""",
                 start_node=AssignNode))

    node.add(
        js_parse("""
    this.pop_trystack = function() {
      this.trystack.pop(this.trystack.length-1);
    }""",
                 start_node=AssignNode))

    #build next function
    keynode = IdentNode("$__state")
    sn = SwitchNode(keynode)
    slist = js_parse(
        "var $__ret = undefined; var $__state = this.state; var scope = this.scope;"
    )

    slist2 = StatementList()
    slist2.add(sn)

    wn = WhileNode(
        BinOpNode(IdentNode("$__state"), NumLitNode(len(flatframes)), "<"))
    wn.add(slist2)

    wn[1].add(
        js_parse("""
    if ($__ret != undefined) {
      break;
    }
  """,
                 start_node=IfNode))

    slist.add(wn)
    slist.add(
        js_parse("""
    if ($__ret != undefined) {
      this.ret.value = $__ret.value;
    } else {
      this.ret.done = true;
      this.ret.value = undefined;
    }
    
    this.state = $__state;
    return this.ret;
  """))

    next = js_parse("this._next = function() { };", start_node=AssignNode)

    next[1].add(slist)

    node.add(next)

    sn.line = slist.line = node.line
    sn.lexpos = slist.lexpos = node.lexpos

    #find leaves
    for f in flatframes:
        if len(f) > 0:
            f.leaf = True

            for c in f:
                if type(c) == Frame:
                    f.leaf = False
                    break

    #move control frame of dowhile statements to
    #after their statement body frames.
    visit = set()
    for i in range(len(flatframes)):
        if i in visit: continue

        f = flatframes[i]

        if f.leaf or type(f.node) != DoWhileNode: continue

        f2 = f_first(f)
        if f2 == None: continue

        last = f2.label
        while (f2 != f_next(f) and f2 != f):
            last = f2.label
            f2 = f_next(f2)

        last = ((last - 1) if last > i else last) + 1

        flatframes.pop(i)
        flatframes.insert(last, f)
        visit.add(last)

    for i, f in enumerate(flatframes):
        f.label = i

    #set up case statements
    for f in flatframes:
        n2 = CaseNode(NumLitNode(f.label))
        sl = StatementList()

        if debug_gen:
            sl.add(js_parse("console.log(\"in frame $s\");", [f.label]))

        #set line/lexpos data
        if f.node != None:
            n2.line = f.node.line
            n2.lexpos = f.node.lexpos
            sl.line = f.node.line
            sl.lexpos = f.node.lexpos

        f.case_sl = sl

        n2.add(sl)

        #add to switch statement
        sn.add(n2)

    def set_linepos(n, line, lexpos):
        n.line = line
        n.lexpos = lexpos
        for c in n:
            set_linepos(c, line, lexpos)

    for f in flatframes:
        if f.leaf:
            for c in f:
                c.frame = f
        else:
            f.node.frame = f

    #handle loop breaks/continues
    visit = set()

    def visit_breaks(n):
        wn = n

        if n in visit: return
        visit.add(n)

        while type(wn) not in [WhileNode, DoWhileNode, ForLoopNode]:
            if type(wn) == SwitchNode:
                typespace.error("Switches in generators not supported yet.",
                                wn)
            wn = wn.parent

        if not wn:
            typespace.error("Invalid break statement.", n)

        if "frame" not in wn.__dict__:
            return

        f = wn.frame
        i = n.parent.index(n)

        n2 = js_parse("$s=$s;", ("$__state", f_next(f).label))

        if "frame" in n.__dict__:
            n.frame.insert(n.frame.index(n), n2)
        else:
            n.parent.insert(i, n2)

    def visit_continues(n):
        if n in visit: return
        visit.add(n)

        wn = n
        while wn != None and (type(wn)
                              not in [WhileNode, DoWhileNode, ForLoopNode]):
            wn = wn.parent

        if wn == None:
            typespace.error("Invalid continue statement.", n)

        if "frame" not in wn.__dict__:
            return

        f = wn.frame
        i = n.parent.index(n)
        n2 = js_parse("$s=$s;", ("$__state", f.label))

        n3 = BreakNode()
        visit.add(n3)

        n.parent.remove(n)
        n.frame.replace(n, n2)
        n.frame.insert(n.frame.index(n2) + 1, n3)

    def handle_yields(node):
        slist = js_parse("""$__ret = this.ret;""")

        is_empty = type(node[0]) == ExprNode and len(node[0]) == 0

        if is_empty:
            slist.add(
                js_parse("""$s.value = undefined;""", ["$__ret"],
                         start_node=AssignNode))
        else:
            slist.add(
                js_parse("""$s.value = $n;""", ["$__ret", node[0]],
                         start_node=AssignNode))

        slen = len(slist)
        #print(slist)

        if node in node.parent:
            i = node.parent.index(node)

            node.parent.remove(node)
            for j in range(slen):
                node.parent.insert(i, slist[slen - j - 1])

        i = node.frame.index(node)
        node.frame.remove(node)
        for j in range(slen):
            node.frame.insert(i, slist[slen - j - 1])

    #handle loop breaks
    for f in flatframes:
        if not f.leaf: continue
        for c in f:
            traverse(c, BreakNode, visit_breaks, exclude=FunctionNode)
            pass
    #handle loop continues
    for f in flatframes:
        if not f.leaf: continue
        for c in f:
            traverse(c, ContinueNode, visit_continues, exclude=FunctionNode)
            pass

    #handle yields
    for f in flatframes:
        if not f.leaf: continue
        for c in f:
            traverse(c, YieldNode, handle_yields, exclude=FunctionNode)

    def has_common_parent(n1, n2, p):
        while n1 != p and n1 != None:
            n1 = n1.parent

        while n2 != p and n2 != None:
            n2 = n2.parent

        if n1 == n2 and n1 == p: return True
        else: return False

    #build control code
    for f in flatframes:
        if f.leaf: continue
        n = f.node
        sl = f.case_sl

        if type(n) == IfNode:
            f2 = f_first(f)

            if f2 == None:  #empty if node
                f2 = Frame()
                f2.label = len(flatframes)

            if len(n) > 2:
                f3 = n[2].frame
            else:
                f3 = f_next(f)

            f.paths += [f2, f3]

            n2 = js_parse("""
        $s = ($n) ? $s : $s;
      """, ["$__state", n[0], f2.label, f3.label])

            set_linepos(n2, n.line, n.lexpos)
            sl.add(n2)
        elif type(n) == ElseNode:
            f2 = f_first(f)

            if f2 == None:  #empty else node
                f2 = Frame()
                f2.label = len(flatframes)

            f.paths += [f2]

            n2 = js_parse(";$s = $s;", ("$__state", str(f2.label)))

            set_linepos(n2, n.line, n.lexpos)
            sl.add(n2)
        elif type(n) == WhileNode:
            f.paths += [f_first(f), f_next(f, False)]

            n2 = js_parse("""
        $s = ($n) ? $s : $s;
      """, ("$__state", n[0], f_first(f).label, f_next(f, False).label))

            set_linepos(n2, n.line, n.lexpos)
            sl.add(n2)
        elif type(n) == ForLoopNode:
            #okay, why did I say to ignore loops here?
            f.paths += [f_first(f), f_next(f, False)]

            if type(n[0]) == ForCNode:
                n2 = js_parse("""
          $s = ($n) ? $s : $s;
        """, ("$__state", n[0][1], f_first(f).label, f_next(f, False).label))

                set_linepos(n2, n.line, n.lexpos)
                sl.add(n2)
            else:
                typespace.error(
                    "process_generators expects unpacked iterator for loops",
                    n)
        elif type(n) == DoWhileNode:
            f.paths += [f_first(f), f_next(f, False)]

            n2 = js_parse("""
        $s = ($n) ? $s : $s;
      """, ("$__state", n[0], f_first(f).label, f_next(f, False).label),
                          start_node=AssignNode)

            set_linepos(n2, n.line, n.lexpos)
            sl.add(n2)
        elif type(n) == TryNode:
            f.paths += [f_first(f)]

            cn = f_raw_next(f).node
            if type(cn) != CatchNode:
                typespace.error("Missing catch block", f.node)

            ident = cn[0].gen_js(0).replace("scope.", "")

            n2 = js_parse("$s = $s;", ("$__state", f_first(f).label),
                          start_node=AssignNode)
            n3 = js_parse("this.push_trystack($s, \"$s\");",
                          [f_raw_next(f).label, ident])

            set_linepos(n2, n.line, n.lexpos)
            set_linepos(n3, n.line, n.lexpos)
            sl.add(n2)
            sl.add(n3)
        elif type(n) == CatchNode:
            f.paths += [f_first(f)]

            n2 = js_parse("$s = $s;", ("$__state", f_first(f).label),
                          start_node=AssignNode)
            set_linepos(n2, n.line, n.lexpos)
            sl.add(n2)

    #build leaf code
    for f in flatframes:
        if not f.leaf: continue
        sl = f.case_sl

        for n in f:
            sl.add(n)

        f2 = f_next(f)
        sl.add(js_parse(";$s=$s;", ("$__state", str(f2.label))))
        f.paths += [f2]

    #add in pop_trystack calls
    for f in flatframes:
        if type(f.node) != TryNode: continue
        f2 = f_last(f)

        ps = find_exit_points(f)
        for f2 in ps:
            f2.case_sl.add(js_parse("this.pop_trystack();"))

    #add case breaks
    for f in flatframes:
        bn = BreakNode()
        bn.line = f.case_sl.line
        bn.lexpos = f.case_sl.lexpos
        f.case_sl.add(bn)

    #add final state case
    cn = CaseNode(NumLitNode(len(flatframes)))
    sl2 = StatementList()
    sl2.add(BreakNode())
    cn.add(sl2)
    sn.add(cn)

    #default case
    df = DefaultCaseNode()
    df.add(
        js_parse("console.log(\"Generator state error\"); console.trace();"))
    df[0].add(BreakNode())
    sn.add(df)

    outernode = js_parse("""
    function() {
      var __gen_this2 = this;
      function _generator_iter() {
      }
      return new _generator_iter();
    }
  """,
                         start_node=FunctionNode)

    #add a self-referencing [Symbol.iterator] method
    n = js_parse("""
    this[Symbol.iterator] = function() {
      return this;
    }
  """)

    for c in n:
        node.add(c)

    #and, a es5.1-style forEach method
    n = js_parse("""
    this.forEach = function(callback, thisvar) {
      if (thisvar == undefined)
        thisvar = self;
      
      var _i = 0;
      
      while (1) {
        var ret = this.next();
        
        if (ret == undefined || ret.done || (ret._ret != undefined && ret._ret.done))
          break;
        
        callback.call(thisvar, ret.value);
        
        if (_i++ > 100) {
          console.log("inf loop", ret);
          break;
        }
      }
    }
  """)

    for c in n:
        node.add(c)

    outernode.name = node.name
    if node.is_anonymous:
        outernode.is_anonymous = True

    outernode.replace(outernode[0], node[0])
    node.parent.replace(node, outernode)
    node2 = outernode[2]

    cs = node[:]
    for c in cs[1:]:
        node2.add(c)
Ejemplo n.º 25
0
def visit_generators(node):
  if not node.is_generator: return
  
  def _remove_this(n):
    if n.val != "this": return
    
    if type(n.parent) != BinOpNode or n.parent.op != ".":
      #typespace.error("Can only reference members of 'this' in generators");
      n.val = "__gen_this2"
    else:
      n.val = "__gen_this2"
      #n.parent.parent.replace(n.parent, n.parent[1])
  
  def set_cur(n):
    if type(n) in [IfNode, WhileNode,
                   DoWhileNode, ForLoopNode, CatchNode]:
      n._cur = 1;
      n._startcur = 1;
    else:
      n._cur = 0
      n._startcur = 0
    
    n._start = True
    n._has_yield = node_has_yield(n)
    
    for c in n:
      set_cur(c)
  def prior_if(n):
    if n.parent == None: return None
    
    sl = n.parent
    i = sl.children.index(n)-1
    while 1:
      while i >= 0:
        if type(sl[i]) == IfNode:
          break
        i -= 1
        
      if i >= 0 or null_node(n.parent): break
      
      i = sl.parent.children.index(sl);
      sl = sl.parent;
      
    if i < 0:
      typespace.error("Orphaned else node", n)
      sys.exit(-1)
    
    return sl[i]
    
  def prior_try(n):
    if n.parent == None: return None
    
    sl = n.parent
    i = sl.children.index(n)-1
    while 1:
      while i >= 0:
        if type(sl[i]) == TryNode:
          break
        i -= 1
        
      if i >= 0 or null_node(n.parent): break
      
      i = sl.parent.children.index(sl);
      sl = sl.parent;
      
    if i < 0:
      typespace.error("Orphaned catch node", n)
      sys.exit(-1)
    
    return sl[i]
    
  def is_stype(n):
    ret = type(n) in stypes # and (n._has_yield or n.parent._has_yield)
    
    return ret
    
    if type(n) == CatchNode:
      ret |= prior_try(n)._has_yield
    if type(n) == ElseNode:
      ret |= prior_if(n)._has_yield
    
    if type(n) in [IfNode, ElseNode]:
      p5 = n.parent
      while not null_node(p5):
        if hasattr(p5, "_has_yield") and p5._has_yield:
          ret = True;
          break
        p5 = p5.parent
        
    return ret
  
  combine_if_else_nodes(node)
  
  traverse(node, ForCNode, unpack_for_c_loops, exclude=[FunctionNode], copy_children=True);
  traverse(node, IdentNode, _remove_this)
  traverse(node, VarDeclNode, _remove_this)
       
  frames = frame = Frame(node=node)
  
  stack = [c for c in node.children[1:]]
  stack.reverse()
  
  stypes = set([ForLoopNode, WhileNode, DoWhileNode, IfNode,
                ElseNode, TryNode, CatchNode])
  
  for c in stack: 
    set_cur(c)
  
  while len(stack) > 0:
    n = stack.pop(-1)
    
    if is_stype(n) or type(n) == StatementList:
      if n._start:
        if type(n) != StatementList:
          f = Frame(node=n)
          frame.append(f)
          frame = f
        n._start = False
      
      if n._cur < len(n.children):
        stack.append(n)
        stack.append(n[n._cur])
        n._cur += 1
      elif type(n) != StatementList:
        frame = frame.parent
    else:
      frame.append(n)
  
  def compact_frames(frames):
    i = 0
    frm = None
    while i < len(frames):
      f1 = frames[i]
      
      if type(f1) == YieldNode:
        frm = None
        
      if type(f1) != Frame:
        if frm == None:
          frm = Frame()
          frames.insert(i, frm)
          frm.parent = frames
          i += 1
          
        frames.remove(f1)
        i -= 1
        frm.append(f1)
      else:
        compact_frames(f1)
        frm = None
      
      if type(f1) == YieldNode:
        frm = None
        
      i += 1
      
  def label_frames(frames, cur=None):
    if cur == None: cur = [0]
    
    frames.label = cur[0]
    cur[0] += 1
    
    for f in frames:
      if type(f) == Frame:
        if f.node != None:
          f.node.frame = f
        label_frames(f, cur)
      else:
        f.frame = f
  
  def prop_frame_refs(node, f):
    if hasattr(node, "frame"): f = node.frame
    else: node.frame = f
    
    for c in node.children:
      prop_frame_refs(c, f)
      
  def apply_frame_scope(n, scope, frames):
    if type(n) == IdentNode:
      if n.val in scope:
        n.val = "scope.%s_%d" % (n.val, scope[n.val])
      else:
        p = n.parent
        n2 = n
        #check for implicit declarations within catch and loop nodes
        while not null_node(p):
          if type(p) in [CatchNode, WhileNode, ForLoopNode]: break
          n2 = p
          p = p.parent
          
        if not null_node(p) and n2 == p[0]:
          scope[n.val] = frames.label
          n.val = "scope.%s_%d" % (n.val, scope[n.val])
          
    elif type(n) == VarDeclNode:
      n.local = False;
      if "local" in n.modifiers: n.modifiers.remove("local")
      
      if hasattr(n.parent, "_c_loop_node"):
        frames = n.parent._c_loop_node.frame
        #print("yay", n.parent._c_loop_node.frame.label)
      
      if n.val not in scope:
        scope[n.val] = frames.label
      if n.val in scope:
        n.val = "scope.%s_%d" % (n.val, scope[n.val])
    for c in n.children:
      #ignore expr functions, but not nested functions?
      if type(c) == FunctionNode and type(c.parent) == AssignNode: continue
      if type(n) == BinOpNode and n.op == "." and c == n[1] and type(c) == IdentNode:
        continue
      if type(n) == FuncCallNode and type(c) == IdentNode and c == n[0]:
        continue
        
      apply_frame_scope(c, scope, frames)
        
  def frame_scope(frames, scope, depth=0):
    frames.scope = scope
    
    for f in frames:
      ss = "-"
      fstr = ""
      if type(f) == Frame:
        if f.node != None:
          fstr = f.node.get_line_str()
        else:
          if type(f[0]) == Frame: fstr = f[0].node.get_line_str()
          else: fstr = f[0].get_line_str()
        
        if f.node != None:
          ss = "+"
          scope2 = dict(scope)
          for i in range(f.node._startcur):
            apply_frame_scope(f.node[i], scope2, f)
          
          frame_scope(f, scope2, depth+1)
        else:
          frame_scope(f, scope, depth)
      else:
        fstr = f.get_line_str()
        apply_frame_scope(f, scope, frames)       
        
  scope = {}
  for a in node.children[0]:
    scope[a.val] = 0
  
  compact_frames(frames) 
  label_frames(frames)
  prop_frame_refs(node, frames)
  frame_scope(frames, scope)
  #print_frames(frames)
  
  def frames_validate(frames):
    def gen_frame_validate(frames, tlevel=0):
      s = ""
      tstr = tab(tlevel+1)
      tstr2 = tab(tlevel+2)
      
      for f in frames:
        if type(f) == Frame:
          if f.node != None:
            cs = f.node.children
            f.node.children = f.node.children[:node._startcur]
            f.node.add(ExprNode([]))
            
            c = f.node.gen_js(tlevel+1).split("\n")[0].replace("{", "").replace("\n", "").replace("}", "").strip()
            
            if c.endswith(";"): c = c[:-1]
            
            s += tstr + c + " {\n"
            f.node.children = cs
            
          s += gen_frame_validate(f, tlevel+1)
          if f.node != None:
            s += tstr + "}\n"
        else:
          c = tstr + f.gen_js(tlevel+2)
          s += c
          if c.strip().endswith("}") == 0 and c.strip().endswith(";") == 0:
            s += ";"
          s += "\n"
      
      if tlevel == 0:
        c = node.gen_js(0).split("\n")[0] + "\n"
        s = c + s + "}\n"
      return s
      
    #print(node.gen_js(0))
    #print(scope)
    #print_frames(frames)
    s = gen_frame_validate(frames)
    
    s2 = js_parse(s).gen_js(0).strip()
    s = node.gen_js(0).strip()
    s = js_parse(s, print_stack=False).gen_js(0).strip()
    
    print(s==s2)
    if s != s2:
      import difflib
      print(dir(difflib))
      d = difflib.ndiff(s.split("\n"), s2.split("\n"))
      ds = ""
      for l in d:
        ds += l + "\n"

      #print(ds)
      line_print(s)
      line_print(s2)
  
  #frames_validate(frames)
  
  flatframes = []
  def flatten_frames(frames):
    flatframes.append(frames)
    
    for f in frames:
      if type(f) == Frame:
        flatten_frames(f)
  
  flatten_frames(frames)
  #print([f.label for f in flatframes])
  
  def frames_transform(frames, node2):
    scope = frames.scope
  
  node2 = FunctionNode(node.name, node.lineno)
  node2.add(ExprListNode([]))
  
  for c in node.children[0]:
    node2[0].add(IdentNode(c.val))
  
  frames2 = frames
  
  for j, frames in enumerate(flatframes[1:]):
    p = frames.parent
    f = frames
    
    frames.return_frame = 0
    frames.return_frame_parent = 0
      
    i = p.index(f)      
    while i >= len(p)-1 and p.parent != None:
      f = p
      p = p.parent
      i = p.index(f)
    
    if p.parent == None:
      frames.return_frame = 0
      frames.return_frame_parent = p.label
    else:
      frames.return_frame = p[i+1].label      
      frames.return_frame_parent = p.label
  
  def f_name(f):
    return "frame_%d" % f.label
    
  def f_ref(f):
    return "this.frame_%d" % f.label

  def f_raw_next(f):
    if f.parent == None: 
       f = Frame()
       f.label = len(flatframes)
       return f
      
    while f.parent != None:
        i = f.parent.index(f)+1
        while i < len(f.parent):
          if type(f.parent[i]) == Frame:
            return f.parent[i]
          i += 1
          
        f = f.parent
        
    f = Frame()
    f.label = len(flatframes)
    return f
  
  def f_next(f, ignore_loops=False):
    if f.parent == None: 
      if debug_gen:
        print("no f.parent! make frame");
      
      f = Frame()
      f.label = len(flatframes)
      return f
      
    while f.parent != None:
      i = f.parent.index(f)+1
      
      while i < len(f.parent):
        if type(f.parent[i]) == Frame:
          if type(f.parent[i].node) not in [CatchNode, ElseNode]:
            return f.parent[i]
        i += 1
        
      if not ignore_loops and f.parent != None and \
         type(f.parent.node) in \
         [WhileNode, DoWhileNode, ForLoopNode]:
        if debug_gen:
          print("looper!", f.label, f.parent.label)
        return f.parent
      
      f = f.parent
      
    if debug_gen:
      print("made frame!", len(flatframes))
      
    f = Frame()
    f.label = len(flatframes)
    return f
    
  def f_first(f):
    for f2 in f:
      if type(f2) == Frame:
        return f2
    #return f
    
  def f_last(f):
    return f[-1]
  
  def has_parent(f, p):
    while f != p and f != None:
      f = f.parent
    return f == p
   
  def find_exit_points(f, p=None, vset=None):
    stack = []
    
    if p == None: p = f 
    if vset == None: vset = set()
    
    lst = []
    """
    lst = []
    for f2 in f:
      if type(f2) == Frame:
        for f3 in f2.paths:
          if type(f3) == Frame:
            if not has_parent(f3, p) and f3.label not in vset:
              lst.append(f3)
              vset.add(f3.label)
            lst += find_exit_points(f3, p, vset)
          else:
            continue
    """
    
    for f2 in f.paths:
      if not has_parent(f2, p) and f2.label not in vset:
        lst.append(f)
        vset.add(f.label)
      else:
        lst += find_exit_points(f2, p, vset)
    
    for f in lst:
      print(f.label)
      
    #sys.exit()
    return lst
    
  tot = len(node)-1
  for i in range(tot):
    node.pop(1)
  
  def param_var(k):
    for c in node[0]:
      val = c.gen_js(0)
      val = val.strip()
      k = k.strip()
      if k == val: return True  
    return False
    
  #build generator state data
  scopestr = "{"
  for k in scope:
    if scopestr != "{": scopestr += ", ";
    if param_var(k):
      scopestr += "%s_%i : %s" % (k, scope[k], k);
    else:
      scopestr += "%s_%i : %s" % (k, scope[k], "undefined");
  scopestr += "}"
  
  
  node.add(js_parse("this.scope = $s;", [scopestr], start_node=AssignNode))
  node.add(js_parse("this.ret = {done : false, value : undefined};", start_node=AssignNode))
  node.add(js_parse("this.state = 1;", start_node=AssignNode))
  node.add(js_parse("this.trystack = [];", start_node=AssignNode))
  
  node.add(js_parse("""
    this.next = function() {
      var ret;
      var stack = this.trystack;
      
      try {
        ret = this._next();
      } catch (err) {
        if (stack.length > 0) {
          var item = stack.pop(stack.length-1);
          this.state = item[0];
          this.scope[item[1]] = err;
          
          return this.next();
        } else {
          throw err;
        }
      }
      
      return ret;
    }""", start_node=AssignNode))
    
  node.add(js_parse("""
    this.push_trystack = function(catchstate, catchvar) {
      this.trystack.push([catchstate, catchvar]);
    }""", start_node=AssignNode))
    
  node.add(js_parse("""
    this.pop_trystack = function() {
      this.trystack.pop(this.trystack.length-1);
    }""", start_node=AssignNode))
 
  #build next function
  keynode = IdentNode("$__state");
  sn = SwitchNode(keynode);
  slist = js_parse("var $__ret = undefined; var $__state = this.state; var scope = this.scope;");
  
  slist2 = StatementList()
  slist2.add(sn)
  
  wn = WhileNode(BinOpNode(IdentNode("$__state"), NumLitNode(len(flatframes)), "<"))
  wn.add(slist2)
  
  wn[1].add(js_parse("""
    if ($__ret != undefined) {
      break;
    }
  """, start_node=IfNode));
  
  slist.add(wn);
  slist.add(js_parse("""
    if ($__ret != undefined) {
      this.ret.value = $__ret.value;
    } else {
      this.ret.done = true;
      this.ret.value = undefined;
    }
    
    this.state = $__state;
    return this.ret;
  """));
  
  next = js_parse("this._next = function() { };", start_node=AssignNode)
 
  next[1].add(slist)
  
  node.add(next)
  
  sn.line = slist.line = node.line
  sn.lexpos = slist.lexpos = node.lexpos
  
  #find leaves
  for f in flatframes:
    if len(f) > 0:
      f.leaf = True
      
      for c in f:
        if type(c) == Frame: 
          f.leaf = False
          break
  
  #move control frame of dowhile statements to
  #after their statement body frames.
  visit = set()
  for i in range(len(flatframes)):
    if i in visit: continue
    
    f = flatframes[i]
    
    if f.leaf or type(f.node) != DoWhileNode: continue
    
    f2 = f_first(f)
    if f2 == None: continue
    
    last = f2.label
    while (f2 != f_next(f) and f2 != f):
      last = f2.label
      f2 = f_next(f2)
    
    last = ((last-1) if last > i else last) + 1
    
    flatframes.pop(i);
    flatframes.insert(last, f);
    visit.add(last)
    
  for i, f in enumerate(flatframes):
    f.label = i
  
  #set up case statements
  for f in flatframes:
    n2 = CaseNode(NumLitNode(f.label))
    sl = StatementList()
    
    if debug_gen:
      sl.add(js_parse("console.log(\"in frame $s\");", [f.label]));
      
    #set line/lexpos data
    if f.node != None:
      n2.line = f.node.line
      n2.lexpos = f.node.lexpos
      sl.line = f.node.line
      sl.lexpos = f.node.lexpos
      
    f.case_sl = sl
    
    n2.add(sl)
    
    #add to switch statement
    sn.add(n2)
   
  def set_linepos(n, line, lexpos):
    n.line = line
    n.lexpos = lexpos
    for c in n:
      set_linepos(c, line, lexpos)
  
  for f in flatframes:
    if f.leaf:
      for c in f:
        c.frame = f
    else:
      f.node.frame = f
    
  #handle loop breaks/continues
  visit = set()
  def visit_breaks(n):
    wn = n
    
    if n in visit: return
    visit.add(n)
    
    while type(wn) not in [WhileNode, DoWhileNode, ForLoopNode]:
      if type(wn) == SwitchNode:
        typespace.error("Switches in generators not supported yet.", wn);
      wn = wn.parent
    
    if not wn:
      typespace.error("Invalid break statement.", n);
    
    if "frame" not in wn.__dict__:
      return
      
    f = wn.frame
    i = n.parent.index(n)
    
    n2 = js_parse("$s=$s;", ("$__state", f_next(f).label))
    
    if "frame" in n.__dict__:
      n.frame.insert(n.frame.index(n), n2)
    else:
      n.parent.insert(i, n2)
 
  def visit_continues(n):
    if n in visit: return
    visit.add(n)
    
    wn = n
    while wn != None and (type(wn) not in [WhileNode, DoWhileNode, ForLoopNode]):
      wn = wn.parent
    
    if wn == None:
      typespace.error("Invalid continue statement.", n);
    
    if "frame" not in wn.__dict__:
      return
      
    f = wn.frame
    i = n.parent.index(n)
    n2 = js_parse("$s=$s;", ("$__state", f.label));
    
    n3 = BreakNode();
    visit.add(n3)
    
    n.parent.remove(n)
    n.frame.replace(n, n2)
    n.frame.insert(n.frame.index(n2)+1, n3)
  
  def handle_yields(node):
    slist = js_parse("""$__ret = this.ret;""");
    
    is_empty = type(node[0]) == ExprNode and len(node[0]) == 0
    
    if is_empty:
      slist.add(js_parse("""$s.value = undefined;""", ["$__ret"], start_node=AssignNode));
    else:
      slist.add(js_parse("""$s.value = $n;""", ["$__ret", node[0]], start_node=AssignNode))
    
    slen = len(slist)
    #print(slist)
    
    if node in node.parent:
      i = node.parent.index(node)
      
      node.parent.remove(node)
      for j in range(slen):
        node.parent.insert(i, slist[slen-j-1])
    
    i = node.frame.index(node)
    node.frame.remove(node)
    for j in range(slen):
      node.frame.insert(i, slist[slen-j-1])
    
  #handle loop breaks
  for f in flatframes:
    if not f.leaf: continue;
    for c in f:
      traverse(c, BreakNode, visit_breaks, exclude=FunctionNode)
      pass
  #handle loop continues
  for f in flatframes:
    if not f.leaf: continue;
    for c in f:
      traverse(c, ContinueNode, visit_continues, exclude=FunctionNode)
      pass
      
  #handle yields
  for f in flatframes:
    if not f.leaf: continue
    for c in f:
      traverse(c, YieldNode, handle_yields, exclude=FunctionNode);
  
  def has_common_parent(n1, n2, p):
    while n1 != p and n1 != None:
      n1 = n1.parent
      
    while n2 != p and n2 != None:
      n2 = n2.parent
    
    if n1 == n2 and n1 == p: return True
    else: return False
    
  #build control code
  for f in flatframes:
    if f.leaf: continue
    n = f.node
    sl = f.case_sl
    
    if type(n) == IfNode:
      f2 = f_first(f)
      
      if f2 == None: #empty if node
        f2 = Frame()
        f2.label = len(flatframes)
        
      if len(n) > 2:
        f3 = n[2].frame
      else:
        f3 = f_next(f)
      
      f.paths += [f2, f3]
      
      n2 = js_parse("""
        $s = ($n) ? $s : $s;
      """, ["$__state", n[0], f2.label, f3.label]);
      
      set_linepos(n2, n.line, n.lexpos);
      sl.add(n2)
    elif type(n) == ElseNode:
      f2 = f_first(f)
      
      if f2 == None: #empty else node
        f2 = Frame()
        f2.label = len(flatframes)
        
      f.paths += [f2]
      
      n2 = js_parse(";$s = $s;", ("$__state", str(f2.label)))
      
      set_linepos(n2, n.line, n.lexpos);
      sl.add(n2)
    elif type(n) == WhileNode:
      f.paths += [f_first(f), f_next(f, False)]
      
      n2 = js_parse("""
        $s = ($n) ? $s : $s;
      """, ("$__state", n[0], f_first(f).label, f_next(f, False).label));
      
      set_linepos(n2, n.line, n.lexpos);
      sl.add(n2)
    elif type(n) == ForLoopNode:
      #okay, why did I say to ignore loops here?
      f.paths += [f_first(f), f_next(f, False)]
      
      if type(n[0]) == ForCNode:
        n2 = js_parse("""
          $s = ($n) ? $s : $s;
        """, ("$__state", n[0][1], f_first(f).label, f_next(f, False).label));
        
        set_linepos(n2, n.line, n.lexpos);
        sl.add(n2)
      else:
        typespace.error("process_generators expects unpacked iterator for loops")
    elif type(n) == DoWhileNode:
      f.paths += [f_first(f), f_next(f, False)]
      
      n2 = js_parse("""
        $s = ($n) ? $s : $s;
      """, ("$__state", n[0], f_first(f).label, f_next(f, False).label), start_node=AssignNode)
      
      set_linepos(n2, n.line, n.lexpos)
      sl.add(n2)
    elif type(n) == TryNode:
      f.paths += [f_first(f)]
      
      cn = f_raw_next(f).node
      if type(cn) != CatchNode:
        typespace.error("Missing catch block", f.node)
      
      ident = cn[0].gen_js(0).replace("scope.", "")
      
      n2 = js_parse("$s = $s;", ("$__state", f_first(f).label), start_node=AssignNode)
      n3 = js_parse("this.push_trystack($s, \"$s\");", [f_raw_next(f).label, ident])
      
      set_linepos(n2, n.line, n.lexpos)
      set_linepos(n3, n.line, n.lexpos)
      sl.add(n2)
      sl.add(n3)
    elif type(n) == CatchNode:
      f.paths += [f_first(f)]
      
      n2 = js_parse("$s = $s;", ("$__state", f_first(f).label), start_node=AssignNode)
      set_linepos(n2, n.line, n.lexpos)
      sl.add(n2)
    
  #build leaf code
  for f in flatframes:
    if not f.leaf: continue
    sl = f.case_sl
    
    for n in f:
      sl.add(n)
    
    f2 = f_next(f)
    sl.add(js_parse(";$s=$s;", ("$__state", str(f2.label))))
    f.paths += [f2]
    
  #add in pop_trystack calls
  for f in flatframes:
    if type(f.node) != TryNode: continue
    f2 = f_last(f)
    
    ps = find_exit_points(f)
    for f2 in ps:
      f2.case_sl.add(js_parse("this.pop_trystack();"))
    
  #add case breaks
  for f in flatframes:
    bn = BreakNode()
    bn.line = f.case_sl.line
    bn.lexpos = f.case_sl.lexpos
    f.case_sl.add(bn);
  
  #add final state case
  cn = CaseNode(NumLitNode(len(flatframes)))
  sl2 = StatementList()
  sl2.add(BreakNode())
  cn.add(sl2)
  sn.add(cn)
  
  #default case
  df = DefaultCaseNode()
  df.add(js_parse("console.log(\"Generator state error\"); console.trace();"))
  df[0].add(BreakNode())
  sn.add(df)
  
  outernode = js_parse("""
    function() {
      var __gen_this2 = this;
      function _generator_iter() {
      }
      return new _generator_iter();
    }
  """, start_node=FunctionNode);
  
  #add a self-referencing [Symbol.iterator] method
  n = js_parse("""
    this[Symbol.iterator] = function() {
      return this;
    }
  """);
  
  for c in n:
    node.add(c);
  
  #and, a es5.1-style forEach method
  n = js_parse("""
    this.forEach = function(callback, thisvar) {
      if (thisvar == undefined)
        thisvar = self;
      
      var _i = 0;
      
      while (1) {
        var ret = this.next();
        
        if (ret == undefined || ret.done || (ret._ret != undefined && ret._ret.done))
          break;
        
        callback.call(thisvar, ret.value);
        
        if (_i++ > 100) {
          console.log("inf loop", ret);
          break;
        }
      }
    }
  """);
  
  for c in n:
    node.add(c);
    
  outernode.name = node.name;
  if node.is_anonymous:
    outernode.is_anonymous = True
    
  outernode.replace(outernode[0], node[0])
  node.parent.replace(node, outernode);
  node2 = outernode[2]
  
  cs = node[:]
  for c in cs[1:]:
    node2.add(c)
Ejemplo n.º 26
0
if __name__ == "__main__":
  result = js_parse("""
    function bleh(a, b) {
      c = 0;
      d = 2;
      return e;
    }
    
    var a = bleh() + 3;
    var r = /a/g;
    if (a == 0) {
      b = b==0 ? c : a;
    } else if (b == 2) {
      console.log(c);
    }
    
    var obj = {a: b, c: 2};
    var arr = [0, 2, 3, 4];
    
    switch (a) {
      case 2:
        break;
      default:
        break;
    }
    
    function GArray(input) {
      Array<T>.call(this);
      b = 0;
    }
  """)
  
Ejemplo n.º 27
0
def handle_potential_class(result, ni, typespace):
  c = result[ni]
  op = c[0].gen_js(0).strip();
  
  name = c[1][0].gen_js(0).strip()

  if op == "inherit":
    parents = [c[1][1].gen_js(0).strip()];
  else:
    parents = []
  
  cls = ClassNode(name, parents)
  constructor = None
  
  i = ni-1
  while i >= 0:
    n = result[i]
    if type(n) == FunctionNode:
      if n.name == name:
        constructor = n
        break
        
    i -= 1
  
  if constructor == None:
    typespace.error("Could not find constructor for " + name + ".", result[ni])
  
  
  members = {}
  i = ni;
  m1 = js_parse("obj.prototype.func = {}");
  m2 = js_parse("obj.func = {}");
  while i < len(result):
    n = result[i];
    bad = type(n) != AssignNode
    bad |= type(n[1]) != FunctionNode
    
    if bad: 
      i += 1
      continue
    
    root = n[0]
    while type(root) == BinOpNode:
      root = root[0]
    
    bad = root.gen_js(0).strip() != name
    if bad:
      i += 1
      continue
    
    is_static = False
    if root.parent[1].gen_js(0) == "prototype":
      method_name = root.parent.parent[1].gen_js(0).strip()
    else:
      method_name = root.parent[1].gen_js(0).strip()
      is_static = True
    
    f = n[1]
    
    print(method_name)
    m = MethodNode(method_name)
    m.add(f[0])
    
    if len(f) > 2:
      s = StatementList()
      for c in f.children[1:]:
        s.add(c)
    else:
      m.add(f[1])
    cls.add(m)
    
    i += 1
  
  print(name, parents, constructor.name)
  
  if name != "ClassTest":
    sys.exit()
Ejemplo n.º 28
0
def module_transform(node, typespace):
  flatten_statementlists(node, typespace);
  
  depends = set()
  
  def at_root(n):
    p = n
    while p != None:
      if isinstance(p, FunctionNode):
        return False
      p = p.parent
    return True
 
  def varvisit(n, startn):
      return
      n2 = js_parse("""
        _es6_module.add_global('$s', $s);
      """, [n.val, n.val]);
      
      startn.parent.insert(startn.parent.index(startn)+1, n2);
      
      for n2 in n[2:]:
        varvisit(n2, startn);
  
  def exportvisit(n):
    if not at_root(n):
      typespace.error("Export statements cannot be within functions or classes", n)
    
    pi = n.parent.index(n)
    n.parent.remove(n)
    
    for n2 in n[:]:
      n.remove(n2)
      n.parent.insert(pi, n2)
      pi += 1
     
    if not n.is_default:
      n2 = js_parse("""
        $s = _es6_module.add_export('$s', $s);
      """, [n.name, n.name, n.name]);
    else: 
      n2 = js_parse("""
        $s = _es6_module.set_default_export('$s', $s);
      """, [n.name, n.name, n.name]);
      
    n.parent.insert(pi, n2)
    
  def exportfromvisit(n):
    n2 = js_parse("""
      import * as _$s1 from '$s1';
      
      for (var k in _$s1) {
        _es6_module.add_export(k, _$s1[k], true);
      }
    """, [n.name.val])
    
    n.parent.replace(n, n2)
  #print(node)

  #ahem.  if I do this one first, I can use  import statements in it :)
  #. . .also, how cool, it captures the dependencies, too

  traverse(node, ExportFromNode, exportfromvisit, copy_children=True);
  traverse(node, ExportNode, exportvisit, copy_children=True);
  
  #fetch explicit global variables
  globals = [];
  
  def kill_assignments(n):
    n.replace(n[0], ExprNode([]))
    for c in n:
      if type(c) == VarDeclNode:
        kill_assignments(c)
  
  def global_to_var(n):
    if type(n) == VarDeclNode and "global" in n.modifiers:
      n.modifiers.remove("global")
      n.modifiers.add("local")
      
    for c in n:
      global_to_var(c)
      
  def transform_into_assignments(n, parent, pi):
    if type(n) == VarDeclNode and not (type(n[0]) == ExprNode and len(n[0]) == 0):
      n2 = AssignNode(IdentNode(n.val), n[0])
      n.parent.remove(n)
      parent.insert(pi, n2)
      
    for c in n:
      transform_into_assignments(c, parent, pi)
      
  for c in node:
    if type(c) == VarDeclNode and "global" in c.modifiers:
      c2 = c.copy()
      kill_assignments(c2);
      global_to_var(c2);

      globals.append(c2)
      transform_into_assignments(c, c.parent, c.parent.index(c))
      
      
  #to maintain backward compatibility, add everything in module to
  #global namespace (for now).
  
  if 0:
    for n in node[:]:
      if type(n) in [ClassNode, FunctionNode]:
        n2 = js_parse("""
          $s = _es6_module.add_global('$s', $s);
        """, [n.name, n.name, n.name]);
        n.parent.insert(n.parent.index(n)+1, n2)
      elif type(n) == VarDeclNode:
        varvisit(n, n);
    
  def visit(n):
    if not at_root(n):
      typespace.error("Import statements cannot be within functions or classes", n)
      
    modname = n[0].val
    
    depends.add(modname)
    
    if len(n) == 1: #import module name
      n.parent.replace(n, js_parse("""
        es6_import(_es6_module, '$s');
      """, [modname]));
    else:
      slist = StatementList()
      n.parent.replace(n, slist)
      
      for n2 in n[1:]:
        if n2.name == "*":
          n3 = js_parse("""
            var $s = es6_import(_es6_module, '$s');
          """, [n2.bindname, modname]);
          
          slist.add(n3);
        else:
          n3 = js_parse("""
          var $s = es6_import_item(_es6_module, '$s', '$s');
          """, [n2.bindname, modname, n2.name]);
          
          slist.add(n3)
  
  traverse(node, ImportNode, visit)
  flatten_statementlists(node, typespace)
  
  def class_visit(n):
    n2 = js_parse("""
      _es6_module.add_class($s);
    """, [n.name])
    n.parent.insert(n.parent.index(n)+1, n2);
    
  traverse(node, ClassNode, class_visit)
  flatten_statementlists(node, typespace)
  
  deps = "["
  for i, d in enumerate(depends):
    if i > 0: 
      deps += ", "
      
    deps += '"'+d+'"'
  deps += "]"
  
  fname = glob.g_file
  if "/" in fname or "\\" in fname:
    fname = os.path.split(fname)[1]
  fname = fname.strip().replace("/", "").replace("\\", "").replace(".js", "")
  
  safe_fname = "_" + fname.replace(" ", "_").replace(".", "_").replace("-", "_") + "_module";
  
  header = "es6_module_define('"+fname+"', "+deps+", function " + safe_fname + "(_es6_module) {"
  header += "});";
  
  #print(header)
  
  node2 = js_parse(header)
  
  func = node2[0][1][2]
  
  for n in node:
    func.add(n)
    
  node.children = []
  for g in globals:
    node.add(g)
    
  node.add(node2)
  
  
  
Ejemplo n.º 29
0
def bleh():
  for frames in flatframes:
    fname = f_name(frames)
    n = js_parse("""
           function $s1(scope) {
            if (_do_frame_debug) console.log("in $s1");

           }""", (fname), start_node=FunctionNode)
    
    if type(n[1]) != StatementList:
      n.replace(n[1], StatementList())
    n = n[1]
    
    func = n
    while type(func) != FunctionNode:
      func = func.parent
    
    excl = (type(frames.node) == StatementList and type(frames.parent.node) == FunctionNode) 
    if frames.node != None and not excl and type(frames.node) != FunctionNode:
      f = frames
      
      sl = StatementList()
      f.node[f.node._startcur] = sl
        
    frames.funcnode = func
    frames.subnode = frames.funcnode
    
    local_frames = "["
    totframes = 0

    for i, f in enumerate(frames):
      if type(f) != Frame:
        frames.subnode.add(f)
        frames.leaf = True
        
      else:
        frames.leaf = False
        if len(local_frames) > 1: local_frames += ", "
        local_frames += f_ref(f) #.replace("this.", "")
        totframes += 1
        if f.node != None and type(f.node) != FunctionNode:
          if len(f.node.children) > f.node._startcur + 1:
            do_conv(f.node, f)
    
    if frames.leaf:
      f2 = f_next(frames)
      f2 = f2.label if f2 != -1 else -1
      frames.subnode.add(js_parse("return [$i, undefined];", [f2], start_node=ReturnNode));

    local_frames = "%s_frames = "%f_ref(frames) + local_frames + "];"
      
    frames.frames = js_parse(local_frames)
    frames.totframes = totframes

  def build_next(f, parent=None):
    if type(f) != Frame: 
      return
    
    subnode = f.subnode
    if f.label >= 0: # and f.label < 3:
      n2 = js_parse("this.$s1 = 0;", [f_name(f)], start_node=AssignNode)
      n2.replace(n2[1], f.funcnode)
      f.funcnode.name = "(anonymous)"
      f.funcnode.is_anonymous = True
      
      node2.add(n2) #f.funcnode)
        
    if f.totframes > 0:
      if f.node != None and type(f.node) == WhileNode:
        f2 = f_next(f)
        f2 = f2.label if f2 != -1 else -1
        n = js_parse("""
                     if (!"placeholder") {
                        return [$i1, undefined];
                     }
                     """, [f2])
        
        if n == None:
          typespace.error("internal error", subnode);
          
        n2 = find_node(n, StrLitNode);
        n2.parent.replace(n2, f.node[0])
        
        subnode.add(n)
        f2 = f_first(f);
        n.add(js_parse("return [$i, undefined];", [f2.label], start_node=ReturnNode))
      elif f.node != None and type(f.node) == TryNode:
        n = StatementList()
        
        if n == None:
          typespace.error("internal error", subnode);
        
        f3 = f_raw_next(f)
        while f3 != -1 and type(f3.node) != CatchNode:
          f3 = f_raw_next(f3);
        
        if f3 == -1:
          typespace.error("Orphaned try block", f.node)
        
        f3name = "_nfothing"
        if len(f3.node) > 0:
          f3name = f3.node[0].gen_js(0).replace("scope.", "")
          
        n.add(js_parse("""
           this.trystack.push([$i, "$s"]);
                        """, [f3.label, f3name]))
                        
        f2 = f_first(f);
        n.add(js_parse("return [$i, undefined];", [f2.label], start_node=ReturnNode))
        subnode.add(n)
        f2.pop_trystack = True
      elif f.node != None and type(f.node) == IfNode:
        f2 = f_first(f)
        f1 = f_raw_next(f)
        while type(f1.node) != ElseNode and f1.label != len(flatframes):
          f1 = f_raw_next(f1)
        
        if f1.label == len(flatframes):
          f1 = f_next(f)
        
        n = js_parse("""
          if (!("placeholder")) {
            return [$i1, undefined];
          } else {
            return [$i2, undefined];
          }
        """, [f1.label, f2.label]);
        
        n2 = find_node(n, StrLitNode)
        n2.parent.replace(n2, f.node[0].copy())
        
        if n == None:
          typespace.error("internal error", subnode);
        
        f2 = f_first(f);
        n.add(js_parse("return [$i, undefined];", [f2.label], start_node=ReturnNode))
        subnode.add(n)
        f2.pop_trystack = True
      elif f.node != None and type(f.node) == ElseNode:
        f2 = f_first(f)
        f1 = f_raw_next(f)
        while type(f1.node) != ElseNode and f1.label != len(flatframes):
          f1 = f_raw_next(f1)
        
        if f1.label == len(flatframes):
          f1 = f_next(f)
        
        n = js_parse("""
          return [$i1, undefined];
        """, [f2.label]);
        
        if n == None:
          typespace.error("internal error", subnode);
        
        f2 = f_first(f);
        subnode.add(n)
      elif f.node != None and type(f.node) == CatchNode:
        f2 = f_first(f)
        
        n = js_parse("""
          return [$i1, undefined];
        """, [f2.label]);
        
        if n == None:
          typespace.error("internal error", subnode);
        subnode.add(n)
      elif f.node != None and type(f.node) == ForLoopNode:
        f2 = f_first(f);
        f3 = f_next(f)
        
        f3 = f3.label if f2 != -1 else -1
        f2 = f2.label if f2 != -1 else -1
        
        n = js_parse("""
                     if ($n) {
                      return [$i, undefined];
                     } else {
                      return [$i, undefined];
                     }                       
                     """, [f.node[0][1], f2, f3])
        
        if n == None:
          typespace.error("internal error", subnode);
        
        subnode.add(n)
      
      
  node2.insert(1, js_parse("""
    this[Symbol.iterator] = function() {
      return this;
    }
  """)[0])
  for f in flatframes:
    build_next(f, f.parent)
  
  #process returns from within try nodes
  for f in flatframes:
    if f.parent != None and type(f.parent.node) == TryNode:
      def visit_rets1(n2):
        target = n2[0][0][0].val
        isyield = n2[0][0][1].val
        ni = n2.parent.index(n2)
        
        if target >= f_next(f.parent).label:
          n3 = js_parse("this.trystack.pop();")[0]
          n2.parent.insert(ni, n3)
        
      traverse(f.subnode, ReturnNode, visit_rets1, copy_children=True);

  #process yields
  for f in flatframes:
    f2 = f.parent
    set_yield = None
    
    def visit_rets2(n2):
      if set_yield != None:
        #print(n2)
        n2[0][0].replace(n2[0][0][1], set_yield);
        
    set_yield = find_node(f.subnode, YieldNode);
    if set_yield != None:
      set_yield.parent.remove(set_yield);
      set_yield = ArrayLitNode(ExprListNode([set_yield[0]]))
      
    traverse(f.subnode, ReturnNode, visit_rets2, copy_children=True);
  
  def find_parent_frame(f, ntypes, include_first=True):
    p = f
    if not include_first:
      p = p.parent
      
    while p != None:
      if type(p.node) in ntypes:
        return p
      p = p.parent
    return None
    
  #process breaks
  for f in flatframes:
    f2 = f.parent
    
    def visit_rets3(n2):
      p = n2.parent
      while not null_node(p) and p != f.subnode:
        if type(p) in [WhileNode, DoWhileNode, ForLoopNode]: break
        p = p.parent
        
      if p != f.subnode and not null_node(p): return #break corresponds to a loop internal to this frame
      p = find_parent_frame(f, [WhileNode, DoWhileNode, ForLoopNode], True)
        
      if p == None:
        typespace.error("Invalid break statement (switches within generators aren't supported yet)", n2)
      
      
      f2 = f_next(p)
        
      n3 = js_parse("return [$i, undefined];", [f2.label], start_node=ReturnNode);
      n2.parent.replace(n2, n3)
      
    traverse(f.subnode, BreakNode, visit_rets3, copy_children=True);

  #process continues
  for f in flatframes:
    f2 = f.parent
    
    def visit_rets3(n2):
      p = n2.parent
      while not null_node(p) and p != f.subnode:
        p = p.parent
        
      if p != f.subnode and not null_node(p): return #continue corresponds to a loop internal to this frame
      p = f.parent
      while p != None:
        if type(p.node) in [WhileNode, DoWhileNode, ForLoopNode]:
          break;
        p = p.parent
        
      if p == None:
        typespace.error("Invalid continue statement")
      
      n3 = js_parse("return [$i, undefined];", [p.label], start_node=ReturnNode);
      n2.parent.replace(n2, n3)
      
    traverse(f.subnode, ContinueNode, visit_rets3, copy_children=True);

  firstnode = js_parse("if (this.first) {\n}", start_node=IfNode)
  firstnode2 = js_parse("if (this.first) {\n}", start_node=IfNode)
  firstnode.replace(firstnode[1], StatementList())
  firstnode2.replace(firstnode2[1], StatementList())
  flatframes[0].subnode.add(firstnode);
  node2.insert(1, firstnode2[1]);

  firstnode = firstnode[1]
  firstnode2 = firstnode2[1]
  
  args = list(node.children[0])
  for i3 in range(len(args)):
    argn = args[i3]
    while type(argn) not in [IdentNode, VarDeclNode]:
      argn = argn[0]
   
    args[i3] = argn.val
  
  scope = {}
  for f in flatframes:
    scope.update(f.scope)
  
  s = "{"
  j2 = 0
  for j, v in enumerate(scope.keys()):
    if j2 > 0: s += ", "
    j2 += 1
    
    if v in args:
      s += "%s:%s" % ("%s_%s"%(v, scope[v]), v)
    else:
      s += "%s:undefined" % ("%s_%s"%(v, scope[v]))
  s += "}"
    
  s = "this.scope = %s;\n" % s
  firstnode2.add(js_parse(s)[0])
  
  #ensure all frames have returns
  for f in flatframes:
    if not find_node(f.subnode, ReturnNode):
      f.subnode.add(js_parse("return [$i, undefined];", [f_next(f).label], start_node=ReturnNode));
    
  framelist = "["
  for i, f in enumerate(flatframes):
    if i > 0: framelist += ", "
    framelist += "this.frame_%i" % f.label
  framelist = "this.frames = %s];"%framelist
  node2.add(js_parse(framelist));
  
  node2.add(js_parse("""
    this.cur = 1;
    this.trystack = new Array();
    
    this.next = function() {
      var ret;
      while (this.cur < this.frames.length) {
        try {
          ret = this.frames[this.cur].call(this, this.scope);
        } catch (_generator_error) {
          if (this.trystack.length > 0) {
            var ts1 = this.trystack.pop();
            
            this.scope[ts1[1]] = _generator_error;
            
            ret = [ts1[0], undefined];
          } else {
            throw _generator_error;
          }
        }
        
        if (ret[0] == this.frames.length) {
          return {done : true, value : undefined};
          break;
        }
        
        if (ret[0] == this.cur) {
          console.trace();
          console.log("YEEK!")
          return {done : true, value : undefined};
        }
        
        this.cur = ret[0];
        
        if (ret[1] != undefined) {
          return {value : ret[1][0], done : false};
        } else {
          return {value : undefined, done : false};
        }
      }
    }
  """, []))
  
  node.parent.replace(node, node2)
Ejemplo n.º 30
0
    def __init__(self):
        self.functions = {}
        self.types = {}
        self.globals = {}
        self.logrec = []
        self.logmap = {}
        self.builtin_typenames = builtin_types
        self.func_excludes = set(["inherit", "inherit_multiple", "define_static", "create_prototype", "prior"])

        self.functions["inherit"] = js_parse(
            "function inherit(Object a, Object b) : void { };", start_node=FunctionNode
        )

        for t in builtin_types:
            n = BuiltinTypeNode(t)
            n.ret = "class"
            n.members = {}

            # """
            if t in builtin_code:
                fn = js_parse(builtin_code[t], exit_on_err=False, start_node=FunctionNode)
                if fn == None:
                    sys.stderr.write("Warning: could not compile internal type code in JSTypeSpace.__init__\n")
                    # self.error("js_parse error", n);
                    glob.g_error = False
                    return
                else:
                    self.types[fn.name] = fn
                    for n in fn.children[1:]:
                        if (
                            type(n) == AssignNode
                            and type(n[0]) == BinOpNode
                            and n[0].op == "."
                            and type(n[0][0]) == IdentNode
                            and n[0][0].val == "this"
                            and type(n[0][1]) == IdentNode
                        ):

                            if type(n[1]) == FunctionNode and n.type == None:
                                n.type = VoidTypeNode()

                            if n[1].type != None:
                                fn.members[n[0][1].val] = n[1].type
                            else:
                                fn.members[n[0][1].val] = n.type
            else:
                if t != "Object":
                    fn = js_parse("function %s(value) {};" % t, exit_on_err=False, start_node=FunctionNode)
                elif t != "undefined":
                    fn = js_parse("function %s() {};" % t, exit_on_err=False, start_node=FunctionNode)
            """
      fn = None
      #"""

            if fn == None or len(fn.children) == 0:
                sys.stderr.write("Warning: could not compile internal type code in JSTypeSpace.__init__\n")
                # self.error("js_parse error", n);
                glob.g_error = False
                return
            else:
                while fn != None and type(fn) != FunctionNode and len(fn.children) > 0:
                    fn = fn.children[0]

                if type(fn) != FunctionNode:
                    sys.stderr.write("\nWarning: could not compile internal type code in JSTypeSpace.__init__\n")
                    return
                if t == "Array":
                    fn.class_type = "array"
                else:
                    fn.class_type = "class"

                fn.is_builtin = True
                fn.is_native = True
                fn.ret = n
                self.functions[t] = fn
                self.types[t] = fn

        funcs = self.functions
        funcs["Number"].add_class_child(funcs["Boolean"])
        funcs["Array"].add_class_child(funcs["String"])
        funcs["CanIterate"].add_class_child(funcs["Array"])
        funcs["CanIterate"].add_class_child(funcs["ObjectMap"])
        for k in funcs:
            if k == "Object":
                continue

            f = funcs[k]
            if f.class_parent == None:
                funcs["Object"].add_class_child(f)
Ejemplo n.º 31
0
 def __init__(self):
   self.functions = {}
   self.types = {}
   self.globals = {}
   self.logrec = []
   self.logmap = {}
   self.builtin_typenames = builtin_types
   self.func_excludes = set(["inherit", "inherit_multiple", "define_static", "create_prototype", "prior"])
   
   self.functions["inherit"] = js_parse("function inherit(Object a, Object b) : void { };", start_node=FunctionNode)
   
   for t in builtin_types:
     n = BuiltinTypeNode(t)
     n.ret = "class"
     n.members = {}
     
     #"""
     if t in builtin_code:
       fn = js_parse(builtin_code[t], exit_on_err=False, start_node=FunctionNode);
       if fn == None:
         sys.stderr.write("Warning: could not compile internal type code in JSTypeSpace.__init__\n")
         #self.error("js_parse error", n);
         glob.g_error = False
         return
       else:
         self.types[fn.name] = fn
         for n in fn.children[1:]:
           if type(n) == AssignNode and type(n[0]) == BinOpNode and \
             n[0].op == "." and type(n[0][0]) == IdentNode and n[0][0].val == "this" \
              and type(n[0][1]) == IdentNode:
              
             if type(n[1]) == FunctionNode and n.type == None:
               n.type = VoidTypeNode()
               
             if n[1].type != None:
               fn.members[n[0][1].val] = n[1].type
             else:
               fn.members[n[0][1].val] = n.type
     else:
       if t != "Object":
         fn = js_parse("function %s(value) {};"%t, exit_on_err=False, start_node=FunctionNode);
       elif t != "undefined":
         fn = js_parse("function %s() {};"%t, exit_on_err=False, start_node=FunctionNode);
     """
     fn = None
     #"""
     
     if fn == None or len(fn.children) == 0:
       sys.stderr.write("Warning: could not compile internal type code in JSTypeSpace.__init__\n")
       #self.error("js_parse error", n);
       glob.g_error = False
       return
     else:
       while fn != None and type(fn) != FunctionNode and len(fn.children) > 0:
         fn = fn.children[0]
       
       if type(fn) != FunctionNode:
         sys.stderr.write("\nWarning: could not compile internal type code in JSTypeSpace.__init__\n")
         return
       if t == "Array":
         fn.class_type = "array"
       else:
         fn.class_type = "class"
       
       fn.is_builtin = True
       fn.is_native = True
       fn.ret = n
       self.functions[t] = fn
       self.types[t] = fn
   
   funcs = self.functions
   funcs["Number"].add_class_child(funcs["Boolean"])
   funcs["Array"].add_class_child(funcs["String"])
   funcs["CanIterate"].add_class_child(funcs["Array"])
   funcs["CanIterate"].add_class_child(funcs["ObjectMap"])
   for k in funcs:
     if k == "Object": continue
     
     f = funcs[k]
     if f.class_parent == None:
       funcs["Object"].add_class_child(f)
Ejemplo n.º 32
0
def create_type_logger(node, typespace):
    flatten_statementlists(node, typespace)


    for i, s in enumerate(node):
        if i > 5:
            break;

        if s.gen_js(0).strip() in ["'no_type_logging'", '"no_type_logging"', "`no_type_logging`"]:
            return []



    def visit(n):
        args = []
        for c in n[0]:
            n2 = js_parse("""
                _log_types($s1, $s2, $s3, $s4, $s5, $s6, $s7);
            """, ['"'+n.file+'"', str(n.line), '`'+buildkey(n)+'`', '`'+str(c.val)+'`', str(c.val),
            n.lexpos, n.lexpos2]);

            args.append(n2)

        for arg in args:
            if len(n) == 2 and type(n[1]) == StatementList:
                n[1].insert(0, arg)
            else:
                n.insert(1, arg)


    def retvisit(n):
        val = None

        if len(n) == 0 or n[0].gen_js(0).strip() == "":
            val = IdentNode("undefined")
        else:
            val = n[0]

        n2 = js_parse("""_log_return($s1, $s2, $s3, $n4, $s5, $s6)""",
                ['"'+n.file+'"', str(n.line), '`'+buildkey(n)+'`', val, n.lexpos, n.lexpos2],
                start_node=FuncCallNode)

        if len(n) == 0:
            n.append(n2)
        else:
            n.replace(n[0], n2)

    traverse(node, FunctionNode, visit)
    traverse(node, MethodNode, visit)
    traverse(node, MethodGetter, visit)
    traverse(node, MethodSetter, visit)
    traverse(node, ObjLitSetGet, visit)
    traverse(node, ReturnNode, retvisit)

    prefix = js_parse(loggercode)
    oldprefix = None

    if len(node) > 0 and "not_a_module" in node[0].gen_js(0):
        oldprefix = StrLitNode("'not_a_module'")

    node.prepend(prefix)
    if oldprefix is not None:
        node.prepend(oldprefix)

    flatten_statementlists(node, typespace);
Ejemplo n.º 33
0
def module_transform(node, typespace):
    flatten_statementlists(node, typespace)

    depends = set()

    def at_root(n):
        p = n
        while p != None:
            if isinstance(p, FunctionNode):
                return False
            p = p.parent
        return True

    def varvisit(n, startn):
        return
        n2 = js_parse("""
        _es6_module.add_global('$s', $s);
      """, [n.val, n.val])

        startn.parent.insert(startn.parent.index(startn) + 1, n2)

        for n2 in n[2:]:
            varvisit(n2, startn)

    def exportvisit(n):
        if not at_root(n):
            typespace.error(
                "Export statements cannot be within functions or classes", n)

        pi = n.parent.index(n)
        n.parent.remove(n)

        for n2 in n[:]:
            n.remove(n2)
            n.parent.insert(pi, n2)
            pi += 1

        if not n.is_default:
            n2 = js_parse(
                """
        $s = _es6_module.add_export('$s', $s);
      """, [n.name, n.name, n.name])
        else:
            n2 = js_parse(
                """
        $s = _es6_module.set_default_export('$s', $s);
      """, [n.name, n.name, n.name])

        n.parent.insert(pi, n2)

    def exportfromvisit(n):
        n2 = js_parse(
            """
      import * as _$s1 from '$s1';
      
      for (var k in _$s1) {
        _es6_module.add_export(k, _$s1[k], true);
      }
    """, [n.name.val])

        n.parent.replace(n, n2)

    #print(node)

    #ahem.  if I do this one first, I can use  import statements in it :)
    #. . .also, how cool, it captures the dependencies, too

    traverse(node, ExportFromNode, exportfromvisit, copy_children=True)
    traverse(node, ExportNode, exportvisit, copy_children=True)

    #fetch explicit global variables
    globals = []

    def kill_assignments(n):
        n.replace(n[0], ExprNode([]))
        for c in n:
            if type(c) == VarDeclNode:
                kill_assignments(c)

    def global_to_var(n):
        if type(n) == VarDeclNode and "global" in n.modifiers:
            n.modifiers.remove("global")
            n.modifiers.add("local")

        for c in n:
            global_to_var(c)

    def transform_into_assignments(n, parent, pi):
        if type(n) == VarDeclNode and not (type(n[0]) == ExprNode
                                           and len(n[0]) == 0):
            n2 = AssignNode(IdentNode(n.val), n[0])
            n.parent.remove(n)
            parent.insert(pi, n2)

        for c in n:
            transform_into_assignments(c, parent, pi)

    for c in node:
        if type(c) == VarDeclNode and "global" in c.modifiers:
            c2 = c.copy()
            kill_assignments(c2)
            global_to_var(c2)

            globals.append(c2)
            transform_into_assignments(c, c.parent, c.parent.index(c))

    #to maintain backward compatibility, add everything in module to
    #global namespace (for now).

    if glob.g_autoglobalize:
        for n in node[:]:
            if type(n) in [ClassNode, FunctionNode, VarDeclNode]:
                if type(n) == VarDeclNode:
                    nname = n.val
                else:
                    nname = n.name

                n2 = js_parse(
                    """
          $s = _es6_module.add_global('$s', $s);
        """, [nname, nname, nname])
                n.parent.insert(n.parent.index(n) + 1, n2)
            elif type(n) == VarDeclNode:
                varvisit(n, n)

    def visit(n):
        if not at_root(n):
            typespace.error(
                "Import statements cannot be within functions or classes", n)

        modname = n[0].val

        depends.add(modname)

        if len(n) == 1:  #import module name
            n.parent.replace(
                n,
                js_parse("""
        es6_import(_es6_module, '$s');
      """, [modname]))
        else:
            slist = StatementList()
            n.parent.replace(n, slist)

            for n2 in n[1:]:
                if n2.name == "*":
                    n3 = js_parse(
                        """
            var $s = es6_import(_es6_module, '$s');
          """, [n2.bindname, modname])

                    slist.add(n3)
                else:
                    n3 = js_parse(
                        """
          var $s = es6_import_item(_es6_module, '$s', '$s');
          """, [n2.bindname, modname, n2.name])

                    slist.add(n3)

    traverse(node, ImportNode, visit)
    flatten_statementlists(node, typespace)

    def class_visit(n):
        n2 = js_parse("""
      _es6_module.add_class($s);
    """, [n.name])
        n.parent.insert(n.parent.index(n) + 1, n2)

    traverse(node, ClassNode, class_visit)
    flatten_statementlists(node, typespace)

    deps = "["
    for i, d in enumerate(depends):
        if i > 0:
            deps += ", "

        deps += '"' + d + '"'
    deps += "]"

    fname = glob.g_file
    if "/" in fname or "\\" in fname:
        fname = os.path.split(fname)[1]
    fname = fname.strip().replace("/", "").replace("\\", "").replace(".js", "")

    safe_fname = "_" + fname.replace(" ", "_").replace(".", "_").replace(
        "-", "_") + "_module"

    header = "es6_module_define('" + fname + "', " + deps + ", function " + safe_fname + "(_es6_module) {"
    header += "});"

    #print(header)

    node2 = js_parse(header)

    func = node2[0][1][2]

    for n in node:
        func.add(n)

    node.children = []
    for g in globals:
        node.add(g)

    node.add(node2)
Ejemplo n.º 34
0
 def build_next(f, parent=None):
   if type(f) != Frame: 
     return
   
   subnode = f.subnode
   if f.label >= 0: # and f.label < 3:
     n2 = js_parse("this.$s1 = 0;", [f_name(f)], start_node=AssignNode)
     n2.replace(n2[1], f.funcnode)
     f.funcnode.name = "(anonymous)"
     f.funcnode.is_anonymous = True
     
     node2.add(n2) #f.funcnode)
       
   if f.totframes > 0:
     if f.node != None and type(f.node) == WhileNode:
       f2 = f_next(f)
       f2 = f2.label if f2 != -1 else -1
       n = js_parse("""
                    if (!"placeholder") {
                       return [$i1, undefined];
                    }
                    """, [f2])
       
       if n == None:
         typespace.error("internal error", subnode);
         
       n2 = find_node(n, StrLitNode);
       n2.parent.replace(n2, f.node[0])
       
       subnode.add(n)
       f2 = f_first(f);
       n.add(js_parse("return [$i, undefined];", [f2.label], start_node=ReturnNode))
     elif f.node != None and type(f.node) == TryNode:
       n = StatementList()
       
       if n == None:
         typespace.error("internal error", subnode);
       
       f3 = f_raw_next(f)
       while f3 != -1 and type(f3.node) != CatchNode:
         f3 = f_raw_next(f3);
       
       if f3 == -1:
         typespace.error("Orphaned try block", f.node)
       
       f3name = "_nfothing"
       if len(f3.node) > 0:
         f3name = f3.node[0].gen_js(0).replace("scope.", "")
         
       n.add(js_parse("""
          this.trystack.push([$i, "$s"]);
                       """, [f3.label, f3name]))
                       
       f2 = f_first(f);
       n.add(js_parse("return [$i, undefined];", [f2.label], start_node=ReturnNode))
       subnode.add(n)
       f2.pop_trystack = True
     elif f.node != None and type(f.node) == IfNode:
       f2 = f_first(f)
       f1 = f_raw_next(f)
       while type(f1.node) != ElseNode and f1.label != len(flatframes):
         f1 = f_raw_next(f1)
       
       if f1.label == len(flatframes):
         f1 = f_next(f)
       
       n = js_parse("""
         if (!("placeholder")) {
           return [$i1, undefined];
         } else {
           return [$i2, undefined];
         }
       """, [f1.label, f2.label]);
       
       n2 = find_node(n, StrLitNode)
       n2.parent.replace(n2, f.node[0].copy())
       
       if n == None:
         typespace.error("internal error", subnode);
       
       f2 = f_first(f);
       n.add(js_parse("return [$i, undefined];", [f2.label], start_node=ReturnNode))
       subnode.add(n)
       f2.pop_trystack = True
     elif f.node != None and type(f.node) == ElseNode:
       f2 = f_first(f)
       f1 = f_raw_next(f)
       while type(f1.node) != ElseNode and f1.label != len(flatframes):
         f1 = f_raw_next(f1)
       
       if f1.label == len(flatframes):
         f1 = f_next(f)
       
       n = js_parse("""
         return [$i1, undefined];
       """, [f2.label]);
       
       if n == None:
         typespace.error("internal error", subnode);
       
       f2 = f_first(f);
       subnode.add(n)
     elif f.node != None and type(f.node) == CatchNode:
       f2 = f_first(f)
       
       n = js_parse("""
         return [$i1, undefined];
       """, [f2.label]);
       
       if n == None:
         typespace.error("internal error", subnode);
       subnode.add(n)
     elif f.node != None and type(f.node) == ForLoopNode:
       f2 = f_first(f);
       f3 = f_next(f)
       
       f3 = f3.label if f2 != -1 else -1
       f2 = f2.label if f2 != -1 else -1
       
       n = js_parse("""
                    if ($n) {
                     return [$i, undefined];
                    } else {
                     return [$i, undefined];
                    }                       
                    """, [f.node[0][1], f2, f3])
       
       if n == None:
         typespace.error("internal error", subnode);
       
       subnode.add(n)