⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 narcissus.py

📁 Harvestman-最新版本
💻 PY
📖 第 1 页 / 共 3 页
字号:
        if tt != consts["END"] and \
           tt != consts["NEWLINE"] and \
           tt != consts["SEMICOLON"] and \
           tt != consts["RIGHT_CURLY"]:
            raise NarcissusError("Missing ; before statement", t)

    t.match(consts["SEMICOLON"])
    return n
              
            
    
def FunctionDefinition(t, x, requireName, functionForm):

    # t => an instance of Tokenizer
    f = Node(t)
    if f.type != consts["FUNCTION"]:
        f.type = (f.value == "get") and consts["GETTER"] or consts["SETTER"]
#     print f.type
    if t.match(consts["IDENTIFIER"]):
        f.name = t.token().value
    t.mustMatch(consts["LEFT_PAREN"])
    f.params = []

    while True:
        tt = t.get()
        print 'TT IZ',tt
        if tt==consts["RIGHT_PAREN"]: break
        if tt != consts["IDENTIFIER"]:
            raise NarcissusError("Missing formal parameters", t)
        f.params.append(t.token().value)
        if t.peek() != consts["RIGHT_PAREN"]:
            t.mustMatch(consts["COMMA"])

    t.mustMatch(consts["LEFT_CURLY"])
    x2 = CompilerContext(True)
    f.body = Script(t, x2)
    t.mustMatch(consts["RIGHT_CURLY"])
    f.end = t.token().end
    f.functionForm = functionForm
    if functionForm == consts.get("DECLARED_FORM"):
#         print 'okay'
        x.funDecls.append(f)

    return f

def Variables(t, x):

    n = Node(t)

    while True:
        t.mustMatch(consts["IDENTIFIER"])
        n2 = Node(t)
        n2.name = n2.value
        if t.match(consts["ASSIGN"]):
            if t.token().assignOp:
                raise NarcissusError("Invalid variable initialization", t)
#             print 'Initializing var...'
            n2.initializer = Expression(t, x, consts["COMMA"])

        n2.readOnly = ( n.type == consts["CONST"])
        # print 'vars=>',n2.type
#         print 'Starting to push'
        n.push(n2)
#         print "Push ended"        
        x.varDecls.append(n2)
        if not t.match(consts["COMMA"]): break
        
    return n

def ParenExpression(t, x):
    t.mustMatch(consts["LEFT_PAREN"])
    n = Expression(t, x)
    t.mustMatch(consts["RIGHT_PAREN"])
    return n

def Expression(t, x, stop = None):
    operators = List2()
    operands = List2()

    print 'In Expression',len(operands)

    bl = x.bracketLevel
    cl = x.curlyLevel
    pl = x.parenLevel
    hl = x.hookLevel

    def Reduce(operators, operands, t):
        # print 'Reduce called!'
        #for item in operators:
        #    print 'operator=>',item
            
        n = operators.pop()
        print 'N=>',n.type
        op = n.type
        arity = opArity[op]
        print 'Arity=>',arity
        if arity == -2:
            if len(operands) >= 2:
                # Flatten left-associative trees
                left = operands[len(operands) - 2]
                print 'Left=>',left
                
                if left.type == op:
                    print 'Dude!'
                    right = operands.pop()
                    left.append(right)
                    return (operators, operands, left)

            arity = 2

        # Always use push to add operands to n, to update start and end.
        # print 'Before slicing =>',len(operands)
        startidx, endidx = len(operands)-arity, 2*len(operands) - arity
        a = operands[startidx:endidx]
        operands = List2(operands[:startidx])
        # print 'After slicing =>',len(operands)
        # for x in operands:
        #     print "Optype=>",x.type
            
#         print a
#         print arity
        for x in range(arity):
#             print x
#             print a[x]
            # print 'Type=>',a[x].type
            n.push(a[x])

        # Include closing bracket or postfix operator in [start,end).
        if n.end < t.token().end:
            n.end = t.token().end

        operands.append(n)
        # print 'Operands length =>',len(operands)
        return (operators, operands, n)

    while True: # (t.token() and t.token().type != consts["END"]):
        if (t.token() and t.token().type == consts["END"]): break
        tt = t.get()
        if tt  == consts["END"]: break
        
        print 'TT ==>',tt
        # Stop only if tt matches the optional stop parameter, and that
        # token is not quoted by some kind of bracket.        
        if (tt==stop) and \
           (x.bracketLevel == bl) and \
           (x.curlyLevel == cl) and \
           (x.parenLevel == pl) and \
           (x.hookLevel == hl):
            break

        if tt == consts["SEMICOLON"]:
            # NB: cannot be empty, Statement handled that.
            break
        elif (tt==consts["ASSIGN"]) or \
             (tt==consts["HOOK"]) or \
             (tt==consts["COLON"]):
            if t.scanOperand:
                break

