class RubyRunJs::Parser

Constants

Messages

Error messages should be identical to V8.

PropertyKind
Syntax
Token
TokenName

Public Instance Methods

addComment(type, value, start, end1, loc) click to toggle source

The following defs are needed only when the option to preserve the comments is active.

# File lib/ruby_run_js/jsparser.rb, line 2939
def addComment(type, value, start, end1, loc) 
    assert(start.instance_of? Fixnum, 'Comment must have valid position')

    # Because the way the actual token is scanned, often the comments
    # (if any) are skipped twice during the lexical analysis.
    # Thus, we need to skip adding a comment if the comment array already
    # handled it.
    if (@extra[:comments].length > 0) 
        if (@extra[:comments][@extra[:comments].length - 1][:range][1] > start) 
            return
        end
    end

    @extra[:comments].push({
        type: type,
        value: value,
        range: [start, end1],
        loc: loc
    })
end
advance() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 934
def advance()
    skipComment()

    if (@index >= @length) 
        return {
            type: Token[:EOF],
            lineNumber: @lineNumber,
            lineStart: @lineStart,
            range: [@index, @index]
        }
    end

    token = scanPunctuator()
    if token != nil
        return token
    end

    ch = @source[@index]

    if (ch == "'" || ch == '"') 
        return scanStringLiteral()
    end

    if (ch == '.' || isDecimalDigit(ch)) 
        return scanNumericLiteral()
    end

    token = scanIdentifier()
    if token != nil
        return token
    end

    throwError(nil, Messages[:UnexpectedToken], 'ILLEGAL')
end
assert(condition, message) click to toggle source

Ensure the condition is true, otherwise throw an error. This is only to have a better contract semantic, i. another safety net to catch a logic error. The condition shall be fulfilled in normal case. Do NOT use this to enforce a certain condition on any user input.

# File lib/ruby_run_js/jsparser.rb, line 124
def assert(condition, message)
    if (!condition) 
        raise SyntaxError.new 'ASSERT: ' + message
    end
end
collectRegex() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 3131
def collectRegex() 
    skipComment()

    pos = @index
    loc = {
        start: {
            line: @lineNumber,
            column: @index - @lineStart
        }
    }

    regex = @extra.scanRegExp()
    loc[:end] = {
        line: @lineNumber,
        column: @index - @lineStart
    }

    # Pop the previous token, which is likely '/' or '/='
    if (@extra[:tokens].length > 0) 
        token = @extra[:tokens][@extra[:tokens].length - 1]
        if (token[:range][0] == pos && token[:type] == 'Punctuator') 
            if (token[:value] == '/' || token[:value] == '/=') 
                @extra[:tokens].pop()
            end
        end
    end

    @extra[:tokens].push({
        type: 'RegularExpression',
        value: regex[:literal],
        range: [pos, @index],
        loc: loc
    })

    return regex
end
collectToken() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 3101
def collectToken() 
    skipComment()
    start = @index
    loc = {
        start: {
            line: @lineNumber,
            column: @index - @lineStart
        }
    }

    token = @extra.advance()
    loc[:end] = {
        line: @lineNumber,
        column: @index - @lineStart
    }

    if (token[:type] != Token[:EOF]) 
        range = [token[:range][0], token[:range][1]]
        value = sliceSource(token[:range][0], token[:range][1])
        @extra[:tokens].push({
            type: TokenName[token[:type]],
            value: value,
            range: range,
            loc: loc
        })
    end

    return token
end
consumeSemicolon() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1125
def consumeSemicolon() 
    # Catch the very common case first.
    if (@source[@index] == ';') 
        lex()
        return
    end

    line = @lineNumber
    skipComment()
    if (@lineNumber != line) 
        return
    end

    if (match(';')) 
        lex()
        return
    end

    token = lookahead()
    if (token[:type] != Token[:EOF] && !match('}')) 
        throwUnexpected(token)
    end
end
createLiteral(token) click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 3189
def createLiteral(token)
    unless @extra[:raw]
        return {
            type: Syntax[:Literal],
            value: token[:value]
        }
    end

    return {
        type: Syntax[:Literal],
        value: token[:value],
        raw: sliceSource(token[:range][0], token[:range][1])
    }
end
createLocationMarker() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 3204
def createLocationMarker() 
    marker = {}

    marker[:range] = [@index, @index]
    marker[:loc] = {
        start: {
            line: @lineNumber,
            column: @index - @lineStart
        },
        end: {
            line: @lineNumber,
            column: @index - @lineStart
        }
    }

    marker[:end] = lambda {
        this.range[1] = @index
        this[:loc][:end][:line] = @lineNumber
        this[:loc][:end][:column] = @index - @lineStart
    }

    marker[:applyGroup] = lambda do |node| 
        if (@extra[:range]) 
            node[:groupRange] = [this.range[0], this.range[1]]
        end
        if (@extra[:loc]) 
            node[:groupLoc] = {
                start: {
                    line: this[:loc].start[:line],
                    column: this[:loc][:start][:column]
                },
                end: {
                    line: this[:loc].end[:line],
                    column: this[:loc][:end][:column]
                }
            }
        end
    end

    marker[:apply] = lambda do |node| 
        if (@extra[:range]) 
            node[:range] = [this.range[0], this.range[1]]
        end
        if (@extra[:loc]) 
            node[:loc] = {
                start: {
                    line: this[:loc].start[:line],
                    column: this[:loc][:start][:column]
                },
                end: {
                    line: this[:loc].end[:line],
                    column: this[:loc][:end][:column]
                }
            }
        end
    end

    return marker
end
curCharAndMoveNext() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 234
def curCharAndMoveNext
    c = @source[@index]
    @index += 1
    c
end
expect(value) click to toggle source

Expect the next token to match the specified punctuator. If not, an exception will be thrown.

# File lib/ruby_run_js/jsparser.rb, line 1071
def expect(value) 
    token = lex()
    if (token[:type] != Token[:Punctuator] || token[:value] != value) 
        throwUnexpected(token)
    end
end
expectKeyword(keyword) click to toggle source

Expect the next token to match the specified keyword. If not, an exception will be thrown.

# File lib/ruby_run_js/jsparser.rb, line 1081
def expectKeyword(keyword) 
    token = lex()
    if (token[:type] != Token[:Keyword] || token[:value] != keyword) 
        throwUnexpected(token)
    end
end
filterCommentLocation() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 3080
def filterCommentLocation() 
    comments = []

    @extra[:comments].length.times do |i|
        entry = @extra.comments[i]
        comment = {
            type: entry[:type],
            value: entry[:value]
        }
        if (@extra[:range]) 
            comment[:range] = entry[:range]
        end
        if (@extra[:loc]) 
            comment[:loc] = entry[:loc]
        end
        comments.push(comment)
    end

    @extra[:comments] = comments
end
filterTokenLocation() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 3168
def filterTokenLocation() 
    tokens = []

    @extra[:tokens].length.times do |i|
        entry = @extra[:tokens][i]
        token = {
            type: entry[:type],
            value: entry[:value]
        }
        if (@extra[:range]) 
            token[:range] = entry[:range]
        end
        if (@extra[:loc]) 
            token[:loc] = entry[:loc]
        end
        tokens.push(token)
    end

    @extra[:tokens] = tokens
end
isDecimalDigit(ch) click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 134
def isDecimalDigit(ch) 
    return ch && '0123456789'.include?(ch)
end
isFutureReservedWord(id) click to toggle source

7.6.1.2 Future Reserved Words

# File lib/ruby_run_js/jsparser.rb, line 180
def isFutureReservedWord(id)
    %w(class enum export extends import super).include? id
end
isHexDigit(ch) click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 138
def isHexDigit(ch)
    return ch && '0123456789abcdefABCDEF'.include?(ch)
end
isIdentifierName(token) click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 927
def isIdentifierName(token) 
    return token[:type] == Token[:Identifier] ||
        token[:type] == Token[:Keyword] ||
        token[:type] == Token[:BooleanLiteral] ||
        token[:type] == Token[:NullLiteral]
end
isIdentifierPart(ch) click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 171
def isIdentifierPart(ch) 
    return (ch == "$") || (ch == "_") || (ch == "\\") ||
        (ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z") ||
        ((ch >= "0") && (ch <= "9")) ||
      false#  ((ch.ord() >= 0x80) && NonAsciiIdentifierPart.match?(ch))
end
isIdentifierStart(ch) click to toggle source

7.6 Identifier Names and Identifiers

# File lib/ruby_run_js/jsparser.rb, line 165
def isIdentifierStart(ch) 
    return (ch == "$") || (ch == "_") || (ch == "\\") ||
        (ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z") ||
     false#  ((ch.ord() >= 0x80) && NonAsciiIdentifierStart.match?(ch))
end
isKeyword(id) click to toggle source

7.6.1.1 Keywords

# File lib/ruby_run_js/jsparser.rb, line 194
def isKeyword(id)
    keyword = false
    case id.length
    when 2
        keyword = (id == 'if') || (id == 'in') || (id == 'do')
    when 3
        keyword = (id == 'var') || (id == 'for') || (id == 'new') || (id == 'try')
    when 4
        keyword = (id == 'this') || (id == 'else') || (id == 'case') || (id == 'void') || (id == 'with')
    when 5
        keyword = (id == 'while') || (id == 'break') || (id == 'catch') || (id == 'throw')
    when 6
        keyword = (id == 'return') || (id == 'typeof') || (id == 'delete') || (id == 'switch')
    when 7
        keyword = (id == 'default') || (id == 'finally')
    when 8
        keyword = (id == 'function') || (id == 'continue') || (id == 'debugger')
    when 10
        keyword = (id == 'instanceof')
    end

    return true if keyword

    case id
    # Future reserved words.
    # 'const' is specialized as Keyword in V8.
    when 'const'
        return true
    # For compatiblity to SpiderMonkey and ES[:next]
    when 'yield','let'
        return true
    end

    if (@strict && isStrictModeReservedWord(id)) 
        return true
    end

    return isFutureReservedWord(id)
end
isLeftHandSide(expr) click to toggle source

Return true if provided expression is LeftHandSideExpression

# File lib/ruby_run_js/jsparser.rb, line 1151
def isLeftHandSide(expr) 
    return expr[:type] == Syntax[:Identifier] || expr[:type] == Syntax[:MemberExpression]
end
isLineTerminator(ch) click to toggle source

7.3 Line Terminators

# File lib/ruby_run_js/jsparser.rb, line 159
def isLineTerminator(ch)
    ["\n", "\r" ,"\u2028", "\u2029"].include?(ch)
end
isOctalDigit(ch) click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 142
def isOctalDigit(ch)
    return ch && '01234567'.include?(ch)
end
isRestrictedWord(id) click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 188
def isRestrictedWord(id) 
    return id == 'eval' || id == 'arguments'
end
isStrictModeReservedWord(id) click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 184
def isStrictModeReservedWord(id)
    %w(implements interface package private protected public static yield let).include? id
end
isWhiteSpace(ch) click to toggle source

7.2 White Space

# File lib/ruby_run_js/jsparser.rb, line 149
def isWhiteSpace(ch) 
    return false unless ch
    return (ch == " ") || (ch == "\u0009") || (ch == "\u000B") ||
        (ch == "\u000C") || (ch == "\u00A0") ||
        (ch.ord() >= 0x1680 &&
        "\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF".include?(ch))
end
lex() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 969
def lex()

    if (@buffer) 
        @index = @buffer[:range][1]
        @lineNumber = @buffer[:lineNumber]
        @lineStart = @buffer[:lineStart]
        token = @buffer
        @buffer = nil
        return token
    end

    @buffer = nil
    return advance()
end
lookahead() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 984
def lookahead() 

    if (@buffer != nil) 
        return @buffer
    end

    pos = @index
    line = @lineNumber
    start = @lineStart
    @buffer = advance()
    @index = pos
    @lineNumber = line
    @lineStart = start

    return @buffer
end
match(value) click to toggle source

Return true if the next token matches the specified punctuator.

# File lib/ruby_run_js/jsparser.rb, line 1090
def match(value) 
    token = lookahead()
    return token[:type] == Token[:Punctuator] && token[:value] == value
end
matchAssign() click to toggle source

Return true if the next token is an assignment operator

# File lib/ruby_run_js/jsparser.rb, line 1104
def matchAssign() 
    token = lookahead()
    op = token[:value]

    if (token[:type] != Token[:Punctuator]) 
        return false
    end
    return op == '=' ||
        op == '*=' ||
        op == '/=' ||
        op == '%=' ||
        op == '+=' ||
        op == '-=' ||
        op == '<<=' ||
        op == '>>=' ||
        op == '>>>=' ||
        op == '&=' ||
        op == '^=' ||
        op == '|='
end
matchKeyword(keyword) click to toggle source

Return true if the next token matches the specified keyword

# File lib/ruby_run_js/jsparser.rb, line 1097
def matchKeyword(keyword) 
    token = lookahead()
    return token[:type] == Token[:Keyword] && token[:value] == keyword
end
parse(code, options = nil) click to toggle source

def filterGroup(node)

n = (node.instance_of?(Array)) ? [] : {}
for (i in node) {
    if (node.hasOwnProperty(i) && i != 'groupRange' && i != 'groupLoc') 
        entry = node[i]
        if (entry == nil || typeof entry != 'object' || entry instanceof RegExp) 
            n[i] = entry
        else
            n[i] = filterGroup(entry)
        end
    end
end
return n

end

# File lib/ruby_run_js/jsparser.rb, line 3368
def parse(code, options = nil)
    @source = code
    @index = 0
    @lineNumber = (@source.length > 0) ? 1 : 0
    @lineStart = 0
    @length = @source.length
    @buffer = nil
    @state = {
        allowIn: true,
        labelSet: {},
        indefBody: false,
        inIteration: false,
        inSwitch: false
    }

    @extra = {}

    @extra[:range] = false
    @extra[:loc] = false
    @extra[:raw] = false

    if (options) 
        @extra[:range] = options[:range] == true
        @extra[:loc] = options[:loc] == true
        @extra[:raw] = options[:raw] = true
        if (options[:tokens]) 
            @extra[:tokens] = []
        end
        if (options[:comment]) 
            @extra[:comments] = []
        end
        if (options[:tolerant]) 
            @extra[:errors] = []
        end
    end

    
    program = parseProgram()

    if (@extra[:comments]) 
        filterCommentLocation()
        program[:comments] = @extra[:comments]
    end
    if (@extra[:tokens]) 
        filterTokenLocation()
        program[:tokens] = @extra[:tokens]
    end
    if (@extra[:errors]) 
        program[:errors] = @extra[:errors]
    end
    if (@extra[:range] || @extra[:loc]) 
 #       program[:body] = filterGroup(program[:body])
    end

    return program
end
parseAdditiveExpression() click to toggle source

11.6 Additive Operators

# File lib/ruby_run_js/jsparser.rb, line 1647
def parseAdditiveExpression() 
    expr = parseMultiplicativeExpression()

    while (match('+') || match('-')) 
        expr = {
            type: Syntax[:BinaryExpression],
            operator: lex()[:value],
            left: expr,
            right: parseMultiplicativeExpression()
        }
    end

    return expr
end
parseArguments() click to toggle source

11.2 Left-Hand-Side Expressions

# File lib/ruby_run_js/jsparser.rb, line 1419
def parseArguments() 
    args = []

    expect('(')

    if (!match(')')) 
        while (@index < @length) 
            args.push(parseAssignmentExpression())
            if (match(')')) 
                break
            end
            expect(',')
        end
    end

    expect(')')

    return args
end
parseArrayInitialiser() click to toggle source

11.1.4 Array Initialiser

# File lib/ruby_run_js/jsparser.rb, line 1157
def parseArrayInitialiser() 
    elements = []

    expect('[')

    while (!match(']')) 
        if (match(',')) 
            lex()
            elements.push(nil)
        else
            elements.push(parseAssignmentExpression())

            if (!match(']')) 
                expect(',')
            end
        end
    end

    expect(']')

    return {
        type: Syntax[:ArrayExpression],
        elements: elements
    }
end
parseAssignmentExpression() click to toggle source

11.13 Assignment Operators

# File lib/ruby_run_js/jsparser.rb, line 1827
def parseAssignmentExpression()

    token = lookahead()
    expr = parseConditionalExpression()

    if (matchAssign()) 
        # LeftHandSideExpression
        if (!isLeftHandSide(expr)) 
            throwErrorTolerant(nil, Messages[:InvalidLHSInAssignment])
        end

        # 11.13.1
        if (@strict && expr[:type] == Syntax[:Identifier] && isRestrictedWord(expr[:name])) 
            throwErrorTolerant(token, Messages[:StrictLHSAssignment])
        end

        expr = {
            type: Syntax[:AssignmentExpression],
            operator: lex()[:value],
            left: expr,
            right: parseAssignmentExpression()
        }
    end

    return expr
end
parseBitwiseANDExpression() click to toggle source

11.10 Binary Bitwise Operators

# File lib/ruby_run_js/jsparser.rb, line 1718
def parseBitwiseANDExpression() 
    expr = parseEqualityExpression()

    while (match('&')) 
        lex()
        expr = {
            type: Syntax[:BinaryExpression],
            operator: '&',
            left: expr,
            right: parseEqualityExpression()
        }
    end

    return expr
end
parseBitwiseORExpression() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1750
def parseBitwiseORExpression() 
    expr = parseBitwiseXORExpression()

    while (match('|')) 
        lex()
        expr = {
            type: Syntax[:BinaryExpression],
            operator: '|',
            left: expr,
            right: parseBitwiseXORExpression()
        }
    end

    return expr
end
parseBitwiseXORExpression() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1734
def parseBitwiseXORExpression() 
    expr = parseBitwiseANDExpression()

    while (match('^')) 
        lex()
        expr = {
            type: Syntax[:BinaryExpression],
            operator: '^',
            left: expr,
            right: parseBitwiseANDExpression()
        }
    end

    return expr
end
parseBlock() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1897
def parseBlock() 

    expect('{')

    block = parseStatementList()

    expect('}')

    return {
        type: Syntax[:BlockStatement],
        body: block
    }
end
parseBreakStatement() click to toggle source

12.8 The break @statement

# File lib/ruby_run_js/jsparser.rb, line 2257
def parseBreakStatement() 
    token = nil
    label = nil

    expectKeyword('break')

    # Optimize the most common form: 'break'.
    if (@source[@index] == ';') 
        lex()

        if (!(@state[:inIteration] || @state[:inSwitch])) 
            throwError(nil, Messages[:IllegalBreak])
        end

        return {
            type: Syntax[:BreakStatement],
            label: nil
        }
    end

    if (peekLineTerminator()) 
        if (!(@state[:inIteration] || @state[:inSwitch])) 
            throwError(nil, Messages[:IllegalBreak])
        end

        return {
            type: Syntax[:BreakStatement],
            label: nil
        }
    end

    token = lookahead()
    if (token[:type] == Token[:Identifier]) 
        label = parseVariableIdentifier()

        if (false) 
            throwError(nil, Messages[:UnknownLabel], label[:name])
        end
    end

    consumeSemicolon()

    if (label == nil && !(@state[:inIteration] || @state[:inSwitch])) 
        throwError(nil, Messages[:IllegalBreak])
    end

    return {
        type: Syntax[:BreakStatement],
        label: label
    }
end
parseCatchClause() click to toggle source

12.14 The try @statement

# File lib/ruby_run_js/jsparser.rb, line 2486
def parseCatchClause()

    expectKeyword('catch')

    expect('(')
    if (match(')')) 
        throwUnexpected(lookahead())
    end

    param = parseVariableIdentifier()
    # 12.14.1
    if (@strict && isRestrictedWord(param[:name])) 
        throwErrorTolerant(nil, Messages[:StrictCatchVariable])
    end

    expect(')')

    return {
        type: Syntax[:CatchClause],
        param: param,
        body: parseBlock()
    }
end
parseComputedMember() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1458
def parseComputedMember()

    expect('[')

    expr = parseExpression()

    expect(']')

    return expr
end
parseConditionalExpression() click to toggle source

11.12 Conditional Operator

# File lib/ruby_run_js/jsparser.rb, line 1802
def parseConditionalExpression()

    expr = parseLogicalORExpression()

    if (match('?')) 
        lex()
        previousAllowIn = @state[:allowIn]
        @state[:allowIn] = true
        consequent = parseAssignmentExpression()
        @state[:allowIn] = previousAllowIn
        expect(':')

        expr = {
            type: Syntax[:ConditionalExpression],
            test: expr,
            consequent: consequent,
            alternate: parseAssignmentExpression()
        }
    end

    return expr
end
parseConstLetDeclaration(kind) click to toggle source

kind may be `const` or `let` Both are experimental and not in the specification yet. see #wiki[:ecmascript].org/doku.php?id=harmony:const and #wiki[:ecmascript].org/doku.php?id=harmony:let

# File lib/ruby_run_js/jsparser.rb, line 1982
def parseConstLetDeclaration(kind) 

    expectKeyword(kind)

    declarations = parseVariableDeclarationList(kind)

    consumeSemicolon()

    return {
        type: Syntax[:VariableDeclaration],
        declarations: declarations,
        kind: kind
    }
end
parseContinueStatement() click to toggle source

12.7 The continue @statement

# File lib/ruby_run_js/jsparser.rb, line 2203
def parseContinueStatement() 
    token = nil
    label = nil

    expectKeyword('continue')

    # Optimize the most common form: 'continue'.
    if (@source[@index] == ';') 
        lex()

        if (!@state[:inIteration]) 
            throwError(nil, Messages[:IllegalContinue])
        end

        return {
            type: Syntax[:ContinueStatement],
            label: nil
        }
    end

    if (peekLineTerminator()) 
        if (!@state[:inIteration]) 
            throwError(nil, Messages[:IllegalContinue])
        end

        return {
            type: Syntax[:ContinueStatement],
            label: nil
        }
    end

    token = lookahead()
    if (token[:type] == Token[:Identifier]) 
        label = parseVariableIdentifier()

        if (false) 
            throwError(nil, Messages[:UnknownLabel], label[:name])
        end
    end

    consumeSemicolon()

    if (label == nil && !@state[:inIteration]) 
        throwError(nil, Messages[:IllegalContinue])
    end

    return {
        type: Syntax[:ContinueStatement],
        label: label
    }
end
parseDebuggerStatement() click to toggle source

12.15 The debugger @statement

# File lib/ruby_run_js/jsparser.rb, line 2542
def parseDebuggerStatement() 
    expectKeyword('debugger')

    consumeSemicolon()

    return {
        type: Syntax[:DebuggerStatement]
    }
end
parseDoWhileStatement() click to toggle source

12.6 Iteration Statements

# File lib/ruby_run_js/jsparser.rb, line 2051
def parseDoWhileStatement() 
    expectKeyword('do')

    oldInIteration = @state[:inIteration]
    @state[:inIteration] = true

    body = parseStatement()

    @state[:inIteration] = oldInIteration

    expectKeyword('while')

    expect('(')

    test = parseExpression()

    expect(')')

    if (match(';')) 
        lex()
    end

    return {
        type: Syntax[:DoWhileStatement],
        body: body,
        test: test
    }
end
parseEmptyStatement() click to toggle source

12.3 Empty Statement

# File lib/ruby_run_js/jsparser.rb, line 1999
def parseEmptyStatement() 
    expect(';')

    return {
        type: Syntax[:EmptyStatement]
    }
end
parseEqualityExpression() click to toggle source

11.9 Equality Operators

# File lib/ruby_run_js/jsparser.rb, line 1701
def parseEqualityExpression() 
    expr = parseRelationalExpression()

    while (match('==') || match('!=') || match('===') || match('!==')) 
        expr = {
            type: Syntax[:BinaryExpression],
            operator: lex()[:value],
            left: expr,
            right: parseRelationalExpression()
        }
    end

    return expr
end
parseExpression() click to toggle source

11.14 Comma Operator

# File lib/ruby_run_js/jsparser.rb, line 1856
def parseExpression() 
    expr = parseAssignmentExpression()

    if (match(','))
        expr = {
            type: Syntax[:SequenceExpression],
            expressions: [ expr ]
        }

        while (@index < @length)
            if (!match(','))
                break
            end
            lex()
            expr[:expressions].push(parseAssignmentExpression())
        end

    end
    return expr
end
parseExpressionStatement() click to toggle source

12.4 Expression Statement

# File lib/ruby_run_js/jsparser.rb, line 2009
def parseExpressionStatement() 
    expr = parseExpression()

    consumeSemicolon()

    return {
        type: Syntax[:ExpressionStatement],
        expression: expr
    }
end
parseForStatement() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 2114
def parseForStatement() 
    init = nil
    test = nil
    update = nil
    left = nil

    expectKeyword('for')

    expect('(')

    if (match(';')) 
        lex()
    else
        if (matchKeyword('var') || matchKeyword('let')) 
            @state[:allowIn] = false
            init = parseForVariableDeclaration()
            @state[:allowIn] = true

            if (init[:declarations].length == 1 && matchKeyword('in')) 
                lex()
                left = init
                right = parseExpression()
                init = nil
            end
        else
            @state[:allowIn] = false
            init = parseExpression()
            @state[:allowIn] = true

            if (matchKeyword('in')) 
                # LeftHandSideExpression
                if (!isLeftHandSide(init))
                    throwErrorTolerant(nil, Messages[:InvalidLHSInForIn])
                end

                lex()
                left = init
                right = parseExpression()
                init = nil
            end
        end

        if (left == nil) 
            expect(';')
        end
    end

    if (left == nil) 

        if (!match(';')) 
            test = parseExpression()
        end
        expect(';')

        if (!match(')')) 
            update = parseExpression()
        end
    end

    expect(')')

    oldInIteration = @state[:inIteration]
    @state[:inIteration] = true

    body = parseStatement()

    @state[:inIteration] = oldInIteration

    if (left == nil) 
        return {
            type: Syntax[:ForStatement],
            init: init,
            test: test,
            update: update,
            body: body
        }
    end

    return {
        type: Syntax[:ForInStatement],
        left: left,
        right: right,
        body: body,
        each: false
    }
end
parseForVariableDeclaration() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 2104
def parseForVariableDeclaration() 
    token = lex()

    return {
        type: Syntax[:VariableDeclaration],
        declarations: parseVariableDeclarationList(),
        kind: token[:value]
    }
end
parseFunctionDeclaration() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 2701
def parseFunctionDeclaration() 
    params = []

    expectKeyword('function')
    token = lookahead()
    id = parseVariableIdentifier()
    if (@strict) 
        if (isRestrictedWord(token[:value])) 
            throwErrorTolerant(token, Messages[:StrictFunctionName])
        end
    else
        if (isRestrictedWord(token[:value])) 
            firstRestricted = token
            message = Messages[:StrictFunctionName]
        elsif (isStrictModeReservedWord(token[:value])) 
            firstRestricted = token
            message = Messages[:StrictReservedWord]
        end
    end

    expect('(')

    if (!match(')')) 
        paramSet = {}
        while (@index < @length) 
            token = lookahead()
            param = parseVariableIdentifier()
            if (@strict) 
                if (isRestrictedWord(token[:value])) 
                    stricted = token
                    message = Messages[:StrictParamName]
                end
                if (false)
                    stricted = token
                    message = Messages[:StrictParamDupe]
                end
            elsif (!firstRestricted) 
                if (isRestrictedWord(token[:value])) 
                    firstRestricted = token
                    message = Messages[:StrictParamName]
                elsif (isStrictModeReservedWord(token[:value])) 
                    firstRestricted = token
                    message = Messages[:StrictReservedWord]
                elsif (false) 
                    firstRestricted = token
                    message = Messages[:StrictParamDupe]
                end
            end
            params.push(param)
            paramSet[param[:name]] = true
            if (match(')')) 
                break
            end
            expect(',')
        end
    end

    expect(')')

    previousStrict = @strict
    body = parseFunctionSourceElements()
    if (@strict && firstRestricted) 
        throwError(firstRestricted, message)
    end
    if (@strict && stricted) 
        throwErrorTolerant(stricted, message)
    end
    @strict = previousStrict

    return {
        type: Syntax[:FunctionDeclaration],
        id: id,
        params: params,
        defaults: [],
        body: body,
        rest: nil,
        generator: false,
        expression: false
    }
end
parseFunctionExpression() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 2782
def parseFunctionExpression() 
     id = nil
     params = []

    expectKeyword('function')

    if (!match('(')) 
        token = lookahead()
        id = parseVariableIdentifier()
        if (@strict) 
            if (isRestrictedWord(token[:value])) 
                throwErrorTolerant(token, Messages[:StrictFunctionName])
            end
        else
            if (isRestrictedWord(token[:value])) 
                firstRestricted = token
                message = Messages[:StrictFunctionName]
            elsif (isStrictModeReservedWord(token[:value])) 
                firstRestricted = token
                message = Messages[:StrictReservedWord]
            end
        end
    end

    expect('(')

    if (!match(')')) 
        paramSet = {}
        while (@index < @length) 
            token = lookahead()
            param = parseVariableIdentifier()
            if (@strict) 
                if (isRestrictedWord(token[:value])) 
                    stricted = token
                    message = Messages[:StrictParamName]
                end
                if (false) 
                    stricted = token
                    message = Messages[:StrictParamDupe]
                end
            elsif (!firstRestricted) 
                if (isRestrictedWord(token[:value])) 
                    firstRestricted = token
                    message = Messages[:StrictParamName]
                elsif (isStrictModeReservedWord(token[:value])) 
                    firstRestricted = token
                    message = Messages[:StrictReservedWord]
                elsif (false) 
                    firstRestricted = token
                    message = Messages[:StrictParamDupe]
                end
            end
            params.push(param)
            paramSet[param[:name]] = true
            if (match(')')) 
                break
            end
            expect(',')
        end
    end

    expect(')')

    previousStrict = @strict
    body = parseFunctionSourceElements()
    if (@strict && firstRestricted) 
        throwError(firstRestricted, message)
    end
    if (@strict && stricted) 
        throwErrorTolerant(stricted, message)
    end
    @strict = previousStrict

    return {
        type: Syntax[:FunctionExpression],
        id: id,
        params: params,
        defaults: [],
        body: body,
        rest: nil,
        generator: false,
        expression: false
    }
end
parseFunctionSourceElements() click to toggle source

13 Function Definition

# File lib/ruby_run_js/jsparser.rb, line 2636
def parseFunctionSourceElements() 
    sourceElements = []
    firstRestricted = nil

    expect('{')

    while (@index < @length) 
        token = lookahead()
        if (token[:type] != Token[:StringLiteral]) 
            break
        end

        sourceElement = parseSourceElement()
        sourceElements.push(sourceElement)
        if (sourceElement[:expression][:type] != Syntax[:Literal]) 
            # this is not directive
            break
        end
        directive = sliceSource(token[:range][0] + 1, token[:range][1] - 1)
        if (directive == 'use strict') 
            @strict = true
            if (firstRestricted) 
                throwErrorTolerant(firstRestricted, Messages[:StrictOctalLiteral])
            end
        else
            if (!firstRestricted && token[:octal]) 
                firstRestricted = token
            end
        end
    end

    oldLabelSet = @state[:labelSet]
    oldInIteration = @state[:inIteration]
    oldInSwitch = @state[:inSwitch]
    oldIndefBody = @state[:indefBody]

    @state[:labelSet] = {}
    @state[:inIteration] = false
    @state[:inSwitch] = false
    @state[:indefBody] = true

    while (@index < @length) 
        if (match('}')) 
            break
        end
        sourceElement = parseSourceElement()
        if (sourceElement == nil)
            break
        end
        sourceElements.push(sourceElement)
    end

    expect('}')

    @state[:labelSet] = oldLabelSet
    @state[:inIteration] = oldInIteration
    @state[:inSwitch] = oldInSwitch
    @state[:indefBody] = oldIndefBody

    return {
        type: Syntax[:BlockStatement],
        body: sourceElements
    }
end
parseGroupExpression() click to toggle source

11.1.6 The Grouping Operator

# File lib/ruby_run_js/jsparser.rb, line 1342
def parseGroupExpression() 
    expect('(')

    expr = parseExpression()

    expect(')')

    return expr
end
parseIfStatement() click to toggle source

12.5 If @statement

# File lib/ruby_run_js/jsparser.rb, line 2022
def parseIfStatement()

    expectKeyword('if')

    expect('(')

    test = parseExpression()

    expect(')')

    consequent = parseStatement()

    if (matchKeyword('else')) 
        lex()
        alternate = parseStatement()
    else
        alternate = nil
    end

    return {
        type: Syntax[:IfStatement],
        test: test,
        consequent: consequent,
        alternate: alternate
    }
end
parseLeftHandSideExpression() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1517
def parseLeftHandSideExpression() 

    expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression()

    while (match('.') || match('[')) 
        if (match('[')) 
            expr = {
                type: Syntax[:MemberExpression],
                computed: true,
                object: expr,
                property: parseComputedMember()
            }
        else
            expr = {
                type: Syntax[:MemberExpression],
                computed: false,
                object: expr,
                property: parseNonComputedMember()
            }
        end
    end

    return expr
end
parseLeftHandSideExpressionAllowCall() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1485
def parseLeftHandSideExpressionAllowCall() 

    expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression()

    while (match('.') || match('[') || match('(')) 
        if (match('(')) 
            expr = {
                type: Syntax[:CallExpression],
                callee: expr,
                arguments: parseArguments()
            }
        elsif (match('[')) 
            expr = {
                type: Syntax[:MemberExpression],
                computed: true,
                object: expr,
                property: parseComputedMember()
            }
        else
            expr = {
                type: Syntax[:MemberExpression],
                computed: false,
                object: expr,
                property: parseNonComputedMember()
            }
        end
    end

    return expr
end
parseLogicalANDExpression() click to toggle source

11.11 Binary Logical Operators

# File lib/ruby_run_js/jsparser.rb, line 1768
def parseLogicalANDExpression() 
    expr = parseBitwiseORExpression()

    while (match('&&')) 
        lex()
        expr = {
            type: Syntax[:LogicalExpression],
            operator: '&&',
            left: expr,
            right: parseBitwiseORExpression()
        }
    end

    return expr
end
parseLogicalORExpression() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1784
def parseLogicalORExpression() 
    expr = parseLogicalANDExpression()

    while (match('||')) 
        lex()
        expr = {
            type: Syntax[:LogicalExpression],
            operator: '||',
            left: expr,
            right: parseLogicalANDExpression()
        }
    end

    return expr
end
parseMultiplicativeExpression() click to toggle source

11.5 Multiplicative Operators

# File lib/ruby_run_js/jsparser.rb, line 1630
def parseMultiplicativeExpression() 
    expr = parseUnaryExpression()

    while (match('*') || match('/') || match('%')) 
        expr = {
            type: Syntax[:BinaryExpression],
            operator: lex()[:value],
            left: expr,
            right: parseUnaryExpression()
        }
    end

    return expr
end
parseNewExpression() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1469
def parseNewExpression() 
    expectKeyword('new')

    expr = {
        type: Syntax[:NewExpression],
        callee: parseLeftHandSideExpression(),
        arguments: []
    }

    if (match('(')) 
        expr[:arguments] = parseArguments()
    end

    return expr
end
parseNonComputedMember() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1452
def parseNonComputedMember() 
    expect('.')

    return parseNonComputedProperty()
end
parseNonComputedProperty() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1439
def parseNonComputedProperty()
    token = lex()

    if (!isIdentifierName(token)) 
        throwUnexpected(token)
    end

    return {
        type: Syntax[:Identifier],
        name: token[:value]
    }
end
parseObjectInitialiser() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1291
def parseObjectInitialiser() 
    properties = []
    map = {}

    expect('{')

    while (!match('}')) 
        property = parseObjectProperty()

        if (property[:key][:type] == Syntax[:Identifier]) 
            name = property[:key][:name]
        else
            name = (property[:key][:value]).to_s
        end
        kind = (property[:kind] == 'init') ? PropertyKind[:Data] : (property[:kind] == 'get') ? PropertyKind[:Get] : PropertyKind[:Set]
        if (false)
            if (map[name] == PropertyKind[:Data]) 
                if (@strict && kind == PropertyKind[:Data]) 
                    throwErrorTolerant(nil, Messages[:StrictDuplicateProperty])
                elsif (kind != PropertyKind[:Data]) 
                    throwErrorTolerant(nil, Messages[:AccessorDataProperty])
                end
            else
                if (kind == PropertyKind[:Data]) 
                    throwErrorTolerant(nil, Messages[:AccessorDataProperty])
                elsif (map[name] & kind) 
                    throwErrorTolerant(nil, Messages[:AccessorGetSet])
                end
            end
            map[name] |= kind
        else
            map[name] = kind
        end

        properties.push(property)

        if (!match('}')) 
            expect(',')
        end
    end

    expect('}')

    return {
        type: Syntax[:ObjectExpression],
        properties: properties
    }
end
parseObjectProperty() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1225
def parseObjectProperty()

    token = lookahead()

    if (token[:type] == Token[:Identifier]) 

        id = parseObjectPropertyKey()

        # Property Assignment: Getter and Setter.

        if (token[:value] == 'get' && !match(':')) 
            key = parseObjectPropertyKey()
            expect('(')
            expect(')')
            return {
                type: Syntax[:Property],
                key: key,
                value: parsePropertydef([]),
                kind: 'get'
            }
        elsif (token[:value] == 'set' && !match(':')) 
            key = parseObjectPropertyKey()
            expect('(')
            token = lookahead()
            if (token[:type] != Token[:Identifier]) 
                expect(')')
                throwErrorTolerant(token, Messages[:UnexpectedToken], token[:value])
                return {
                    type: Syntax[:Property],
                    key: key,
                    value: parsePropertydef([]),
                    kind: 'set'
                }
            else
                param = [ parseVariableIdentifier() ]
                expect(')')
                return {
                    type: Syntax[:Property],
                    key: key,
                    value: parsePropertydef(param, token),
                    kind: 'set'
                }
            end
        else
            expect(':')
            return {
                type: Syntax[:Property],
                key: id,
                value: parseAssignmentExpression(),
                kind: 'init'
            }
        end
    elsif (token[:type] == Token[:EOF] || token[:type] == Token[:Punctuator]) 
        throwUnexpected(token)
    else
        key = parseObjectPropertyKey()
        expect(':')
        return {
            type: Syntax[:Property],
            key: key,
            value: parseAssignmentExpression(),
            kind: 'init'
        }
    end
end
parseObjectPropertyKey() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1206
def parseObjectPropertyKey() 
    token = lex()

    # Note: This def is called only from parseObjectProperty(), where
    # EOF and Punctuator tokens are already filtered out.

    if (token[:type] == Token[:StringLiteral] || token[:type] == Token[:NumericLiteral]) 
        if (@strict && token[:octal]) 
            throwErrorTolerant(token, Messages[:StrictOctalLiteral])
        end
        return createLiteral(token)
    end

    return {
        type: Syntax[:Identifier],
        name: token[:value]
    }
end
parsePostfixExpression() click to toggle source

11.3 Postfix Expressions

# File lib/ruby_run_js/jsparser.rb, line 1544
def parsePostfixExpression() 
    expr = parseLeftHandSideExpressionAllowCall()

    token = lookahead()
    if (token[:type] != Token[:Punctuator]) 
        return expr
    end

    if ((match('++') || match('--')) && !peekLineTerminator()) 
        # 11.3.1, 11.3.2
        if (@strict && expr[:type] == Syntax[:Identifier] && isRestrictedWord(expr[:name])) 
            throwErrorTolerant(nil, Messages[:StrictLHSPostfix])
        end
        if (!isLeftHandSide(expr)) 
            throwErrorTolerant(nil, Messages[:InvalidLHSInAssignment])
        end

        expr = {
            type: Syntax[:UpdateExpression],
            operator: lex()[:value],
            argument: expr,
            prefix: false
        }
    end

    return expr
end
parsePrimaryExpression() click to toggle source

11.1 Primary Expressions

# File lib/ruby_run_js/jsparser.rb, line 1355
def parsePrimaryExpression() 
    token = lookahead()
    type = token[:type]

    if (type == Token[:Identifier]) 
        return {
            type: Syntax[:Identifier],
            name: lex()[:value]
        }
    end

    if (type == Token[:StringLiteral] || type == Token[:NumericLiteral]) 
        if (@strict && token[:octal])
            throwErrorTolerant(token, Messages[:StrictOctalLiteral])
        end
        return createLiteral(lex())
    end

    if (type == Token[:Keyword]) 
        if (matchKeyword('this')) 
            lex()
            return {
                type: Syntax[:ThisExpression]
            }
        end

        if (matchKeyword('function')) 
            return parseFunctionExpression()
        end
    end

    if (type == Token[:BooleanLiteral]) 
        lex()
        token[:value] = (token[:value] == 'true')
        return createLiteral(token)
    end

    if (type == Token[:NullLiteral]) 
        lex()
        token[:value] = nil
        return createLiteral(token)
    end

    if (match('[')) 
        return parseArrayInitialiser()
    end

    if (match('{')) 
        return parseObjectInitialiser()
    end

    if (match('(')) 
        return parseGroupExpression()
    end

    if (match('/') || match('/=')) 
        return createLiteral(scanRegExp())
    end

    return throwUnexpected(lex())
end
parseProgram() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 2927
def parseProgram() 
    @strict = false
    program = {
        type: Syntax[:Program],
        body: parseSourceElements()
    }
    return program
end
parsePropertydef(param, first = nil) click to toggle source

11.1.5 Object Initialiser

# File lib/ruby_run_js/jsparser.rb, line 1185
def parsePropertydef(param, first = nil)

    previousStrict = @strict
    body = parseFunctionSourceElements()
    if (first && @strict && isRestrictedWord(param[0][:name])) 
        throwErrorTolerant(first, Messages[:StrictParamName])
    end
    @strict = previousStrict

    return {
        type: Syntax[:FunctionExpression],
        id: nil,
        params: param,
        defaults: [],
        body: body,
        rest: nil,
        generator: false,
        expression: false
    }
end
parseRelationalExpression() click to toggle source

11.8 Relational Operators

# File lib/ruby_run_js/jsparser.rb, line 1680
def parseRelationalExpression()
    previousAllowIn = @state[:allowIn]
    @state[:allowIn] = true

    expr = parseShiftExpression()

    while (match('<') || match('>') || match('<=') || match('>=') || (previousAllowIn && matchKeyword('in')) || matchKeyword('instanceof')) 
        expr = {
            type: Syntax[:BinaryExpression],
            operator: lex()[:value],
            left: expr,
            right: parseShiftExpression()
        }
    end

    @state[:allowIn] = previousAllowIn
    return expr
end
parseReturnStatement() click to toggle source

12.9 The return @statement

# File lib/ruby_run_js/jsparser.rb, line 2311
def parseReturnStatement() 
    token = nil
    argument = nil

    expectKeyword('return')

    if (!@state[:indefBody]) 
        throwErrorTolerant(nil, Messages[:IllegalReturn])
    end

    # 'return' followed by a space and an identifier is very common.
    if (@source[@index] == ' ') 
        if (isIdentifierStart(@source[@index + 1])) 
            argument = parseExpression()
            consumeSemicolon()
            return {
                type: Syntax[:ReturnStatement],
                argument: argument
            }
        end
    end

    if (peekLineTerminator()) 
        return {
            type: Syntax[:ReturnStatement],
            argument: nil
        }
    end

    if (!match(';')) 
        token = lookahead()
        if (!match('}') && token[:type] != Token[:EOF]) 
            argument = parseExpression()
        end
    end

    consumeSemicolon()

    return {
        type: Syntax[:ReturnStatement],
        argument: argument
    }
end
parseShiftExpression() click to toggle source

11.7 Bitwise Shift Operators

# File lib/ruby_run_js/jsparser.rb, line 1664
def parseShiftExpression() 
    expr = parseAdditiveExpression()

    while (match('<<') || match('>>') || match('>>>')) 
        expr = {
            type: Syntax[:BinaryExpression],
            operator: lex()[:value],
            left: expr,
            right: parseAdditiveExpression()
        }
    end

    return expr
end
parseSourceElement() click to toggle source

14 Program

# File lib/ruby_run_js/jsparser.rb, line 2869
def parseSourceElement() 
    token = lookahead()

    if (token[:type] == Token[:Keyword]) 
        case (token[:value])
        when 'const','let'
            return parseConstLetDeclaration(token[:value])
        when 'function'
            return parseFunctionDeclaration()
        else
            return parseStatement()
        end
    end

    if (token[:type] != Token[:EOF]) 
        return parseStatement()
    end
end
parseSourceElements() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 2888
def parseSourceElements() 
    sourceElements = []
    firstRestricted = nil

    while (@index < @length) 
        token = lookahead()
        if (token[:type] != Token[:StringLiteral]) 
            break
        end

        sourceElement = parseSourceElement()
        sourceElements.push(sourceElement)
        if (sourceElement[:expression][:type] != Syntax[:Literal]) 
            # this is not directive
            break
        end
        directive = sliceSource(token[:range][0] + 1, token[:range][1] - 1)
        if (directive == 'use strict') 
            @strict = true
            if (firstRestricted) 
                throwErrorTolerant(firstRestricted, Messages[:StrictOctalLiteral])
            end
        else
            if (!firstRestricted && token[:octal]) 
                firstRestricted = token
            end
        end
    end

    while (@index < @length) 
        sourceElement = parseSourceElement()
        if (sourceElement == nil) 
            break
        end
        sourceElements.push(sourceElement)
    end
    return sourceElements
end
parseStatement() click to toggle source

12 Statements

# File lib/ruby_run_js/jsparser.rb, line 2554
def parseStatement() 
    token = lookahead()

    if (token[:type] == Token[:EOF]) 
        throwUnexpected(token)
    end

    if (token[:type] == Token[:Punctuator]) 
        case token[:value]
        when ';'
            return parseEmptyStatement()
        when '{'
            return parseBlock()
        when '('
            return parseExpressionStatement()
        end
    end

    if (token[:type] == Token[:Keyword]) 
        case token[:value]
        when 'break'
            return parseBreakStatement()
        when 'continue'
            return parseContinueStatement()
        when 'debugger'
            return parseDebuggerStatement()
        when 'do'
            return parseDoWhileStatement()
        when 'for'
            return parseForStatement()
        when 'function'
            return parseFunctionDeclaration()
        when 'if'
            return parseIfStatement()
        when 'return'
            return parseReturnStatement()
        when 'switch'
            return parseSwitchStatement()
        when 'throw'
            return parseThrowStatement()
        when 'try'
            return parseTryStatement()
        when 'var'
            return parseVariableStatement()
        when 'while'
            return parseWhileStatement()
        when 'with'
            return parseWithStatement()
        end
    end

    expr = parseExpression()

    # 12.12 Labelled Statements
    if ((expr[:type] == Syntax[:Identifier]) && match(':')) 
        lex()

        if (false) 
            throwError(nil, Messages[:Redeclaration], 'Label', expr[:name])
        end

        @state[:labelSet][expr[:name]] = true
        labeledBody = parseStatement()
        @state[:labelSet].delete(expr[:name])

        return {
            type: Syntax[:LabeledStatement],
            label: expr,
            body: labeledBody
        }
    end

    consumeSemicolon()

    return {
        type: Syntax[:ExpressionStatement],
        expression: expr
    }
end
parseStatementList() click to toggle source

12.1 Block

# File lib/ruby_run_js/jsparser.rb, line 1879
def parseStatementList()
    list = []
    statement = nil

    while (@index < @length)
        if (match('}'))
            break
        end
        statement = parseSourceElement()
        unless (statement)
            break
        end
        list.push(statement)
    end

    return list
end
parseSwitchCase() click to toggle source

12.10 The swith @statement

# File lib/ruby_run_js/jsparser.rb, line 2381
def parseSwitchCase() 
    consequent = []
    statement = nil

    if (matchKeyword('default')) 
        lex()
        test = nil
    else
        expectKeyword('case')
        test = parseExpression()
    end
    expect(':')

    while (@index < @length) 
        if (match('}') || matchKeyword('default') || matchKeyword('case')) 
            break
        end
        statement = parseStatement()
        if (statement == nil) 
            break
        end
        consequent.push(statement)
    end

    return {
        type: Syntax[:SwitchCase],
        test: test,
        consequent: consequent
    }
end
parseSwitchStatement() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 2412
def parseSwitchStatement()

    expectKeyword('switch')

    expect('(')

    discriminant = parseExpression()

    expect(')')

    expect('{')

    cases = []

    if (match('}')) 
        lex()
        return {
            type: Syntax[:SwitchStatement],
            discriminant: discriminant,
            cases: cases
        }
    end

    oldInSwitch = @state[:inSwitch]
    @state[:inSwitch] = true
    defaultFound = false

    while (@index < @length) 
        if (match('}')) 
            break
        end
        clause = parseSwitchCase()
        if (clause[:test] == nil) 
            if (defaultFound) 
                throwError(nil, Messages[:MultipleDefaultsInSwitch])
            end
            defaultFound = true
        end
        cases.push(clause)
    end

    @state[:inSwitch] = oldInSwitch

    expect('}')

    return {
        type: Syntax[:SwitchStatement],
        discriminant: discriminant,
        cases: cases
    }
end
parseThrowStatement() click to toggle source

12.13 The throw @statement

# File lib/ruby_run_js/jsparser.rb, line 2466
def parseThrowStatement()

    expectKeyword('throw')

    if (peekLineTerminator()) 
        throwError(nil, Messages[:NewlineAfterThrow])
    end

    argument = parseExpression()

    consumeSemicolon()

    return {
        type: Syntax[:ThrowStatement],
        argument: argument
    }
end
parseTryStatement() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 2510
def parseTryStatement() 
    handlers = []
    finalizer = nil

    expectKeyword('try')

    block = parseBlock()

    if (matchKeyword('catch')) 
        handlers.push(parseCatchClause())
    end

    if (matchKeyword('finally')) 
        lex()
        finalizer = parseBlock()
    end

    if (handlers.length == 0 && !finalizer) 
        throwError(nil, Messages[:NoCatchOrFinally])
    end

    return {
        type: Syntax[:TryStatement],
        block: block,
        guardedHandlers: [],
        handlers: handlers,
        finalizer: finalizer
    }
end
parseUnaryExpression() click to toggle source

11.4 Unary Operators

# File lib/ruby_run_js/jsparser.rb, line 1574
def parseUnaryExpression()

    token = lookahead()
    if (token[:type] != Token[:Punctuator] && token[:type] != Token[:Keyword]) 
        return parsePostfixExpression()
    end

    if (match('++') || match('--')) 
        token = lex()
        expr = parseUnaryExpression()
        # 11.4.4, 11.4.5
        if (@strict && expr[:type] == Syntax[:Identifier] && isRestrictedWord(expr[:name])) 
            throwErrorTolerant(nil, Messages[:StrictLHSPrefix])
        end

        if (!isLeftHandSide(expr))
            throwErrorTolerant(nil, Messages[:InvalidLHSInAssignment])
        end

        expr = {
            type: Syntax[:UpdateExpression],
            operator: token[:value],
            argument: expr,
            prefix: true
        }
        return expr
    end

    if (match('+') || match('-') || match('~') || match('!')) 
        expr = {
            type: Syntax[:UnaryExpression],
            operator: lex()[:value],
            argument: parseUnaryExpression(),
            prefix: true
        }
        return expr
    end

    if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) 
        expr = {
            type: Syntax[:UnaryExpression],
            operator: lex()[:value],
            argument: parseUnaryExpression(),
            prefix: true
        }
        if (@strict && expr[:operator] == 'delete' && expr[:argument][:type] == Syntax[:Identifier]) 
            throwErrorTolerant(nil, Messages[:StrictDelete])
        end
        return expr
    end

    return parsePostfixExpression()
end
parseVariableDeclaration(kind=nil) click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1926
def parseVariableDeclaration(kind=nil) 
    id = parseVariableIdentifier()
    init = nil

    # 12.2.1
    if (@strict && isRestrictedWord(id[:name])) 
        throwErrorTolerant(nil, Messages[:StrictVarName])
    end

    if (kind == 'const') 
        expect('=')
        init = parseAssignmentExpression()
    elsif (match('=')) 
        lex()
        init = parseAssignmentExpression()
    end

    return {
        type: Syntax[:VariableDeclarator],
        id: id,
        init: init
    }
end
parseVariableDeclarationList(kind = nil) click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1950
def parseVariableDeclarationList(kind = nil) 
    list = []

    begin
        list.push(parseVariableDeclaration(kind))
        if (!match(',')) 
            break
        end
        lex()
    end while (@index < @length)

    return list
end
parseVariableIdentifier() click to toggle source

12.2 Variable Statement

# File lib/ruby_run_js/jsparser.rb, line 1913
def parseVariableIdentifier() 
    token = lex()

    if (token[:type] != Token[:Identifier])
        throwUnexpected(token)
    end

    return {
        type: Syntax[:Identifier],
        name: token[:value]
    }
end
parseVariableStatement() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1964
def parseVariableStatement()
    expectKeyword('var')

    declarations = parseVariableDeclarationList()

    consumeSemicolon()

    return {
        type: Syntax[:VariableDeclaration],
        declarations: declarations,
        kind: 'var'
    }
end
parseWhileStatement() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 2080
def parseWhileStatement()

    expectKeyword('while')

    expect('(')

    test = parseExpression()

    expect(')')

    oldInIteration = @state[:inIteration]
    @state[:inIteration] = true

    body = parseStatement()

    @state[:inIteration] = oldInIteration

    return {
        type: Syntax[:WhileStatement],
        test: test,
        body: body
    }
end
parseWithStatement() click to toggle source

12.10 The with @statement

# File lib/ruby_run_js/jsparser.rb, line 2357
def parseWithStatement() 
    if (@strict) 
        throwErrorTolerant(nil, Messages[:StrictModeWith])
    end

    expectKeyword('with')

    expect('(')

    object = parseExpression()

    expect(')')

    body = parseStatement()

    return {
        type: Syntax[:WithStatement],
        object: object,
        body: body
    }
end
peekLineTerminator() click to toggle source

Return true if there is a line terminator before the next token.

# File lib/ruby_run_js/jsparser.rb, line 1003
def peekLineTerminator() 
    pos = @index
    line = @lineNumber
    start = @lineStart
    skipComment()
    found = @lineNumber != line
    @index = pos
    @lineNumber = line
    @lineStart = start
    return found
end
scanComment() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 2960
def scanComment() 
    comment = ''
    blockComment = false
    lineComment = false

    while (@index < @length) 
        ch = @source[@index]

        if (lineComment) 
            ch = curCharAndMoveNext
            if (isLineTerminator(ch)) 
                loc[:end] = {
                    line: @lineNumber,
                    column: @index - @lineStart - 1
                }
                lineComment = false
                addComment('Line', comment, start, @index - 1, loc)
                if (ch == "\r" && @source[@index] == "\n") 
                    @index += 1
                end
                @lineNumber += 1
                @lineStart = @index
                comment = ''
            elsif (@index >= @length) 
                lineComment = false
                comment += ch
                loc[:end] = {
                    line: @lineNumber,
                    column: @length - @lineStart
                }
                addComment('Line', comment, start, @length, loc)
            else
                comment += ch
            end
        elsif (blockComment) 
            if (isLineTerminator(ch)) 
                if (ch == "\r" && @source[@index + 1] == "\n") 
                    @index += 1
                    comment += "\r\n"
                else
                    comment += ch
                end
                @lineNumber += 1
                @index += 1
                @lineStart = @index
                if (@index >= @length)
                    throwError(nil, Messages[:UnexpectedToken], 'ILLEGAL')
                end
            else
                ch = curCharAndMoveNext
                if (@index >= @length) 
                    throwError(nil, Messages[:UnexpectedToken], 'ILLEGAL')
                end
                comment += ch
                if (ch == '*') 
                    ch = @source[@index]
                    if (ch == '/') 
                        comment = comment.substr(0, comment.length - 1)
                        blockComment = false
                        @index += 1
                        loc[:end] = {
                            line: @lineNumber,
                            column: @index - @lineStart
                        }
                        addComment('Block', comment, start, @index, loc)
                        comment = ''
                    end
                end
            end
        elsif (ch == '/') 
            ch = @source[@index + 1]
            if (ch == '/') 
                loc = {
                    start: {
                        line: @lineNumber,
                        column: @index - @lineStart
                    }
                }
                start = @index
                @index += 2
                lineComment = true
                if (@index >= @length) 
                    loc[:end] = {
                        line: @lineNumber,
                        column: @index - @lineStart
                    }
                    lineComment = false
                    addComment('Line', comment, start, @index, loc)
                end
            elsif (ch == '*') 
                start = @index
                @index += 2
                blockComment = true
                loc = {
                    start: {
                        line: @lineNumber,
                        column: @index - @lineStart - 2
                    }
                }
                if (@index >= @length) 
                    throwError(nil, Messages[:UnexpectedToken], 'ILLEGAL')
                end
            else
                break
            end
        elsif (isWhiteSpace(ch)) 
            @index += 1
        elsif (isLineTerminator(ch)) 
            @index += 1
            if (ch ==  "\r" && @source[@index] == "\n") 
                @index += 1
            end
            @lineNumber += 1
            @lineStart = @index
        else
            break
        end
    end
end
scanHexEscape(prefix) click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 313
def scanHexEscape(prefix) 
    code = 0

    len = (prefix == 'u') ? 4 : 2
    len.times do |i|
        if (@index < @length && isHexDigit(@source[@index])) 
            ch = curCharAndMoveNext
            code = code * 16 + '0123456789abcdef'.index(ch.downcase())
        else
            return nil
        end
    end
    return [code].pack('U*')
end
scanIdentifier() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 328
def scanIdentifier()

    ch = @source[@index]
    if (!isIdentifierStart(ch)) 
        return
    end

    start = @index
    if (ch == "\\") 
        @index += 1
        if (@source[@index] != 'u') 
            return
        end
        @index += 1
        restore = @index
        ch = scanHexEscape('u')
        if (ch) 
            if (ch == "\\" || !isIdentifierStart(ch)) 
                return
            end
            id = ch
        else
            @index = restore
            id = 'u'
        end
    else
        id = curCharAndMoveNext
    end

    while (@index < @length) do
        ch = @source[@index]
        if (!isIdentifierPart(ch)) 
            break
        end
        if (ch == "\\") 
            @index += 1
            if (@source[@index] != 'u') 
                return
            end
            @index += 1
            restore = @index
            ch = scanHexEscape('u')
            if (ch) 
                if (ch == "\\" || !isIdentifierPart(ch)) 
                    return
                end
                id += ch
            else
                @index = restore
                id += 'u'
            end
        else
            id += curCharAndMoveNext
        end
    end

    # There is no keyword or literal with only one character.
    # Thus, it must be an identifier.
    if (id.length == 1) 
        return {
            type: Token[:Identifier],
            value: id,
            lineNumber: @lineNumber,
            lineStart: @lineStart,
            range: [start, @index]
        }
    end

    if (isKeyword(id)) 
        return {
            type: Token[:Keyword],
            value: id,
            lineNumber: @lineNumber,
            lineStart: @lineStart,
            range: [start, @index]
        }
    end


    # 7.8.1 Null Literals

    if (id == 'null') 
        return {
            type: Token[:NullLiteral],
            value: id,
            lineNumber: @lineNumber,
            lineStart: @lineStart,
            range: [start, @index]
        }
    end

    # 7.8.2 Boolean Literals

    if (id == 'true' || id == 'false') 
        return {
            type: Token[:BooleanLiteral],
            value: id,
            lineNumber: @lineNumber,
            lineStart: @lineStart,
            range: [start, @index]
        }
    end

    return {
        type: Token[:Identifier],
        value: id,
        lineNumber: @lineNumber,
        lineStart: @lineStart,
        range: [start, @index]
    }
end
scanNumericLiteral() click to toggle source

7.8.3 Numeric Literals

# File lib/ruby_run_js/jsparser.rb, line 605
def scanNumericLiteral()

    ch = @source[@index]
    assert(isDecimalDigit(ch) || (ch == '.'),
        'Numeric literal must start with a decimal digit or a decimal point')

    start = @index
    number = ''
    if (ch != '.') 
        number = curCharAndMoveNext
        ch = @source[@index]

        # Hex number starts with '0x'.
        # Octal number starts with '0'.
        if (number == '0') 
            if (ch == 'x' || ch == 'X') 
                number += curCharAndMoveNext
                while (@index < @length) 
                    ch = @source[@index]
                    if (!isHexDigit(ch)) 
                        break
                    end
                    number += curCharAndMoveNext
                end

                if (number.length <= 2) 
                    # only 0x
                    throwError(nil, Messages[:UnexpectedToken], 'ILLEGAL')
                end

                if (@index < @length) 
                    ch = @source[@index]
                    if (isIdentifierStart(ch)) 
                        throwError(nil, Messages[:UnexpectedToken], 'ILLEGAL')
                    end
                end
                return {
                    type: Token[:NumericLiteral],
                    value: number.to_i(16),
                    lineNumber: @lineNumber,
                    lineStart: @lineStart,
                    range: [start, @index]
                }
            elsif (isOctalDigit(ch)) 
                number += curCharAndMoveNext
                while (@index < @length) 
                    ch = @source[@index]
                    if (!isOctalDigit(ch)) 
                        break
                    end
                    number += curCharAndMoveNext
                end

                if (@index < @length) 
                    ch = @source[@index]
                    if (isIdentifierStart(ch) || isDecimalDigit(ch)) 
                        throwError(nil, Messages[:UnexpectedToken], 'ILLEGAL')
                    end
                end
                return {
                    type: Token[:NumericLiteral],
                    value: number.to_i(8),
                    octal: true,
                    lineNumber: @lineNumber,
                    lineStart: @lineStart,
                    range: [start, @index]
                }
            end

            # decimal number starts with '0' such as '09' is illegal.
            if (isDecimalDigit(ch)) 
                throwError(nil, Messages[:UnexpectedToken], 'ILLEGAL')
            end
        end

        while (@index < @length) 
            ch = @source[@index]
            if (!isDecimalDigit(ch)) 
                break
            end
            number += curCharAndMoveNext
        end
    end

    if (ch == '.') 
        number += curCharAndMoveNext
        while (@index < @length) 
            ch = @source[@index]
            if (!isDecimalDigit(ch)) 
                break
            end
            number += curCharAndMoveNext
        end
    end

    if (ch == 'e' || ch == 'E') 
        number += curCharAndMoveNext

        ch = @source[@index]
        if (ch == '+' || ch == '-') 
            number += curCharAndMoveNext
        end

        ch = @source[@index]
        if (isDecimalDigit(ch)) 
            number += curCharAndMoveNext
            while (@index < @length) 
                ch = @source[@index]
                if (!isDecimalDigit(ch)) 
                    break
                end
                number += curCharAndMoveNext
            end
        else
            throwError(nil, Messages[:UnexpectedToken], 'ILLEGAL')
        end
    end

    if (@index < @length) 
        ch = @source[@index]
        if (isIdentifierStart(ch)) 
            throwError(nil, Messages[:UnexpectedToken], 'ILLEGAL')
        end
    end

    return {
        type: Token[:NumericLiteral],
        value: number.to_f,
        lineNumber: @lineNumber,
        lineStart: @lineStart,
        range: [start, @index]
    }
end
scanPunctuator() click to toggle source

7.7 Punctuators

# File lib/ruby_run_js/jsparser.rb, line 442
def scanPunctuator() 
    start = @index
    ch1 = @source[@index]

    # Check for most common single-character punctuators.

    if (ch1 == ';' || ch1 == '{' || ch1 == '}') 
        @index += 1
        return {
            type: Token[:Punctuator],
            value: ch1,
            lineNumber: @lineNumber,
            lineStart: @lineStart,
            range: [start, @index]
        }
    end

    if (ch1 == ',' || ch1 == '(' || ch1 == ')') 
        @index += 1
        return {
            type: Token[:Punctuator],
            value: ch1,
            lineNumber: @lineNumber,
            lineStart: @lineStart,
            range: [start, @index]
        }
    end

    # Dot (.) can also start a floating-point number, hence the need
    # to check the next character.

    ch2 = @source[@index + 1]
    if (ch1 == '.' && !isDecimalDigit(ch2)) 
        return {
            type: Token[:Punctuator],
            value: curCharAndMoveNext,
            lineNumber: @lineNumber,
            lineStart: @lineStart,
            range: [start, @index]
        }
    end

    # Peek more characters.

    ch3 = @source[@index + 2]
    ch4 = @source[@index + 3]

    # 4-character punctuator: >>>=

    if (ch1 == '>' && ch2 == '>' && ch3 == '>') 
        if (ch4 == '=') 
            @index += 4
            return {
                type: Token[:Punctuator],
                value: '>>>=',
                lineNumber: @lineNumber,
                lineStart: @lineStart,
                range: [start, @index]
            }
        end
    end

    # 3-character punctuators: == != >>> <<= >>=

    if (ch1 == '=' && ch2 == '=' && ch3 == '=') 
        @index += 3
        return {
            type: Token[:Punctuator],
            value: '===',
            lineNumber: @lineNumber,
            lineStart: @lineStart,
            range: [start, @index]
        }
    end

    if (ch1 == '!' && ch2 == '=' && ch3 == '=') 
        @index += 3
        return {
            type: Token[:Punctuator],
            value: '!==',
            lineNumber: @lineNumber,
            lineStart: @lineStart,
            range: [start, @index]
        }
    end

    if (ch1 == '>' && ch2 == '>' && ch3 == '>') 
        @index += 3
        return {
            type: Token[:Punctuator],
            value: '>>>',
            lineNumber: @lineNumber,
            lineStart: @lineStart,
            range: [start, @index]
        }
    end

    if (ch1 == '<' && ch2 == '<' && ch3 == '=') 
        @index += 3
        return {
            type: Token[:Punctuator],
            value: '<<=',
            lineNumber: @lineNumber,
            lineStart: @lineStart,
            range: [start, @index]
        }
    end

    if (ch1 == '>' && ch2 == '>' && ch3 == '=') 
        @index += 3
        return {
            type: Token[:Punctuator],
            value: '>>=',
            lineNumber: @lineNumber,
            lineStart: @lineStart,
            range: [start, @index]
        }
    end

    # 2-character punctuators: <= >= == != ++ -- << >> && ||
    # += -= *= %= &= |= ^= /=

    if (ch2 == '=') 
        if ('<>=!+-*%&|^/'.include?(ch1)) 
            @index += 2
            return {
                type: Token[:Punctuator],
                value: ch1 + ch2,
                lineNumber: @lineNumber,
                lineStart: @lineStart,
                range: [start, @index]
            }
        end
    end

    if (ch1 == ch2 && ('+-<>&|'.include?(ch1))) 
        if ('+-<>&|'.include?(ch2)) 
            @index += 2
            return {
                type: Token[:Punctuator],
                value: ch1 + ch2,
                lineNumber: @lineNumber,
                lineStart: @lineStart,
                range: [start, @index]
            }
        end
    end

    # The remaining 1-character punctuators.

    if ('[]<>+-*%&|^!~?:=/'.include?(ch1)) 
        return {
            type: Token[:Punctuator],
            value: curCharAndMoveNext,
            lineNumber: @lineNumber,
            lineStart: @lineStart,
            range: [start, @index]
        }
    end
end
scanRegExp() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 836
def scanRegExp() 
    classMarker = false
    terminated = false

    @buffer = nil
    skipComment()

    start = @index
    ch = @source[@index]
    assert(ch == '/', 'Regular expression literal must start with a slash')
    str = curCharAndMoveNext

    while (@index < @length) 
        ch = curCharAndMoveNext
        str += ch
        if (ch == "\\") 
            ch = curCharAndMoveNext
            # ECMA-262 7.8.5
            if (isLineTerminator(ch)) 
                throwError(nil, Messages[:UnterminatedRegExp])
            end
            str += ch
        elsif (classMarker) 
            if (ch == ']') 
                classMarker = false
            end
        else
            if (ch == '/') 
                terminated = true
                break
            elsif (ch == '[') 
                classMarker = true
            elsif (isLineTerminator(ch)) 
                throwError(nil, Messages[:UnterminatedRegExp])
            end
        end
    end

    if (!terminated) 
        throwError(nil, Messages[:UnterminatedRegExp])
    end

    # Exclude leading and trailing slash.
    pattern = str[1, str.length - 2]

    flags = ''
    while (@index < @length) 
        ch = @source[@index]
        if (!isIdentifierPart(ch)) 
            break
        end

        @index += 1
        if (ch == "\\" && @index < @length) 
            ch = @source[@index]
            if (ch == 'u') 
                @index += 1
                restore = @index
                ch = scanHexEscape('u')
                if (ch)
                    flags += ch
                    str += "\\u"
                    while (restore < @index)
                        str += @source[restore]
                        restore += 1
                    end
                else
                    @index = restore
                    flags += 'u'
                    str += "\\u"
                end
            else
                str += "\\"
            end
        else
            flags += ch
            str += ch
        end
    end

    return {
        literal: str,
        value: sliceSource(start,@index),
        regexp: {
            pattern: str,
            flags: flags
        },
        range: [start, @index]
    }
end
scanStringLiteral() click to toggle source

7.8.4 String Literals

# File lib/ruby_run_js/jsparser.rb, line 741
def scanStringLiteral() 
    str = ''
    octal = false

    quote = @source[@index]
    assert((quote == "'" || quote == '"'),
        'String literal must starts with a quote')

    start = @index
    @index += 1

    while (@index < @length) 
        ch = curCharAndMoveNext

        if (ch == quote) 
            quote = ''
            break
        elsif (ch == "\\") 
            ch = curCharAndMoveNext
            if (!isLineTerminator(ch)) 
                case ch
                when 'n'
                    str += "\n"
                when 'r'
                    str += "\r"
                when 't'
                    str += "\t"
                when 'u','x'
                    restore = @index
                    unescaped = scanHexEscape(ch)
                    if (unescaped) 
                        str += unescaped
                    else
                        @index = restore
                        str += ch
                    end
                when 'b'
                    str += "\b"
                when 'f'
                    str += "\f"
                when 'v'
                    str += "\x0B"
                else
                    if (isOctalDigit(ch)) 
                        code = '01234567'.index(ch)

                        # \0 is not octal escape sequence
                        if (code != 0) 
                            octal = true
                        end

                        if (@index < @length && isOctalDigit(@source[@index])) 
                            octal = true
                            code = code * 8 + '01234567'.index(curCharAndMoveNext)

                            # 3 digits are only allowed when string starts
                            # with 0, 1, 2, 3
                            if ('0123'.include?(ch) &&
                                    @index < @length &&
                                    isOctalDigit(@source[@index])) then
                                code = code * 8 + '01234567'.index(curCharAndMoveNext)
                            end
                        end
                        str += [code].pack('U*')
                    else
                        str += ch || ''
                    end
                end
            else
                @lineNumber += 1
                if (ch ==  "\r" && @source[@index] == "\n") 
                    @index += 1
                end
            end
        elsif (isLineTerminator(ch)) 
            break
        else
            str += ch
        end
    end

    if (quote != '') 
        throwError(nil, Messages[:UnexpectedToken], 'ILLEGAL')
    end

    return {
        type: Token[:StringLiteral],
        value: str,
        octal: octal,
        lineNumber: @lineNumber,
        lineStart: @lineStart,
        range: [start, @index]
    }
end
skipComment() click to toggle source

7.4 Comments

# File lib/ruby_run_js/jsparser.rb, line 242
def skipComment()

    blockComment = false
    lineComment = false

    while (@index < @length) do
        ch = @source[@index]

        if (lineComment) 
            ch = curCharAndMoveNext
            if (isLineTerminator(ch)) 
                lineComment = false
                if (ch == "\r" && @source[@index] == "\n")
                    @index += 1
                end
                @lineNumber += 1
                @lineStart = @index
            end
        elsif (blockComment)
            if (isLineTerminator(ch))
                if (ch == "\r" && @source[@index + 1] == "\n") 
                    @index += 1
                end
                @lineNumber += 1
                @index += 1
                @lineStart = @index
                if (@index >= @length)
                    throwError(nil, Messages[:UnexpectedToken], 'ILLEGAL')
                end
            else
                ch = curCharAndMoveNext
                if (@index >= @length) 
                    throwError(nil, Messages[:UnexpectedToken], 'ILLEGAL')
                end
                if (ch == '*') 
                    ch = @source[@index]
                    if (ch == '/')
                        @index += 1
                        blockComment = false
                    end
                end
            end
        elsif (ch == '/') 
            ch = @source[@index + 1]
            if (ch == '/') 
                @index += 2
                lineComment = true
            elsif (ch == '*') 
                @index += 2
                blockComment = true
                if (@index >= @length) 
                    throwError(nil, Messages[:UnexpectedToken], 'ILLEGAL')
                end
            else
                break
            end
        elsif (isWhiteSpace(ch)) 
            @index += 1
        elsif (isLineTerminator(ch)) 
            @index += 1
            if (ch == "\r" && @source[@index] == "\n") 
                @index += 1
            end
            @lineNumber += 1
            @lineStart = @index
        else
            break
        end
    end
end
sliceSource(from, to) click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 130
def sliceSource(from, to) 
    return @source[from...to]
end
throwError(token, messageFormat,*args) click to toggle source

Throw an exception

# File lib/ruby_run_js/jsparser.rb, line 1017
def throwError(token, messageFormat,*args)
    msg = messageFormat.gsub(/%(\d)/) do |i|
        args[i.to_i] || ''
    end

    if (token != nil) 
       # raise "Line #{token[:lineNumber]} at #{(token[:range][0] - token[:lineNumber] + 1)} : #{msg}"
        raise SyntaxError.new "Error: Line #{token[:lineNumber]}: #{msg}"
    else
      #  raise "Line #{@lineNumber} at #{@index - @lineStart + 1} : #{msg}"
        raise SyntaxError.new "Error: Line #{@lineNumber}: #{msg}"
    end
end
throwErrorTolerant(token, messageFormat,*args) click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 1031
def throwErrorTolerant(token, messageFormat,*args)
    throwError(token,messageFormat,*args)
end
throwUnexpected(token) click to toggle source

Throw an exception because of the token.

# File lib/ruby_run_js/jsparser.rb, line 1037
def throwUnexpected(token) 
    if (token[:type] == Token[:EOF]) 
        throwError(token, Messages[:UnexpectedEOS])
    end

    if (token[:type] == Token[:NumericLiteral]) 
        throwError(token, Messages[:UnexpectedNumber])
    end

    if (token[:type] == Token[:StringLiteral]) 
        throwError(token, Messages[:UnexpectedString])
    end

    if (token[:type] == Token[:Identifier]) 
        throwError(token, Messages[:UnexpectedIdentifier])
    end

    if (token[:type] == Token[:Keyword]) 
        if (isFutureReservedWord(token[:value])) 
            throwError(token, Messages[:UnexpectedReserved])
        elsif (@strict && isStrictModeReservedWord(token[:value])) 
            throwErrorTolerant(token, Messages[:StrictReservedWord])
            return
        end
        throwError(token, Messages[:UnexpectedToken], token[:value])
    end

    # BooleanLiteral, NullLiteral, or Punctuator.
    throwError(token, Messages[:UnexpectedToken], token[:value])
end
trackGroupExpression() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 3264
def trackGroupExpression()

    skipComment()
    marker = createLocationMarker()
    expect('(')

    expr = parseExpression()

    expect(')')

    marker[:end].call()
    marker[:applyGroup].call(expr)

    return expr
end
trackLeftHandSideExpression() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 3280
def trackLeftHandSideExpression() 

    skipComment()
    marker = createLocationMarker()

    expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression()

    while (match('.') || match('[')) 
        if (match('[')) 
            expr = {
                type: Syntax[:MemberExpression],
                computed: true,
                object: expr,
                property: parseComputedMember()
            }
            marker[:end].call()
            marker[:apply].call(expr)
        else
            expr = {
                type: Syntax[:MemberExpression],
                computed: false,
                object: expr,
                property: parseNonComputedMember()
            }
            marker[:end].call()
            marker[:apply].call(expr)
        end
    end

    return expr
end
trackLeftHandSideExpressionAllowCall() click to toggle source
# File lib/ruby_run_js/jsparser.rb, line 3312
def trackLeftHandSideExpressionAllowCall()

    skipComment()
    marker = createLocationMarker()

    expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression()

    while (match('.') || match('[') || match('(')) 
        if (match('(')) 
            expr = {
                type: Syntax[:CallExpression],
                callee: expr,
                arguments: parseArguments()
            }
            marker[:end].call()
            marker[:apply].call(expr)
        elsif (match('[')) 
            expr = {
                type: Syntax[:MemberExpression],
                computed: true,
                object: expr,
                property: parseComputedMember()
            }
            marker[:end].call()
            marker[:apply].call(expr)
        else
            expr = {
                type: Syntax[:MemberExpression],
                computed: false,
                object: expr,
                property: parseNonComputedMember()
            }
            marker[:end].call()
            marker[:apply].call(expr)
        end
    end

    return expr
end