Esempio n. 1
0
def combine_try_nodes(node):
    def visit(n):
        if type(n.parent) == TryNode: return

        sl = n.parent

        i = sl.children.index(n)
        i -= 1

        #we remove n here, since we may have to ascend through
        #several layers of StatementList nodes
        sl.children.remove(n)
        while 1:
            while i >= 0:
                if type(sl[i]) == TryNode:
                    break
                i -= 1

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

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

        if i < 0:
            sys.stderr.write("%s:(%d): error: orphaned catch block\n" %
                             (n.file, n.line))
            sys.exit(-1)

        tn = sl[i]
        tn.add(n)

    traverse(node, CatchNode, visit, copy_children=True)
Esempio n. 2
0
 def AssignNode(self, node, traverse):
   self.out("push ")
   traverse(node[0])
   self.out("\npush ")
   traverse(node[1])
   self.out("\n")
   self.out("set\n")
Esempio n. 3
0
 def AssignNode(self, node, traverse):
     self.out("push ")
     traverse(node[0])
     self.out("\npush ")
     traverse(node[1])
     self.out("\n")
     self.out("set\n")
Esempio n. 4
0
def unpack_for_c_loops(node):
    start = node.children[0]

    if node.parent.parent == None:
        return
    p = node.parent.parent

    i = node.parent.parent.children.index(node.parent)
    node.replace(start, ExprNode([]))
    node.parent.parent.insert(i, start)
    start._c_loop_node = node

    if type(node.parent[1]) != StatementList:
        sl = StatementList()
        sl.add(node.parent[1])
        node.parent.replace(node.parent[1], sl)

    sl = node.parent[1]
    inc = node[2]
    node.replace(inc, ExprNode([]))
    sl.add(inc)

    def handle_continues(n):
        if type(n.parent) != StatementList:
            sl = StatementList()
            n.parent.replace(n, sl)
            sl.add(n)

        n.parent.insert(n.parent.index(n), inc.copy())

    traverse(node.parent, ContinueNode, handle_continues, exclude=[FunctionNode], copy_children=True)

    node.parent[1]
Esempio n. 5
0
def combine_try_nodes(node):
    def visit(n):
        if type(n.parent) == TryNode:
            return

        sl = n.parent

        i = sl.children.index(n)
        i -= 1

        # we remove n here, since we may have to ascend through
        # several layers of StatementList nodes
        sl.children.remove(n)
        while 1:
            while i >= 0:
                if type(sl[i]) == TryNode:
                    break
                i -= 1

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

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

        if i < 0:
            sys.stderr.write("%s:(%d): error: orphaned catch block\n" % (n.file, n.line))
            sys.exit(-1)

        tn = sl[i]
        tn.add(n)

    traverse(node, CatchNode, visit, copy_children=True)
Esempio n. 6
0
    def ArrayRefNode(self, node, traverse):
        self.out("push object ")
        traverse(node[0])
        self.out("\n")

        self.out("push ")
        traverse(node[1])
        self.out("\n")
Esempio n. 7
0
 def ArrayRefNode(self, node, traverse):
   self.out("push object ")
   traverse(node[0])
   self.out("\n")
   
   self.out("push ")
   traverse(node[1])
   self.out("\n")
Esempio n. 8
0
    def IfWithElse(self, node, traverse):
        endlabel = self.templabel("if")
        self.ifstack.append(endlabel)

        self.IfWithoutElse(node, traverse)
        for c in node[2:]:
            traverse(c)

        self.out(";end of if chain\n")
        self.out(endlabel + ":\n")
Esempio n. 9
0
 def IfWithElse(self, node, traverse):
   endlabel = self.templabel("if")
   self.ifstack.append(endlabel)
   
   self.IfWithoutElse(node, traverse)
   for c in node[2:]:
     traverse(c)
   
   self.out(";end of if chain\n");
   self.out(endlabel + ":\n")
Esempio n. 10
0
    def addIterEnds(node):
        def visit(n):
            sn = StatementList()
            sn.force_block = True

            n.parent.replace(n, sn)
            sn.add(js_parse(onIterEnd))
            sn.add(n)

        traverse(node, ReturnNode, visit)
Esempio n. 11
0
def inside_generator(node):
  p = node
  while p.parent != None and not isinstance(p, FunctionNode):
    p = p.parent
  
  found = [0]
  def findyield(n):
    found[0] = 1
    
  traverse(p, YieldNode, findyield)
  
  return found[0]
Esempio n. 12
0
 def FuncCallNode(self, node, traverse):
   #self.tlevel += 1
   
   self.out(";BEGIN_CALL calc & push function pointer\n")
   if type(node[0]) == IdentNode:
     self.out("push " + node[0].val + "\n")
   else:
     traverse(node[0])
   
   self.out(";push this\n");
   
   #see if we have a this on the stack
   if type(node[0]) == BinOpNode and node[0].op == ".":
     #so, we should have this value on stack already
     #actually, stack should be:
     # |
     # V
     # function
     # this value
     #
     
     #transform to:
     #
     # function
     # this value
     # function
     # this value
     self.out("dup2;\n")
     
     #remove extraneous stack entry
     #
     # function
     # this value
     # this value
     self.out("drop;\n")
     self.out("swap;\n")
     
     #stack should now have this is right place (hopefully)
   else:
     self.out("push undefined\n")
     self.out("swap\n")
     
   self.out(";push arguments\n");
   for i in range(len(node[1])):
     self.out("push ")
     traverse(node[1][i])
     self.out("\n")
   
   self.out("call %i\n" % len(node[1]))
   
   #self.tlevel -= 1
   pass
Esempio n. 13
0
    def FuncCallNode(self, node, traverse):
        #self.tlevel += 1

        self.out(";BEGIN_CALL calc & push function pointer\n")
        if type(node[0]) == IdentNode:
            self.out("push " + node[0].val + "\n")
        else:
            traverse(node[0])

        self.out(";push this\n")

        #see if we have a this on the stack
        if type(node[0]) == BinOpNode and node[0].op == ".":
            #so, we should have this value on stack already
            #actually, stack should be:
            # |
            # V
            # function
            # this value
            #

            #transform to:
            #
            # function
            # this value
            # function
            # this value
            self.out("dup2;\n")

            #remove extraneous stack entry
            #
            # function
            # this value
            # this value
            self.out("drop;\n")
            self.out("swap;\n")

            #stack should now have this is right place (hopefully)
        else:
            self.out("push undefined\n")
            self.out("swap\n")

        self.out(";push arguments\n")
        for i in range(len(node[1])):
            self.out("push ")
            traverse(node[1][i])
            self.out("\n")

        self.out("call %i\n" % len(node[1]))

        #self.tlevel -= 1
        pass
Esempio n. 14
0
def inside_generator(node):
    p = node
    while p.parent != None and not isinstance(p, FunctionNode):
        p = p.parent

    found = [0]

    def findyield(n):
        found[0] = 1

    traverse(p, YieldNode, findyield)

    return found[0]