#             print 'here....'
#             print operators
#             print operands
#             print len(operands)
            # Use >, not >=, for right-associative ASSIGN and HOOK/COLON.            
            while len(operators) > 0 and \
                  opPrecedence.get(operators.last().type) and \
                  (opPrecedence.get(operators.last().type) > opPrecedence.get(tt)):

                operators, operands, ret = Reduce(operators, operands, t)

            # print 'Operands length2 =>',len(operands)
            if tt == consts["COLON"]:
                n = operators.last()
                if n.type != consts["HOOK"]:
                    raise NarcissusError("Invalid label", t)
            
                n.type = consts["CONDITIONAL"]
                x.hookLevel -= 1
            else:
                operators.append(Node(t))
                if tt == consts["ASSIGN"]:
#                     print operands
                    operands.last().assignOp = t.token().assignOp
                else:
                    x.hookLevel += 1 # tt == HOOK

            t.scanOperand = True

        # Treat comma as left-associative so reduce can fold left-heavy
        # COMMA trees into a single array.
        elif tt in (consts["COMMA"], consts["OR"], consts["AND"], consts["BITWISE_OR"],
                    consts["BITWISE_XOR"], consts["BITWISE_AND"], consts["EQ"],
                    consts["NE"], consts["STRICT_EQ"], consts["STRICT_NE"],
                    consts["LT"], consts["LE"], consts["GE"], consts["GT"],
                    consts["INSTANCEOF"], consts["LSH"], consts["RSH"],
                    consts["URSH"], consts["PLUS"], consts["MINUS"], consts["MUL"],
                    consts["DIV"], consts["MOD"], consts["DOT"], consts["IN"]):

            # print 'here...'
            # An in operator should not be parsed if we're parsing the head of
            # a for (...) loop, unless it is in the then part of a conditional
            # expression, or parenthesized somehow.            
            if (tt == consts["IN"]) and \
               x.inForLoopInit and \
               x.hookLevel == 0 and \
               x.bracketLevel == 0 and \
               x.curlyLevel == 0 and \
               x.parenLevel == 0:
                break

            if t.scanOperand:
                break

            while (len(operators)) and \
                  (opPrecedence.get(operators.last().type)) and \
                  (opPrecedence.get(operators.last().type) >= opPrecedence.get(tt)):
                operators, operands, ret = Reduce(operators, operands, t)

            # print 'Operands length2 =>',len(operands)
            
            if tt == consts["DOT"]:
                t.mustMatch(consts["IDENTIFIER"])
                node = Node(t, consts["DOT"])
                node.push(operands.pop())
                node.push(Node(t))
                operands.append(node)
            else:
                operators.append(Node(t))
                # print operators
                t.scanOperand = True

        elif tt in (consts["DELETE"], consts["VOID"], consts["TYPEOF"],
                    consts["NOT"], consts["BITWISE_NOT"], consts["UNARY_PLUS"],
                    consts["UNARY_MINUS"], consts["NEW"]):

            if not t.scanOperand:
                break

            operators.append(Node(t))

        elif tt in (consts["INCREMENT"], consts["DECREMENT"]):
            if t.scanOperand:
                operators.append(Node(t)) # prefix increment or decrement
            else:
                # Use >, not >=, so postfix has higher precedence than prefix.
                while (len(operators)) and \
                      (opPrecedence.get(operators.last().type)) and \
                      (opPrecedence.get(operators.last().type) > opPrecedence.get(tt)):
                    operators, operands, ret = Reduce(operators, operands, t)                    

                n = Node(t, tt)
                n.push(operands.pop())
                n.postfix = True
                operands.append(n)

        elif tt == consts["FUNCTION"]:
#             print 'HERE'
            if not t.scanOperand:
                break
            operands.append(FunctionDefinition(t, x, False, consts.get("EXPRESSED_FORM")))
            t.scanOperand = False

        elif tt in (consts["NULL"], consts["THIS"], consts["TRUE"], consts["FALSE"],
                    consts["IDENTIFIER"], consts["NUMBER"], consts["STRING"],
                    consts["REGEXP"]):

            if not t.scanOperand:
                break
            # print 'HERE2'
            operands.append(Node(t))
