func (self *_parser) scan() (tkn token.Token, literal string, idx file.Idx) { self.implicitSemicolon = false for { self.skipWhiteSpace() idx = self.idxOf(self.chrOffset) insertSemicolon := false switch chr := self.chr; { case isIdentifierStart(chr): var err error literal, err = self.scanIdentifier() if err != nil { tkn = token.ILLEGAL break } if len(literal) > 1 { // Keywords are longer than 1 character, avoid lookup otherwise var strict bool tkn, strict = token.IsKeyword(literal) switch tkn { case 0: // Not a keyword if literal == "true" || literal == "false" { self.insertSemicolon = true tkn = token.BOOLEAN return } else if literal == "null" { self.insertSemicolon = true tkn = token.NULL return } case token.KEYWORD: tkn = token.KEYWORD if strict { // TODO If strict and in strict mode, then this is not a break break } return case token.THIS, token.BREAK, token.THROW, // A newline after a throw is not allowed, but we need to detect it token.RETURN, token.CONTINUE, token.DEBUGGER: self.insertSemicolon = true return default: return } } self.insertSemicolon = true tkn = token.IDENTIFIER return case '0' <= chr && chr <= '9': self.insertSemicolon = true tkn, literal = self.scanNumericLiteral(false) return default: self.read() switch chr { case -1: if self.insertSemicolon { self.insertSemicolon = false self.implicitSemicolon = true } tkn = token.EOF case '\r', '\n', '\u2028', '\u2029': self.insertSemicolon = false self.implicitSemicolon = true continue case ':': tkn = token.COLON case '.': if digitValue(self.chr) < 10 { insertSemicolon = true tkn, literal = self.scanNumericLiteral(true) } else { tkn = token.PERIOD } case ',': tkn = token.COMMA case ';': tkn = token.SEMICOLON case '(': tkn = token.LEFT_PARENTHESIS case ')': tkn = token.RIGHT_PARENTHESIS insertSemicolon = true case '[': tkn = token.LEFT_BRACKET case ']': tkn = token.RIGHT_BRACKET insertSemicolon = true case '{': tkn = token.LEFT_BRACE case '}': tkn = token.RIGHT_BRACE insertSemicolon = true case '+': tkn = self.switch3(token.PLUS, token.ADD_ASSIGN, '+', token.INCREMENT) if tkn == token.INCREMENT { insertSemicolon = true } case '-': tkn = self.switch3(token.MINUS, token.SUBTRACT_ASSIGN, '-', token.DECREMENT) if tkn == token.DECREMENT { insertSemicolon = true } case '*': tkn = self.switch2(token.MULTIPLY, token.MULTIPLY_ASSIGN) case '/': if self.chr == '/' { self.skipSingleLineComment() continue } else if self.chr == '*' { self.skipMultiLineComment() continue } else { // Could be division, could be RegExp literal tkn = self.switch2(token.SLASH, token.QUOTIENT_ASSIGN) insertSemicolon = true } case '%': tkn = self.switch2(token.REMAINDER, token.REMAINDER_ASSIGN) case '^': tkn = self.switch2(token.EXCLUSIVE_OR, token.EXCLUSIVE_OR_ASSIGN) case '<': tkn = self.switch4(token.LESS, token.LESS_OR_EQUAL, '<', token.SHIFT_LEFT, token.SHIFT_LEFT_ASSIGN) case '>': tkn = self.switch6(token.GREATER, token.GREATER_OR_EQUAL, '>', token.SHIFT_RIGHT, token.SHIFT_RIGHT_ASSIGN, '>', token.UNSIGNED_SHIFT_RIGHT, token.UNSIGNED_SHIFT_RIGHT_ASSIGN) case '=': tkn = self.switch2(token.ASSIGN, token.EQUAL) if tkn == token.EQUAL && self.chr == '=' { self.read() tkn = token.STRICT_EQUAL } case '!': tkn = self.switch2(token.NOT, token.NOT_EQUAL) if tkn == token.NOT_EQUAL && self.chr == '=' { self.read() tkn = token.STRICT_NOT_EQUAL } case '&': if self.chr == '^' { self.read() tkn = self.switch2(token.AND_NOT, token.AND_NOT_ASSIGN) } else { tkn = self.switch3(token.AND, token.AND_ASSIGN, '&', token.LOGICAL_AND) } case '|': tkn = self.switch3(token.OR, token.OR_ASSIGN, '|', token.LOGICAL_OR) case '~': tkn = token.BITWISE_NOT case '?': tkn = token.QUESTION_MARK case '"', '\'': insertSemicolon = true tkn = token.STRING var err error literal, err = self.scanString(self.chrOffset - 1) if err != nil { tkn = token.ILLEGAL } case '`': insertSemicolon = true tkn = token.STRING var err error literal, err = self.scanMultiString(self.chrOffset - 1) if err != nil { tkn = token.ILLEGAL } default: self.errorUnexpected(idx, chr) tkn = token.ILLEGAL } } self.insertSemicolon = insertSemicolon return } }
func (self *_parser) parsePrimaryExpression() ast.Expression { literal := self.literal idx := self.idx switch self.token { case token.IDENTIFIER: self.next() if len(literal) > 1 { tkn, strict := token.IsKeyword(literal) if tkn == token.KEYWORD { if !strict { self.error(idx, "Unexpected reserved word") } } } return &ast.Identifier{ Name: literal, Idx: idx, } case token.NULL: self.next() return &ast.NullLiteral{ Idx: idx, Literal: literal, } case token.BOOLEAN: self.next() value := false switch literal { case "true": value = true case "false": value = false default: self.error(idx, "Illegal boolean literal") } return &ast.BooleanLiteral{ Idx: idx, Literal: literal, Value: value, } case token.STRING: self.next() value, err := parseStringLiteral(literal[1 : len(literal)-1]) if err != nil { self.error(idx, err.Error()) } return &ast.StringLiteral{ Idx: idx, Literal: literal, Value: value, } case token.NUMBER: self.next() value, err := parseNumberLiteral(literal) if err != nil { self.error(idx, err.Error()) value = 0 } return &ast.NumberLiteral{ Idx: idx, Literal: literal, Value: value, } case token.SLASH, token.QUOTIENT_ASSIGN: return self.parseRegExpLiteral() case token.LEFT_BRACE: return self.parseObjectLiteral() case token.LEFT_BRACKET: return self.parseArrayLiteral() case token.LEFT_PARENTHESIS: self.expect(token.LEFT_PARENTHESIS) expression := self.parseExpression() self.expect(token.RIGHT_PARENTHESIS) return expression case token.THIS: self.next() return &ast.ThisExpression{ Idx: idx, } case token.FUNCTION: return self.parseFunction(false) } self.errorUnexpectedToken(self.token) self.nextStatement() return &ast.BadExpression{From: idx, To: self.idx} }