Esempio n. 15
0
    def IfWithoutElse(self, node, traverse):
        self.out("\n;if (" + node[0].gen_js(0) + ")\n")
        traverse(node[0])
        label = self.templabel("if")
        self.out("jz " + label + "\n\n")
        traverse(node[1])

        if type(node.parent) == ElseIfNode:
            print(self.ifstack)
            self.out(";escape if chain\n")
            self.out("jmp " + self.ifstack[-1] + "\n")

        self.out("\n" + label + ":\n")
Esempio n. 16
0
 def IfWithoutElse(self, node, traverse):
   self.out("\n;if (" + node[0].gen_js(0) + ")\n")
   traverse(node[0])
   label = self.templabel("if")
   self.out("jz " + label + "\n\n")
   traverse(node[1])
   
   if type(node.parent) == ElseIfNode:
     print(self.ifstack)
     self.out(";escape if chain\n");
     self.out("jmp " + self.ifstack[-1] + "\n")
     
   self.out("\n" + label + ":\n");
Esempio n. 17
0
def combine_if_else_nodes(node):
    vset = set()
    found = [False]

    def visit(n):
        if type(n.parent) == IfNode:
            return

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

        sl = n.parent

        i = sl.children.index(n)
        # i -= 1

        # we remove n here, since we may have to ascend through
        # several layers of StatementList nodes
        sl.children.remove(n)

        # clamp i
        i = max(min(i, len(sl) - 1), 0)
        # print(len(sl), i)
        while 1:
            while i >= 0 and i < len(sl):
                if type(sl[i]) == IfNode:
                    break

                i -= 1

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

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

        if i < 0:
            sys.stderr.write("%s:(%d): error: orphaned else block\n" % (n.file, n.line))
            sys.exit(-1)

        tn = sl[i]
        while len(tn) > 2:
            tn = tn[2][0]
        tn.add(n)
        found[0] = True

    traverse(node, ElseNode, visit, copy_children=True)
    while found[0]:
        found[0] = False
        traverse(node, ElseNode, visit, copy_children=True)
Esempio n. 18
0
def combine_if_else_nodes(node):
    vset = set()
    found = [False]

    def visit(n):
        if type(n.parent) == IfNode: return

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

        sl = n.parent

        i = sl.children.index(n)
        #i -= 1

        #we remove n here, since we may have to ascend through
        #several layers of StatementList nodes
        sl.children.remove(n)

        #clamp i
        i = max(min(i,
                    len(sl) - 1), 0)
        #print(len(sl), i)
        while 1:
            while i >= 0 and i < len(sl):
                if type(sl[i]) == IfNode:
                    break

                i -= 1

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

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

        if i < 0:
            sys.stderr.write("%s:(%d): error: orphaned else block\n" %
                             (n.file, n.line))
            sys.exit(-1)

        tn = sl[i]
        while len(tn) > 2:
            tn = tn[2][0]
        tn.add(n)
        found[0] = True

    traverse(node, ElseNode, visit, copy_children=True)
    while found[0]:
        found[0] = False
        traverse(node, ElseNode, visit, copy_children=True)
Esempio n. 19
0
 def BinOpNode(self, node, traverse):
   #self.tlevel += 1
   
   print("eek!", node.op)
   
   if node.op == ".":
     if type(node[0]) == IdentNode:
       self.out("gv " + node[0].val + "\n")
     else:      
       traverse(node[0])
       
     if type(node[1]) == IdentNode:
       self.out("push " + node[1].val)
       self.out("\n")
     else:      
       traverse(node[1])
     
     self.out("get\n")
   else:
     if type(node[0]) in [IdentNode, NumLitNode, StrLitNode]:
       self.out("push " + str(node[0].val))
       self.out("\n")
     else:      
       traverse(node[0])
       
     if type(node[1]) in [IdentNode, NumLitNode, StrLitNode]:
       self.out("push " + str(node[1].val))
       self.out("\n")
     else:      
       traverse(node[1])
     
     self.out(bin_opmap[node.op]+"\n")
     
   self.out("\n");
Esempio n. 20
0
    def BinOpNode(self, node, traverse):
        #self.tlevel += 1

        print("eek!", node.op)

        if node.op == ".":
            if type(node[0]) == IdentNode:
                self.out("gv " + node[0].val + "\n")
            else:
                traverse(node[0])

            if type(node[1]) == IdentNode:
                self.out("push " + node[1].val)
                self.out("\n")
            else:
                traverse(node[1])

            self.out("get\n")
        else:
            if type(node[0]) in [IdentNode, NumLitNode, StrLitNode]:
                self.out("push " + str(node[0].val))
                self.out("\n")
            else:
                traverse(node[0])

            if type(node[1]) in [IdentNode, NumLitNode, StrLitNode]:
                self.out("push " + str(node[1].val))
                self.out("\n")
            else:
                traverse(node[1])

            self.out(bin_opmap[node.op] + "\n")

        self.out("\n")
Esempio n. 21
0
def process_generators(result, tspace):
    global typespace
    typespace = tspace

    traverse(result, YieldNode, visit_yields)
    traverse(result, FunctionNode, visit_generators)

    del_attrs = []

    def cleanup_generator_garbage(n):
        for a in del_attrs:
            if hasattr(n, a):
                delattr(n, a)
        for c in n.children:
            cleanup_generator_garbage(c)

    cleanup_generator_garbage(result)
Esempio n. 22
0
def process_generators(result, tspace):
  global typespace
  typespace = tspace
  
  traverse(result, YieldNode, visit_yields)
  traverse(result, FunctionNode, visit_generators)

  
  del_attrs = []
  def cleanup_generator_garbage(n):
    for a in del_attrs:
      if hasattr(n, a):
        delattr(n, a)
    for c in n.children:
      cleanup_generator_garbage(c)
      
  cleanup_generator_garbage(result)
Esempio n. 23
0
    def FunctionNode(self, node, traverse):
        self.push_label(node.name)

        for c in node[1:]:
            traverse(c)

        if not self.buf.strip().endswith("ret"):
            self.out("ret\n")

        self.pop_label()
        #XXX
        #self.out("endfunction\n\n");

        #XXX need to deal with continuations, nested functions, etc.
        #for now though. . .

        self.out(";add function to scope\n")
        self.out("cf %s, %d\n" % (node.name, len(node[0])))
        self.out("sv " + node.name + "\n")
        self.out("drop\n\n")
Esempio n. 24
0
    def VarDeclNode(self, node, traverse):
        for c in node[1:]:
            traverse(c)

        self.out(";declare " + node.val + "\n")
        self.tlevel += 1

        if type(node[0]) in [IdentNode, NumLitNode, StrLitNode]:
            self.out("push ")
            self.traverse(node[0])
            self.out("\n")
        else:
            traverse(node[0])

        self.out("setvar " + node.val + "\n")
        self.out("drop\n")

        self.tlevel -= 1

        self.scope[node.val] = node
Esempio n. 25
0
 def VarDeclNode(self, node, traverse):
   for c in node[1:]:
     traverse(c)
     
   self.out(";declare " + node.val + "\n")
   self.tlevel += 1
   
   if type(node[0]) in [IdentNode, NumLitNode, StrLitNode]:
     self.out("push ")
     self.traverse(node[0])
     self.out("\n");
   else:
     traverse(node[0])
   
   self.out("setvar " + node.val + "\n")
   self.out("drop\n");
   
   self.tlevel -= 1
   
   self.scope[node.val] = node;
Esempio n. 26
0
 def FunctionNode(self, node, traverse):
   self.push_label(node.name)
   
   for c in node[1:]:
     traverse(c)
     
   if not self.buf.strip().endswith("ret"):
     self.out("ret\n");
   
   self.pop_label()
   #XXX
   #self.out("endfunction\n\n");
   
   #XXX need to deal with continuations, nested functions, etc.
   #for now though. . .
   
   self.out(";add function to scope\n");
   self.out("cf %s, %d\n" % (node.name, len(node[0])));
   self.out("sv " + node.name + "\n");
   self.out("drop\n\n");
Esempio n. 27
0
def create_elseif_nodes(result, typespace):
  def visit(node):
    n = node[0]
      
    while type(n) == StatementList:
      if len(n) > 1:
        return
      n = n[0]
    
    if type(n) == IfNode:
      node.parent.replace(node, ElseIfNode(n))
    
  traverse(result, ElseNode, visit)
  
  def visit2(node):
    if type(node) in [ElseIfNode, ElseNode]:
      ni = node.parent.index(node)
      if ni == 0:
        typespace.error("invalid else 1", node)
      
      prev = node.parent[ni-1]
      
      print("PREV", type(prev))
      
      if type(prev) != IfNode:
        typespace.error("invalid else 2", node)
      
      node.parent.remove(node)
      prev.add(node)
    else:
      i = 0
      while i < len(node):
        i_inc = 1 if type(node[i]) not in [ElseIfNode, ElseNode] else 0
        
        visit2(node[i])
        i += i_inc
  
  #collapse if nodes
  visit2(result)
  print("\n\n", result, "\n\n")
Esempio n. 28
0
def create_elseif_nodes(result, typespace):
    def visit(node):
        n = node[0]

        while type(n) == StatementList:
            if len(n) > 1:
                return
            n = n[0]

        if type(n) == IfNode:
            node.parent.replace(node, ElseIfNode(n))

    traverse(result, ElseNode, visit)

    def visit2(node):
        if type(node) in [ElseIfNode, ElseNode]:
            ni = node.parent.index(node)
            if ni == 0:
                typespace.error("invalid else 1", node)

            prev = node.parent[ni - 1]

            print("PREV", type(prev))

            if type(prev) != IfNode:
                typespace.error("invalid else 2", node)

            node.parent.remove(node)
            prev.add(node)
        else:
            i = 0
            while i < len(node):
                i_inc = 1 if type(node[i]) not in [ElseIfNode, ElseNode] else 0

                visit2(node[i])
                i += i_inc

    #collapse if nodes
    visit2(result)
    print("\n\n", result, "\n\n")
Esempio n. 29
0
def unpack_for_c_loops(node):
    start = node.children[0]

    if node.parent.parent == None: return
    p = node.parent.parent

    i = node.parent.parent.children.index(node.parent)
    node.replace(start, ExprNode([]))
    node.parent.parent.insert(i, start)
    start._c_loop_node = node

    if type(node.parent[1]) != StatementList:
        sl = StatementList()
        sl.add(node.parent[1])
        node.parent.replace(node.parent[1], sl)

    sl = node.parent[1]
    inc = node[2]
    node.replace(inc, ExprNode([]))
    sl.add(inc)

    def handle_continues(n):
        if type(n.parent) != StatementList:
            sl = StatementList()
            n.parent.replace(n, sl)
            sl.add(n)

        n.parent.insert(n.parent.index(n), inc.copy())

    traverse(node.parent,
             ContinueNode,
             handle_continues,
             exclude=[FunctionNode],
             copy_children=True)

    node.parent[1]
Esempio n. 30
0
def expand_of_loops(result, typespace):
    def expand_mozilla_forloops_new(node, scope):
        use_in_iter = False

        if (node.of_keyword == "in"):
            use_in_iter = True
            typespace.warning("Temporary warning: detected for-in usage", node)

            if not inside_generator(node):
                return

        func = node.parent
        while not null_node(func) and type(func) != FunctionNode:
            func = func.parent

        if not null_node(func):
            if func.name in forloop_expansion_exclude: return

        def prop_ident_change(node, oldid, newid):
            if type(node) in [IdentNode, VarDeclNode] and node.val == oldid:
                if type(node.parent) == BinOpNode and node.parent.op == ".":
                    if node != node.parent[1]:
                        node.val = newid
                else:
                    node.val = newid

            for c in node.children:
                if type(c) == FunctionNode:
                    continue
                prop_ident_change(c, oldid, newid)

        #for-in-loops don't seem to behave like for-C-loops,
        #the iteration variable is in it's own scope, and
        #doesn't seem to affect the parent scope.
        val = node[0].val
        di = 0
        while node[0].val in scope:
            node[0].val = "%s_%d" % (val, di)
            di += 1

            #print(node[0].val)

        if node[0].val != val:
            scope[node[0].val] = node[0]
            prop_ident_change(node.parent, val, node[0].val)

        slist = node.parent.children[1]
        if type(slist) != StatementList:
            s = StatementList()
            s.add(slist)
            slist = s

        getiter = "__get_in_iter" if use_in_iter else "__get_iter"

        itername = node[0].val
        objname = node[1].gen_js(0)
        if glob.g_log_forloops:
            n2 = js_parse(
                """
        var __iter_$s1 = __get_iter($s2, $s3, $s4, $s5);
        var $s1;
        while (1) {
          var __ival_$s1 = __iter_$s1.next();
          if (__ival_$s1.done) {
            break;
          }
          
          $s1 = __ival_$s1.value;
        }
      """.replace("__get_iter", getiter),
                (itername, GETITER, objname, "'" + node[0].file + "'",
                 node[0].line, "'" + node.of_keyword + "'"))
        else:
            n2 = js_parse(
                """
        var __iter_$s1 = __get_iter($s2);
        var $s1;
        while (1) {
          var __ival_$s1 = __iter_$s1.next();
          if (__ival_$s1.done) {
            break;
          }
          
          $s1 = __ival_$s1.value;
        }
      """.replace("__get_iter", getiter), (itername, objname))

        def set_line(n, slist, line, lexpos):
            n.line = line
            n.lexpos = lexpos

            for c in n.children:
                set_line(c, slist, line, lexpos)

        #preserving line info is a bit tricky.
        #slist goes through a js->gen_js->js cycle,
        #so make sure we still have it (and its
        #line/lexpos information).

        set_line(n2, slist, node.line, node.lexpos)
        for c in slist:
            n2[2][1].add(c)

        node.parent.parent.replace(node.parent, n2)

    #expand_of_loops lexical scope here
    traverse(result, ForInNode, expand_mozilla_forloops_new, use_scope=True)