#             print operands
            t.scanOperand = False

        elif tt == consts["LEFT_BRACKET"]:
            if t.scanOperand:
                # Array initialiser.  Parse using recursive descent, as the
                # sub-grammar here is not an operator grammar.
                n = Node(t, consts["ARRAY_INIT"])

                while True:
                    tt = t.peek()
                    if tt == consts["RIGHT_BRACKET"]: break
                    if tt == consts["COMMA"]:
                        print 'Tt Iz',t.get()
                        n.push(None)

                        # FIXME: What is this next ?
                        next

                    n.push(Expression(t, x, consts["COMMA"]))
                    if not t.match(consts["COMMA"]):
                        continue
                    
                t.mustMatch(consts["RIGHT_BRACKET"])
                operands.append(n)
                t.scanOperand = False
            else:
                # Property indexing operator.
                operators.append(Node(t, consts["INDEX"]))
                t.scanOperand = True
                x.bracketLevel += 1

        elif tt == consts["RIGHT_BRACKET"]:
            if t.scanOperand or x.bracketLevel == bl:
                break

            while True:
                operators, operands, ret = Reduce(operators, operands, t)
                if ret.type == consts["INDEX"]: break
                pass
            x.bracketLevel -= 1

        elif tt == consts["LEFT_CURLY"]:
            if not t.scanOperand:
                break
            # Object initialiser.  As for array initialisers (see above),
            # parse using recursive descent.
            x.curlyLevel += 1
            n = Node(t, consts["OBJECT_INIT"])
            
            if not t.match(consts["RIGHT_CURLY"]):
                while True:
                    tt = t.get()
                    print 'tt IZ',tt
                    if (t.token().value == 'get') or (t.token().value=='set') and (t.peek() == consts["IDENTIFIER"]):
                        if x.ecmaStrictMode:
                            raise NarcissusError("Illegal property accessor", t)
                        n.push(FunctionDefinition(t, x, True, consts["EXPRESSED_FORM"]))
                    elif tt in (consts["IDENTIFIER"], consts["NUMBER"], consts["STRING"]):
                        id = Node(t)
                    elif tt == consts["RIGHT_CURLY"]:
                        if x.ecmaStrictMode:
                            raise NarcissusError("Illegal training", t)
                    else:
                        raise NarcissusError("Invalid property name", t)

                    t.mustMatch(consts["COLON"])
                    n2 = Node(t, consts["PROPERTY_INIT"])
                    n2.push(id)
                    n2.push(Expression(t, x, consts["COMMA"]))
                    n.push(n2)                    
                    if not t.match(consts["COMMA"]): break

                t.mustMatch(consts["RIGHT_CURLY"])

            operands.append(n)
            t.scanOperand = False
            x.curlyLevel -= 1

        elif tt == consts["RIGHT_CURLY"]:
            if not t.scanOperand and x.curlyLevel != cl:
                raise NarcissusError("PANIC: right curly botch", t)
            break

        elif tt == consts["LEFT_PAREN"]:
            if t.scanOperand:
                operators.append(Node(t, consts["GROUP"]))
            else:
                print operators, type(operators)
                while len(operators) and \
                      opPrecedence.get(operators.last().type) and \
                      opPrecedence.get(operators.last().type) > opPrecedence.get(consts["NEW"]):
                    operators, operands, ret = Reduce(operators, operands, t)

                # Handle () now, to regularize the n-ary case for n > 0.
                # We must set scanOperand in case there are arguments and
                # the first one is a regexp or unary+/-.
                n = operators.last()
                # print n, n.type, consts["NEW"]
                t.scanOperand = True
                print 'I WENT HERE'
                if t.match(consts["RIGHT_PAREN"]):
                    if n != None and n.type == consts["NEW"]:
                        print "INSIDE" 
                        operators.pop()
                        n.push(operands.pop())
                    else:
                        print "OUTSIDE"
                        n = Node(t, consts["CALL"])
                        n.push(operands.pop())
                        n.push(Node(t, consts["LIST"]))

                    operands.append(n)
                    t.scanOperand = False
                    continue
   
                if n != None and n.type == consts["NEW"]:
                    n.type = consts["NEW_WITH_ARGS"]
                else:
                    operators.append(Node(t, consts["CALL"]))

            x.parenLevel += 1

        elif tt == consts["RIGHT_PAREN"]:
            if t.scanOperand or x.parenLevel == pl:
                break
            while True:
                print 'Operators =>',len(operators),len(operands)
                
                operators, operands, tt = Reduce(operators, operands, t)
                print 'TT=>',tt,tt.type
                if (tt.type == consts["GROUP"]) or \
                       (tt.type == consts["CALL"]) or \
                       (tt.type == consts["NEW_WITH_ARGS"]):
                    print 'Breaking'
                    break
                
            if tt != consts["GROUP"]:
                n = operands.last()
                if n[1].type != consts["COMMA"]:
                    n2 = n[1]
                    n[1] = Node(t, consts["LIST"])
                    n[1].push(n2)
                else:
                    n[1].type = consts["LIST"]

            x.parenLevel -= 1
                
        else:
            # Automatic semicolon insertion means we may scan across a newline
            # and into the beginning of another statement.  If so, break out of
            # the while loop and let the t.scanOperand logic handle errors.
            break

    if x.hookLevel != hl:
        raise NarcissusError("Missing : after ?", t)
    if t.scanOperand:
        raise NarcissusError("Missing operand", t)

    # Resume default mode, scanning for operands, not operators.
    t.scanOperand = True
    print 'Ungetting...'
    print t.unget()
#     print 'HERE4'    
    while len(operators) > 0:
        operators, operands, ret = Reduce(operators, operands, t)

    # print 'Operands length2 =>',len(operands)        
    return operands.pop()
        
def parse(source, filename, line = 1):
    t = Tokenizer(source, filename, line)
    x = CompilerContext(False)
    n = Script(t, x)
    if not t.done:
        raise NarcissusError("Syntax error", t)

    return n


        

            
            
        
    

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -