parser.rb

来自「Harvestman-最新版本」· RB 代码 · 共 1,205 行 · 第 1/4 页

RB
1,205
字号
gotoloopContinue = catch(:gotoloop) do#loop:        while true                puts "Before getting TT"                if ((tt = t.get) == $consts["END"])                  break                 end                puts "TT ==> " + tt.to_s                # 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                        throw :gotoloop, true                end                                case tt                        when $consts["SEMICOLON"]                                # NB: cannot be empty, Statement handled that.                                throw :gotoloop, true;                                                when $consts["ASSIGN"], $consts["HOOK"], $consts["COLON"]                                if t.scanOperand                                        throw :gotoloop, true                                end                                                                                                # Use >, not >=, for right-associative ASSIGN and HOOK/COLON.                                while operators.length > 0 && $opPrecedence[operators.last.type] && $opPrecedence[operators.last.type] > $opPrecedence[tt]                                        reduce(operators, operands, t)                                end                                if tt == $consts["COLON"]                                        n = operators.last                                        raise SyntaxError.new("Invalid label", t) if n.type != $consts["HOOK"]                                        n.type = $consts["CONDITIONAL"]                                        x.hookLevel -= 1                                else                                        operators.push(Node.new(t))                                        if tt == $consts["ASSIGN"]                                                operands.last.assignOp = t.token.assignOp                                        else                                                x.hookLevel += 1 # tt == HOOK                                        end                                end                                t.scanOperand = true                                                when $consts["COMMA"],                                # Treat comma as left-associative so reduce can fold left-heavy                                # COMMA trees into a single array.                                $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"]                                # 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                                        throw :gotoloop, true                                end                                                                if t.scanOperand                                        throw :gotoloop, true                                end                                reduce(operators, operands, t) while operators.length > 0 && $opPrecedence[operators.last.type] && $opPrecedence[operators.last.type] >= $opPrecedence[tt]                                if tt == $consts["DOT"]                                        t.mustMatch($consts["IDENTIFIER"])                                        node = Node.new(t, $consts["DOT"])                                        node.push(operands.pop)                                        node.push(Node.new(t))                                        operands.push(node)                                else                                        operators.push(Node.new(t))                                        t.scanOperand = true                                end                                                when $consts["DELETE"], $consts["VOID"], $consts["TYPEOF"], $consts["NOT"],                                $consts["BITWISE_NOT"], $consts["UNARY_PLUS"], $consts["UNARY_MINUS"],                                $consts["NEW"]                                if !t.scanOperand                                        throw :gotoloop, true                                end                                operators.push(Node.new(t))                                                when $consts["INCREMENT"], $consts["DECREMENT"]                                if t.scanOperand                                        operators.push(Node.new(t)) # prefix increment or decrement                                else                                        # Use >, not >=, so postfix has higher precedence than prefix.                                        reduce(operators, operands, t) while operators.length > 0 && $opPrecedence[operators.last.type] && $opPrecedence[operators.last.type] > $opPrecedence[tt]                                        n = Node.new(t, tt)                                        n.push(operands.pop)                                        n.postfix = true                                        operands.push(n)                                end                                                when $consts["FUNCTION"]                                if !t.scanOperand                                        throw :gotoloop, true                                end                                # puts "EXPRESSED FORM=> " + $consts["EXPRESSED_FORM"]                                operands.push(FunctionDefinition(t, x, false, $consts["EXPRESSED_FORM"]))                                t.scanOperand = false                                                when $consts["NULL"], $consts["THIS"], $consts["TRUE"], $consts["FALSE"],                                $consts["IDENTIFIER"], $consts["NUMBER"], $consts["STRING"],                                $consts["REGEXP"]                                if !t.scanOperand                                        puts "THrowing"                                        throw :gotoloop, true                                end                                puts "No throw"                                operands.push(Node.new(t))                                t.scanOperand = false                                                when $consts["LEFT_BRACKET"]                                if t.scanOperand                                        # Array initialiser.  Parse using recursive descent, as the                                        # sub-grammar here is not an operator grammar.                                        n = Node.new(t, $consts["ARRAY_INIT"])                                        while (tt = t.peek) != $consts["RIGHT_BRACKET"]                                                if tt == $consts["COMMA"]                                                        t.get                                                        n.push(nil)                                                        next                                                end                                                n.push(Expression(t, x, $consts["COMMA"]))                                                break if !t.match($consts["COMMA"])                                        end                                        t.mustMatch($consts["RIGHT_BRACKET"])                                        operands.push(n)                                        t.scanOperand = false                                else                                        # Property indexing operator.                                        operators.push(Node.new(t, $consts["INDEX"]))                                        t.scanOperand = true                                        x.bracketLevel += 1                                end                                                when $consts["RIGHT_BRACKET"]                                if t.scanOperand or x.bracketLevel == bl                                        throw :gotoloop, true                                end                                while reduce(operators, operands, t).type != $consts["INDEX"]                                        nil                                end                                x.bracketLevel -= 1                                                when $consts["LEFT_CURLY"]                                if !t.scanOperand                                        throw :gotoloop, true                                end                                # Object initialiser.  As for array initialisers (see above),                                # parse using recursive descent.                                x.curlyLevel += 1                                n = Node.new(t, $consts["OBJECT_INIT"])catch(:gotoobject_init) do#object_init:                                if !t.match($consts["RIGHT_CURLY"])                                        begin                                                tt = t.get                                                if (t.token.value == "get" or t.token.value == "set") and t.peek == $consts["IDENTIFIER"]                                                        raise SyntaxError.new("Illegal property accessor", t) if x.ecmaStrictMode                                                        n.push(FunctionDefinition(t, x, true, $consts["EXPRESSED_FORM"]))                                                else                                                        case tt                                                                when $consts["IDENTIFIER"], $consts["NUMBER"], $consts["STRING"]                                                                        id = Node.new(t)                                                                                                                                when $consts["RIGHT_CURLY"]                                                                        raise SyntaxError.new("Illegal trailing ,", t) if x.ecmaStrictMode                                                                        throw :gotoobject_init                                                                                                                                else                                                                        raise SyntaxError.new("Invalid property name", t)                                                        end                                                        t.mustMatch($consts["COLON"])                                                        n2 = Node.new(t, $consts["PROPERTY_INIT"])                                                        n2.push(id)                                                        n2.push(Expression(t, x, $consts["COMMA"]))                                                        n.push(n2)                                                end                                        end while t.match($consts["COMMA"])                                        t.mustMatch($consts["RIGHT_CURLY"])                                end                                operands.push(n)                                t.scanOperand = false                                x.curlyLevel -= 1end                        when $consts["RIGHT_CURLY"]                                raise SyntaxError.new("PANIC: right curly botch", t) if !t.scanOperand and x.curlyLevel != cl                                throw :gotoloop, true                                                when $consts["LEFT_PAREN"]                                if t.scanOperand                                        operators.push(Node.new(t, $consts["GROUP"]))                                else                                        reduce(operators, operands, t) while operators.length > 0 && $opPrecedence[operators.last.type] && $opPrecedence[operators.last.type] > $opPrecedence[$consts["NEW"]]                                        # 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                                        puts n.to_s + " " + n.type.to_s + " " + $consts["NEW"].to_s                                        t.scanOperand = true                                        puts "I WENT HERE"                                        if t.match($consts["RIGHT_PAREN"])                                                if n && n.type == $consts["NEW"]                                                        puts "INSIDE"                                                        operators.pop                                                        n.push(operands.pop)                                                        puts "AFTER*"                                                else                                                        puts "OUTSIDE"                                                        n = Node.new(t, $consts["CALL"])                                                        n.push(operands.pop)                                                        n.push(Node.new(t, $consts["LIST"]))                                                end                                                puts "AFTER2*"                                                operands.push(n)                                                t.scanOperand = false                                                #puts "woah"                                                puts "BEFOREBREAK"                                                break                                        end                                        if n && n.type == $consts["NEW"]                                                n.type = $consts["NEW_WITH_ARGS"]                                        else                                                operators.push(Node.new(t, $consts["CALL"]))                                        end                                end                                x.parenLevel += 1                                                        when $consts["RIGHT_PAREN"]                                if t.scanOperand or x.parenLevel == pl                                        throw :gotoloop, true                                end                                                                #while (tt = reduce(operators, operands, t).type) != $consts["GROUP"] \                                #                and tt != $consts["CALL"] and tt != $consts["NEW_WITH_ARGS"]                                #        nil                                #end                                while true                                      puts "Operators => " + operators.length.to_s + " " + operands.length.to_s                                      tt = reduce(operators, operands, t)                                      puts "TT=> " + tt.to_s + " " + tt.type.to_s                                      if tt.type == $consts["GROUP"] or tt.type == $consts["CALL"] or tt.type == $consts["NEW_WITH_ARGS"]                                         puts "Breaking..."                                         break                                         end                                    end                                if tt != $consts["GROUP"]                                        n = operands.last                                        if n[1].type != $consts["COMMA"]                                                n2 = n[1]                                                n[1] = Node.new(t, $consts["LIST"])                                                n[1].push(n2)                                        else                                                n[1].type = $consts["LIST"]                                        end                                end                                x.parenLevel -= 1                                                        # 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.                        else                                throw :gotoloop, true                end        endendend        raise SyntaxError.new("Missing : after ?", t) if x.hookLevel != hl        raise SyntaxError.new("Missing operand", t) if t.scanOperand                        # Resume default mode, scanning for operands, not operators.        t.scanOperand = true        puts "Ungetting"        puts t.unget        reduce(operators, operands, t) while operators.length > 0        return operands.popenddef parse (source, filename, line = 1)        t = Tokenizer.new(source, filename, line)        x = CompilerContext.new(false)        n = Script(t, x)        raise SyntaxError.new("Syntax error", t) if !t.done    return nend

⌨️ 快捷键说明

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