Esempio n. 31
0
def process_generators_old(result, typespace):
    def visit_yields(node):
        p = node

        while not null_node(p) and type(p) != FunctionNode:
            p = p.parent

        if null_node(p):
            typespace.error("yield keyword only valid within functions")

        p.is_generator = True

    traverse(result, YieldNode, visit_yields)

    def node_has_yield(node):
        if type(node) == YieldNode:
            return True

        for c in node.children:
            if type(c) == FunctionNode:
                continue

            ret = node_has_yield(c)
            if ret: return True

        return False

    def visit_generators(node):
        def print_frames(frames, tlevel=0):
            tstr = tab(tlevel)
            tstr2 = tab(tlevel + 1)

            s = ""
            for f in frames:
                if type(f) == Frame:
                    if f.node != None:
                        nstr = "%s %d " % (f.node.get_line_str(), f.label)
                    else:
                        nstr = str(f.label) + " "

                    s += tstr + nstr + "{\n" + print_frames(f, tlevel + 1)
                    s += tstr + "}\n"
                else:
                    s += tstr + f.get_line_str() + "\n"

            if tlevel == 0:
                print(s)

            return s

        if 0:
            file = open("generator_test.html", "w")
            file.write("""
      <html><head><title>Generator Test</title></head>
      <script>
      FrameContinue = {1:1};
      FrameBreak = {2:2};
      """)
            file.write(node2.gen_js(3).replace("yield", "return"))
            file.write("""
  j = 0;
  for (var tst in new range(2, 8)) {
    console.log(tst);
    if (j > 10)
      break;
    j++;
  }
  </script>
  </html>
  """)
            file.close()

        #print(node2.gen_js(1))
        #print_frames(frames2)

    traverse(result, FunctionNode, visit_generators)

    del_attrs = ["_cur", "_startcur", "frame", "return_frame", "pop_trystack"]

    def cleanup_generator_garbage(n):
        for a in del_attrs:
            if hasattr(n, a):
                delattr(n, a)
        for c in n.children:
            cleanup_generator_garbage(c)

    cleanup_generator_garbage(result)
Esempio n. 32
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)
Esempio n. 33
0
def parse_intern(data,
                 create_logger=False,
                 expand_loops=True,
                 expand_generators=True):
    glob.g_lines = data.split("\n")

    if glob.g_preprocess_code:
        data = preprocess_text(data, glob.g_file)

    if glob.g_print_tokens:
        plexer.input(data)
        tok = plexer.token()
        while tok != None:
            print(tok)
            tok = plexer.token()
        plexer.input(data)

    glob.g_lexer = plexer
    result = parser.parse(data, lexer=plexer)

    if result == None:
        if glob.g_error_pre != None:
            glob.g_error = True

        result = StatementList()

    if glob.g_error:
        print_err(glob.g_error_pre)

    typespace = JSTypeSpace()

    #handle some directives
    for c in result:
        if type(c) != StrLitNode: break

        if c.val[1:-1] == "use strict":
            glob.g_force_global_strict = True
        elif c.val[1:-1] == "not_a_module":
            glob.g_es6_modules = False

    if glob.g_profile_coverage:
        from js_process_ast import coverage_profile
        coverage_profile(result, typespace)

    if glob.g_compile_statics_only:
        process_static_vars(result, typespace)
        return result.gen_js(0), result

    if glob.g_enable_let:
        process_let(result, typespace)

    if glob.g_force_global_strict:
        kill_bad_globals(result, typespace)

    #handle .? operator
    transform_exisential_operators(result, typespace)

    if glob.g_write_manifest and glob.g_outfile != "":
        buf = gen_manifest_file(result, typespace)
        file = open(glob.g_outfile + ".manifest", "w")
        file.write(buf)
        file.close()

    if glob.g_es6_modules:
        module_transform(result, typespace)

    if glob.g_require_js:
        expand_requirejs_classes(result, typespace)
    elif glob.g_expand_classes:
        expand_harmony_classes(result, typespace)
        expand_typed_classes(result, typespace)
    else:
        create_class_list(result, typespace)

    if glob.g_clear_slashr:
        print("\n")

    if result != None and len(result) == 0:
        result = None
        return "", None
        #sys.stdout.write("Error: empty compilation\n");
        #raise JSError("Empty compilation");

    global f_id
    f_id = [0]
    flatten_statementlists(result, typespace)

    has_generators = [False]

    def has_generator(n):
        if not glob.g_expand_generators: return

        if type(n) == YieldNode:
            has_generators[0] = True

        for c in n:
            has_generator(c)

    has_generator(result)

    if expand_loops or has_generators[0]:
        expand_of_loops(result, typespace)

    #combine_try_nodes may have nested statementlists again, so better reflatten
    flatten_statementlists(result, typespace)

    if create_logger:
        traverse(result, FunctionNode, create_type_logger)

    #don't need to do this anymore, yay!
    #process_arrow_function_this(result, typespace)

    if expand_generators:
        flatten_statementlists(result, typespace)
        process_generators(result, typespace)
        flatten_statementlists(result, typespace)

    if glob.g_add_opt_initializers:
        add_func_opt_code(result, typespace)

    debug_forloop_expansion = False
    if debug_forloop_expansion:
        reset = 0
        if reset or not os.path.exists("cur_d.txt"):
            f = open("cur_d.txt", "w")
            f.write("-1")
            f.close()

        f = open("cur_d.txt", "r")
        d = int(f.read())
        print("\n\nd: %d\n" % d)
        traverse_i(result,
                   ForInNode,
                   expand_mozilla_forloops,
                   d,
                   use_scope=True)
        f.close()

        f = open("cur_d.txt", "w")
        f.write(str(d + 1))
        f.close()

    if glob.g_combine_ifelse_nodes:
        combine_if_else_nodes(result)

    if glob.g_print_nodes:
        print("nodes: ", result)
        pass

    if glob.g_replace_instanceof and not glob.g_require_js:
        replace_instanceof(result, typespace)

    if glob.g_enable_static_vars:
        process_static_vars(result, typespace)

    if glob.g_do_docstrings:
        process_docstrings(result, typespace)

    if glob.g_gen_source_map:
        smap = SourceMap()

        def set_smap(node, smap):
            node.smap = smap
            for n in node:
                set_smap(n, smap)

        set_smap(result, smap)

        if not glob.g_minify:
            buf = result.gen_js(0)
            map = gen_source_map(data, buf, smap)
        else:
            buf, smap = js_minify(result)
            map = gen_source_map(data, buf, smap)

        if glob.g_add_srcmap_ref:
            spath = glob.g_outfile
            if os.path.sep in spath: spath = os.path.split(spath)[1]

            buf += "\n//# sourceMappingURL=/content/%s\n" % (spath + ".map")

        if glob.g_gen_smap_orig:
            f = open(glob.g_outfile + ".origsrc", "w")
            f.write(data)
            f.close()
    else:
        if not glob.g_minify:
            buf = result.gen_js(0)
        else:
            buf, smap = js_minify(result)

    if glob.g_outfile == "":
        print(buf)
        if 0:
            file = open("generator_test.html", "w")
            file.write("""
      <html><head><title>Generator Test</title></head>
      <script>
      function arr_iter(keys)
      {
        this.keys = keys;
        this.cur = 0;
        
        this.next = function() {
          if (this.cur >= this.keys.length) {
            throw StopIteration;
          }
          
          return this.keys[this.cur++];
        }
      }

      __use_Iterator = true;

      function __get_iter(obj)
      {
        if (obj.__proto__.hasOwnProperty("__iterator__") || obj.hasOwnProperty("__iterator__")) {
          return obj.__iterator__();
        } else {
          if (__use_Iterator) {
            return Iterator(obj);
          } else {
            keys = []
            for (var k in obj) {
              keys.push(k)
            }
            return new arr_iter(keys);
          }
        }
      }

      function __get_iter2(obj)
      {
        if (obj.__proto__.hasOwnProperty("__iterator__") || obj.hasOwnProperty("__iterator__")) {
          return obj.__iterator__();
        } else {
          keys = []
          for (var k in obj) {
            keys.push([k, obj[k]])
          }
          return new arr_iter(keys);
        }
      }

      try {
        _tst = Iterator({});
      } catch (Error) {
        __use_Iterator = false;
        Iterator = __get_iter2;
      }
      FrameContinue = {1:1};
      FrameBreak = {2:2};
      """)
            file.write(buf.replace("yield", "return"))
            file.write("""
  j = 0;
  for (var tst in new range2(2, 8)) {
    if (_do_frame_debug) console.log(tst);
    if (j > 10)
      break;
    j++;
  }
  </script>
  </html>
  """)
            file.close()
        pass

    return buf, result
Esempio n. 34
0
 def value_traverse(self, node, traverse):
     if type(node) in [IdentNode, StrLitNode, NumLitNode]:
         self.out("push ")
     traverse(node)
     self.out("\n")
Esempio n. 35
0
def expand_of_loops(result, typespace):
    def expand_mozilla_forloops_new(node, scope):
        if node.of_keyword == "in":
            typespace.warning("Temporary warning: detected for-in usage", node)
            return

        func = node.parent
        while not null_node(func) and type(func) != FunctionNode:
            func = func.parent

        if not null_node(func):
            if func.name in forloop_expansion_exclude:
                return

        def prop_ident_change(node, oldid, newid):
            if type(node) in [IdentNode, VarDeclNode] and node.val == oldid:
                if type(node.parent) == BinOpNode and node.parent.op == ".":
                    if node != node.parent[1]:
                        node.val = newid
                else:
                    node.val = newid

            for c in node.children:
                if type(c) == FunctionNode:
                    continue
                prop_ident_change(c, oldid, newid)

        # for-in-loops don't seem to behave like for-C-loops,
        # the iteration variable is in it's own scope, and
        # doesn't seem to affect the parent scope.
        val = node[0].val
        di = 0
        while node[0].val in scope:
            node[0].val = "%s_%d" % (val, di)
            di += 1

            # print(node[0].val)

        if node[0].val != val:
            scope[node[0].val] = node[0]
            prop_ident_change(node.parent, val, node[0].val)

        slist = node.parent.children[1]
        if type(slist) != StatementList:
            s = StatementList()
            s.add(slist)
            slist = s

        itername = node[0].val
        objname = node[1].gen_js(0)
        if glob.g_log_forloops:
            n2 = js_parse(
                """
        var __iter_$s1 = __get_iter($s2, $s3, $s4, $s5);
        var $s1;
        while (1) {
          var __ival_$s1 = __iter_$s1.next();
          if (__ival_$s1.done) {
            break;
          }
          
          $s1 = __ival_$s1.value;
        }
      """,
                (itername, objname, "'" + node[0].file + "'", node[0].line, "'" + node.of_keyword + "'"),
            )
        else:
            n2 = js_parse(
                """
        var __iter_$s1 = __get_iter($s2);
        var $s1;
        while (1) {
          var __ival_$s1 = __iter_$s1.next();
          if (__ival_$s1.done) {
            break;
          }
          
          $s1 = __ival_$s1.value;
        }
      """,
                (itername, objname),
            )

        def set_line(n, slist, line, lexpos):
            n.line = line
            n.lexpos = lexpos

            for c in n.children:
                set_line(c, slist, line, lexpos)

        # preserving line info is a bit tricky.
        # slist goes through a js->gen_js->js cycle,
        # so make sure we still have it (and its
        # line/lexpos information).

        set_line(n2, slist, node.line, node.lexpos)
        for c in slist:
            n2[2][1].add(c)

        node.parent.parent.replace(node.parent, n2)

    # expand_of_loops lexical scope here
    traverse(result, ForInNode, expand_mozilla_forloops_new, use_scope=True)
Esempio n. 36
0
def process_generators_old(result, typespace):
  def visit_yields(node):
    p = node
    
    while not null_node(p) and type(p) != FunctionNode:
      p = p.parent
    
    if null_node(p):
      typespace.error("yield keyword only valid within functions")
    
    p.is_generator = True
    
  traverse(result, YieldNode, visit_yields)
  
  def node_has_yield(node):
    if type(node) == YieldNode:
      return True
      
    for c in node.children:
      if type(c) == FunctionNode:
        continue
       
      ret = node_has_yield(c)
      if ret: return True
      
    return False
  
  def visit_generators(node):
    def print_frames(frames, tlevel=0):
      tstr = tab(tlevel)
      tstr2 = tab(tlevel+1)
      
      s = ""
      for f in frames:
        if type(f) == Frame:
          if f.node != None:
            nstr = "%s %d " % (f.node.get_line_str(), f.label)
          else:
            nstr = str(f.label) + " "
            
          s += tstr + nstr + "{\n" + print_frames(f, tlevel+1)
          s += tstr + "}\n";
        else:
          s += tstr + f.get_line_str() + "\n"
      
      if tlevel == 0:
        print(s)
        
      return s
      
    if 0:
      file = open("generator_test.html", "w")
      file.write("""
      <html><head><title>Generator Test</title></head>
      <script>
      FrameContinue = {1:1};
      FrameBreak = {2:2};
      """)
      file.write(node2.gen_js(3).replace("yield", "return"))
      file.write("""
  j = 0;
  for (var tst in new range(2, 8)) {
    console.log(tst);
    if (j > 10)
      break;
    j++;
  }
  </script>
  </html>
  """)
      file.close()
    
    #print(node2.gen_js(1))
    #print_frames(frames2)
    
  traverse(result, FunctionNode, visit_generators)
  
  del_attrs = ["_cur", "_startcur", "frame", "return_frame", "pop_trystack"]
  def cleanup_generator_garbage(n):
    for a in del_attrs:
      if hasattr(n, a):
        delattr(n, a)
    for c in n.children:
      cleanup_generator_garbage(c)
      
  cleanup_generator_garbage(result)
Esempio n. 37
0
def parse_intern(data, create_logger=False, expand_loops=True, expand_generators=True):
  glob.g_lines = data.split("\n")
  
  if glob.g_preprocess_code:
    data = preprocess_text(data, glob.g_file)
    
  if glob.g_print_tokens:
    plexer.input(data)
    tok = plexer.token()
    while tok != None:
      print(tok)
      tok = plexer.token()
    plexer.input(data)
  
  glob.g_lexer = plexer
  result = parser.parse(data, lexer=plexer)
  
  if result == None:
    if glob.g_error_pre != None:
      glob.g_error = True
    
    result = StatementList()

  if glob.g_error:
    print_err(glob.g_error_pre)
    
  typespace = JSTypeSpace()
  
  if result != None:
    if len(result) > 0 and type(result[0]) == StrLitNode and result[0].val == '"use strict"':
      glob.g_force_global_strict = True
    elif len(result) > 0 and type(result[0]) == StrLitNode and result[0].val == '"not_a_module"':
      glob.g_es6_modules = False
      
  if glob.g_compile_statics_only:
    process_static_vars(result, typespace)
    return result.gen_js(0), result
    
  if glob.g_enable_let:
    process_let(result, typespace)
    
  if glob.g_force_global_strict:
    kill_bad_globals(result, typespace)
  
  #handle .? operator
  transform_exisential_operators(result, typespace)
  
  if glob.g_write_manifest and glob.g_outfile != "":
    buf = gen_manifest_file(result, typespace);
    file = open(glob.g_outfile+".manifest", "w")
    file.write(buf)
    file.close()
    
  if glob.g_es6_modules:
    module_transform(result, typespace)
  
  if glob.g_require_js:
    expand_requirejs_classes(result, typespace);
  else:
    expand_harmony_classes(result, typespace);
  expand_typed_classes(result, typespace)
  
  if glob.g_clear_slashr:
    print("\n")
  
  if result != None and len(result) == 0:
    result = None
    return "", None
    #sys.stdout.write("Error: empty compilation\n");
    #raise JSError("Empty compilation");
  
  global f_id  
  f_id = [0]
  flatten_statementlists(result, typespace)
  
  has_generators = [False]
  def has_generator(n):
    if type(n) == YieldNode:
      has_generators[0] = True
    
    for c in n:
      has_generator(c)
  
  has_generator(result)
  
  if expand_loops or has_generators[0]:
    expand_of_loops(result, typespace)
  
  #combine_try_nodes may have nested statementlists again, so better reflatten
  flatten_statementlists(result, typespace)
  
  if create_logger:
    traverse(result, FunctionNode, create_type_logger)
  
  process_arrow_function_this(result, typespace)
  
  if expand_generators:
    flatten_statementlists(result, typespace)
    process_generators(result, typespace);
    flatten_statementlists(result, typespace)
  
  if glob.g_add_opt_initializers:
    add_func_opt_code(result, typespace)
  
  if glob.g_combine_ifelse_nodes:
    combine_if_else_nodes(result)
  
  if glob.g_print_nodes:
    print("nodes: ", result)
    pass
    
  if glob.g_replace_instanceof and not glob.g_require_js:
    replace_instanceof(result, typespace)
  
  if glob.g_enable_static_vars:
    process_static_vars(result, typespace)
    
  if glob.g_do_docstrings:
    process_docstrings(result, typespace)
  
  if glob.g_gen_v7_bytecode:
    from js_opcode_emit2 import v7_emit_bytecode
    buf = v7_emit_bytecode(result, typespace)
  elif not glob.g_minify:
    buf = result.gen_js(0)
  else:
    buf, smap = js_minify(result)
    
  if glob.g_outfile == "":
    print(buf)
    
  return buf, result
Esempio n. 38
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)
Esempio n. 39
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)
Esempio n. 40
0
 def value_traverse(self, node, traverse):
   if type(node) in [IdentNode, StrLitNode, NumLitNode]:
     self.out("push ")
   traverse(node)
   self.out("\n")
Esempio n. 41
0
def parse_intern(data,
                 create_logger=False,
                 expand_loops=True,
                 expand_generators=True):
    glob.g_lines = data.split("\n")

    if glob.g_preprocess_code:
        data = preprocess_text(data, glob.g_file)

    if glob.g_print_tokens:
        plexer.input(data)
        tok = plexer.token()
        while tok != None:
            print(tok)
            tok = plexer.token()
        plexer.input(data)

    glob.g_lexer = plexer
    result = parser.parse(data, lexer=plexer)

    if result == None:
        if glob.g_error_pre != None:
            glob.g_error = True

        result = StatementList()

    if glob.g_error:
        print_err(glob.g_error_pre)

    typespace = JSTypeSpace()

    if result != None:
        if len(result) > 0 and type(
                result[0]) == StrLitNode and result[0].val == '"use strict"':
            glob.g_force_global_strict = True
        elif len(result) > 0 and type(
                result[0]) == StrLitNode and result[0].val == '"not_a_module"':
            glob.g_es6_modules = False

    if glob.g_compile_statics_only:
        process_static_vars(result, typespace)
        return result.gen_js(0), result

    if glob.g_enable_let:
        process_let(result, typespace)

    if glob.g_force_global_strict:
        kill_bad_globals(result, typespace)

    #handle .? operator
    transform_exisential_operators(result, typespace)

    if glob.g_write_manifest and glob.g_outfile != "":
        buf = gen_manifest_file(result, typespace)
        file = open(glob.g_outfile + ".manifest", "w")
        file.write(buf)
        file.close()

    if glob.g_es6_modules:
        module_transform(result, typespace)

    if glob.g_require_js:
        expand_requirejs_classes(result, typespace)
    else:
        expand_harmony_classes(result, typespace)
    expand_typed_classes(result, typespace)

    if glob.g_clear_slashr:
        print("\n")

    if result != None and len(result) == 0:
        result = None
        return "", None
        #sys.stdout.write("Error: empty compilation\n");
        #raise JSError("Empty compilation");

    global f_id
    f_id = [0]
    flatten_statementlists(result, typespace)

    has_generators = [False]

    def has_generator(n):
        if type(n) == YieldNode:
            has_generators[0] = True

        for c in n:
            has_generator(c)

    has_generator(result)

    if expand_loops or has_generators[0]:
        expand_of_loops(result, typespace)

    #combine_try_nodes may have nested statementlists again, so better reflatten
    flatten_statementlists(result, typespace)

    if create_logger:
        traverse(result, FunctionNode, create_type_logger)

    process_arrow_function_this(result, typespace)

    if expand_generators:
        flatten_statementlists(result, typespace)
        process_generators(result, typespace)
        flatten_statementlists(result, typespace)

    if glob.g_add_opt_initializers:
        add_func_opt_code(result, typespace)

    if glob.g_combine_ifelse_nodes:
        combine_if_else_nodes(result)

    if glob.g_print_nodes:
        print("nodes: ", result)
        pass

    if glob.g_replace_instanceof and not glob.g_require_js:
        replace_instanceof(result, typespace)

    if glob.g_enable_static_vars:
        process_static_vars(result, typespace)

    if glob.g_do_docstrings:
        process_docstrings(result, typespace)

    if glob.g_gen_v7_bytecode:
        from js_opcode_emit2 import v7_emit_bytecode
        buf = v7_emit_bytecode(result, typespace)
    elif not glob.g_minify:
        buf = result.gen_js(0)
    else:
        buf, smap = js_minify(result)

    if glob.g_outfile == "":
        print(buf)

    return buf, result
Esempio n. 42
0
def combine_try_nodes(node):
    return

    def error(msg, srcnode):
        if glob.g_print_stack:
            pass  #traceback.print_stack()

        lines = glob.g_lexdata.split("\n")
        s = max(srcnode.line - 30, 0)
        e = min(srcnode.line + 3, len(lines) - 1)
        ls = ""
        for i in range(s, e):
            ls += str(i + 1) + ": " + lines[i] + "\n"

        sys.stderr.write("\n%s\n%s:(%s): error: %s\n" %
                         (ls, srcnode.file, srcnode.line + 1, msg))
        sys.exit(-1)

    def visit(n):
        if type(n.parent) == TryNode: return

        sl = n.parent

        i = sl.children.index(n)
        i -= 1

        #we remove n here, since we may have to ascend through
        #several layers of StatementList nodes
        #sl.children.remove(n)

        p = n.parent
        lastp = n

        while p and type(p) == StatementList:
            print(p.get_line_str())

            if lastp is not None and type(p) == StatementList:
                i = max(p.index(lastp) - 1, 0)

                if type(p[i]) == TryNode:
                    p = p[i]
                    break
                elif type(p[i]) != StatementList:
                    n = p

                    error(
                        "%s:(%d): error: orphaned catch block 1\n" %
                        (n.file, n.line), n)
                    sys.exit(-1)

            lastp = p
            p = p.parent

        if type(p) != TryNode or len(p) >= 2:
            n = p
            error(
                "%s:(%d): error: orphaned catch block 2\n" % (n.file, n.line),
                n)
            sys.exit(-1)

        n.parent.remove(n)
        p.add(n)
        return

    traverse(node, CatchNode, visit, copy_children=True)
Esempio n. 43
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)
Esempio n. 44
0
def parse_intern(data, create_logger=False, expand_loops=True, expand_generators=True):
    glob.g_lines = data.split("\n")

    if glob.g_preprocess_code:
        data = preprocess_text(data, glob.g_file)

    if glob.g_print_tokens:
        plexer.input(data)
        tok = plexer.token()
        while tok != None:
            print(tok)
            tok = plexer.token()
        plexer.input(data)

    glob.g_lexer = plexer
    result = parser.parse(data, lexer=plexer)

    if result == None:
        if glob.g_error_pre != None:
            glob.g_error = True

        result = StatementList()

    if glob.g_error:
        print_err(glob.g_error_pre)

    typespace = JSTypeSpace()

    if result != None:
        if len(result) > 0 and type(result[0]) == StrLitNode and result[0].val == '"use strict"':
            glob.g_force_global_strict = True
        elif len(result) > 0 and type(result[0]) == StrLitNode and result[0].val == '"not_a_module"':
            glob.g_es6_modules = False

    if glob.g_force_global_strict:
        kill_bad_globals(result, typespace)

    # handle .? operator
    transform_exisential_operators(result, typespace)

    if glob.g_write_manifest and glob.g_outfile != "":
        buf = gen_manifest_file(result, typespace)
        file = open(glob.g_outfile + ".manifest", "w")
        file.write(buf)
        file.close()

    if glob.g_es6_modules:
        module_transform(result, typespace)

    if glob.g_require_js:
        expand_requirejs_classes(result, typespace)
    else:
        expand_harmony_classes(result, typespace)
    expand_typed_classes(result, typespace)

    if glob.g_clear_slashr:
        print("\n")

    if result != None and len(result) == 0:
        result = None
        return "", None
        # sys.stdout.write("Error: empty compilation\n");
        # raise JSError("Empty compilation");

    global f_id
    f_id = [0]
    flatten_statementlists(result, typespace)

    if expand_loops:
        expand_of_loops(result, typespace)

    # combine_try_nodes may have nested statementlists again, so better reflatten
    flatten_statementlists(result, typespace)

    if create_logger:
        traverse(result, FunctionNode, create_type_logger)

    if expand_generators:
        flatten_statementlists(result, typespace)
        process_generators(result, typespace)
        flatten_statementlists(result, typespace)

    if glob.g_add_opt_initializers:
        add_func_opt_code(result, typespace)

    debug_forloop_expansion = False
    if debug_forloop_expansion:
        reset = 0
        if reset or not os.path.exists("cur_d.txt"):
            f = open("cur_d.txt", "w")
            f.write("-1")
            f.close()

        f = open("cur_d.txt", "r")
        d = int(f.read())
        print("\n\nd: %d\n" % d)
        traverse_i(result, ForInNode, expand_mozilla_forloops, d, use_scope=True)
        f.close()

        f = open("cur_d.txt", "w")
        f.write(str(d + 1))
        f.close()

    if glob.g_combine_ifelse_nodes:
        combine_if_else_nodes(result)

    if glob.g_print_nodes:
        print("nodes: ", result)
        pass

    if glob.g_replace_instanceof and not glob.g_require_js:
        replace_instanceof(result, typespace)

    if glob.g_enable_static_vars:
        process_static_vars(result, typespace)

    if glob.g_do_docstrings:
        process_docstrings(result, typespace)

    if glob.g_gen_source_map:
        smap = SourceMap()

        def set_smap(node, smap):
            node.smap = smap
            for n in node:
                set_smap(n, smap)

        set_smap(result, smap)

        if not glob.g_minify:
            buf = result.gen_js(0)
            map = gen_source_map(data, buf, smap)
        else:
            buf, smap = js_minify(result)
            map = gen_source_map(data, buf, smap)

        if glob.g_add_srcmap_ref:
            spath = glob.g_outfile
            if os.path.sep in spath:
                spath = os.path.split(spath)[1]

            buf += "\n//# sourceMappingURL=/content/%s\n" % (spath + ".map")

        if glob.g_gen_smap_orig:
            f = open(glob.g_outfile + ".origsrc", "w")
            f.write(data)
            f.close()
    else:
        if not glob.g_minify:
            buf = result.gen_js(0)
        else:
            buf, smap = js_minify(result)

    if glob.g_outfile == "":
        print(buf)
        if 0:
            file = open("generator_test.html", "w")
            file.write(
                """
      <html><head><title>Generator Test</title></head>
      <script>
      function arr_iter(keys)
      {
        this.keys = keys;
        this.cur = 0;
        
        this.next = function() {
          if (this.cur >= this.keys.length) {
            throw StopIteration;
          }
          
          return this.keys[this.cur++];
        }
      }

      __use_Iterator = true;

      function __get_iter(obj)
      {
        if (obj.__proto__.hasOwnProperty("__iterator__") || obj.hasOwnProperty("__iterator__")) {
          return obj.__iterator__();
        } else {
          if (__use_Iterator) {
            return Iterator(obj);
          } else {
            keys = []
            for (var k in obj) {
              keys.push(k)
            }
            return new arr_iter(keys);
          }
        }
      }

      function __get_iter2(obj)
      {
        if (obj.__proto__.hasOwnProperty("__iterator__") || obj.hasOwnProperty("__iterator__")) {
          return obj.__iterator__();
        } else {
          keys = []
          for (var k in obj) {
            keys.push([k, obj[k]])
          }
          return new arr_iter(keys);
        }
      }

      try {
        _tst = Iterator({});
      } catch (Error) {
        __use_Iterator = false;
        Iterator = __get_iter2;
      }
      FrameContinue = {1:1};
      FrameBreak = {2:2};
      """
            )
            file.write(buf.replace("yield", "return"))
            file.write(
                """
  j = 0;
  for (var tst in new range2(2, 8)) {
    if (_do_frame_debug) console.log(tst);
    if (j > 10)
      break;
    j++;
  }
  </script>
  </html>
  """
            )
            file.close()
        pass

    return buf, result
Esempio n. 45
0
def expand_of_loops(result, typespace):
    onIterEnd = """
      if (__re_t_.done && typeof __itervar_["return"] === "function") {
        __itervar_["return"]();
      }
  """

    def addIterEnds(node):
        def visit(n):
            sn = StatementList()
            sn.force_block = True

            n.parent.replace(n, sn)
            sn.add(js_parse(onIterEnd))
            sn.add(n)

        traverse(node, ReturnNode, visit)

    def expand_expand_loop(node, scope):

        sn = StatementList()
        sn.force_block = True

        n3 = None
        vdecl = None
        if node[0].etype == "array":
            namenode = BinOpNode(IdentNode("__re_t_"), IdentNode("value"), ".")
            for i, c in enumerate(node[0]):
                n4 = VarDeclNode(ArrayRefNode(namenode, NumLitNode(i)),
                                 name=c.val)
                if len(n4) == 1:
                    n4.add(UnknownTypeNode())

                if n3 is None:
                    n3 = n4
                else:
                    n3.add(n4)

                if vdecl is None:
                    vdecl = n3
                n3 = n4
        else:
            namenode = BinOpNode(IdentNode("__re_t_"), IdentNode("value"), ".")

            for i, c in enumerate(node[0]):
                n4 = VarDeclNode(BinOpNode(namenode, c, "."), name=c.val)
                if len(n4) == 1:
                    n4.add(UnknownTypeNode())

                if n3 is None:
                    n3 = n4
                else:
                    n3.add(n4)

                if vdecl is None:
                    vdecl = n3
                n3 = n4

        vdecl.modifiers = node[0].modifiers

        label = node.parent.label
        label = "" if label is None else label

        innersn = StatementList()
        for c in node.parent[1:]:
            innersn.add(c)

        n2 = js_parse(
            """
        let __itervar_ = __get_iter($n1);
        let __re_t_ = __itervar_.next();
        $s4 for (; !__re_t_.done; __re_t_ = __itervar_.next()) {
            $n3;
            $n2;
        }
        
        $s5
    """, [
                node[1], innersn, vdecl,
                label + ": " if len(label) > 0 else "", onIterEnd
            ])

        sn.add(n2)
        sn.force_block = True

        node.parent.parent.replace(node.parent, sn)
        addIterEnds(sn)

    Found = [0]

    def expand_mozilla_forloops_new(node, scope):
        if node.of_keyword != "of":
            return

        Found[0] = 1

        if type(node[0]) == ExpandNode:
            expand_expand_loop(node, scope)
            return

        vdecl = node[0]
        label = node.parent.label
        label = "" if label is None else label + ":"

        name = vdecl.val
        if isinstance(name, Node):
            name = name.gen_js(0)

        innersn = StatementList()
        for c in node.parent[1:]:
            innersn.add(c)

        flatten_statementlists(innersn, typespace)
        #print(innersn)

        n2 = js_parse(
            """
        let __itervar_ = __get_iter($n1);
        let __re_t_ = __itervar_.next();
        $n3;
        $s5 for (; !__re_t_.done; __re_t_ = __itervar_.next()) {
          $s4 = __re_t_.value;
        
          $n2
        }
        
        $s6
    """, [node[1], innersn, vdecl, name, label, onIterEnd])
        sn = StatementList()
        sn.force_block = True
        sn.add(n2)

        #print("===============================>", sn.gen_js(0), "<==========================")

        node.parent.parent.replace(node.parent, sn)
        addIterEnds(sn)

    def old_expand_mozilla_forloops_new(node, scope):
        if type(node[0]) == ExpandNode:
            expand_expand_loop(node, scope)
            return

        use_in_iter = False

        if (node.of_keyword == "in"):
            use_in_iter = True

            if glob.g_warn_for_in:
                typespace.warning("Detected for-in usage", node)

            if not inside_generator(node):
                return

        func = node.parent
        while not null_node(func) and type(func) != FunctionNode:
            func = func.parent

        if not null_node(func):
            if func.name in forloop_expansion_exclude: return

        def prop_ident_change(node, oldid, newid):
            if type(node) in [IdentNode, VarDeclNode] and node.val == oldid:
                if type(node.parent) == BinOpNode and node.parent.op == ".":
                    if node != node.parent[1]:
                        node.val = newid
                else:
                    node.val = newid

            for c in node.children:
                if type(c) == FunctionNode:
                    continue
                prop_ident_change(c, oldid, newid)

        #for-in-loops don't seem to behave like for-C-loops,
        #the iteration variable is in it's own scope, and
        #doesn't seem to affect the parent scope.
        val = node[0].val
        di = 0
        while node[0].val in scope:
            node[0].val = "%s_%d" % (val, di)
            di += 1

            #print(node[0].val)

        if node[0].val != val:
            scope[node[0].val] = node[0]
            prop_ident_change(node.parent, val, node[0].val)

        slist = node.parent.children[1]
        if type(slist) != StatementList:
            s = StatementList()
            s.add(slist)
            slist = s

        getiter = "__get_in_iter" if use_in_iter else "__get_iter"

        label = node.parent.label
        label = label + ": " if label is not None else ""

        itername = node[0].val
        objname = node[1].gen_js(0)
        if glob.g_log_forloops:
            n2 = js_parse(
                """
        var __iter_$s1 = __get_iter($s2, $s3, $s4, $s5);
        var $s1;
        LABEL while (1) {
          var __ival_$s1 = __iter_$s1.next();
          if (__ival_$s1.done) {
            break;
          }
          
          $s1 = __ival_$s1.value;
        }
      """.replace("LABEL", label).replace("__get_iter", getiter),
                (itername, GETITER, objname, "'" + node[0].file + "'",
                 node[0].line, "'" + node.of_keyword + "'"))
        else:
            n2 = js_parse(
                """
        var __iter_$s1 = __get_iter($s2);
        var $s1;
        LABEL while (1) {
          var __ival_$s1 = __iter_$s1.next();
          if (__ival_$s1.done) {
            break;
          }
          
          $s1 = __ival_$s1.value;
        }
      """.replace("LABEL", label).replace("__get_iter", getiter),
                (itername, objname))

        def set_line(n, slist, line, lexpos):
            n.line = line
            n.lexpos = lexpos

            for c in n.children:
                set_line(c, slist, line, lexpos)

        #preserving line info is a bit tricky.
        #slist goes through a js->gen_js->js cycle,
        #so make sure we still have it (and its
        #line/lexpos information).

        set_line(n2, slist, node.line, node.lexpos)
        for c in slist:
            n2[2][1].add(c)

        node.parent.parent.replace(node.parent, n2)

    #expand_of_loops lexical scope here
    for i in range(1000):
        Found[0] = 0
        traverse(result,
                 ForInNode,
                 expand_mozilla_forloops_new,
                 use_scope=True)
        if not Found[0]:
            break