1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078 |
- package parser
- import (
- "encoding/base64"
- "fmt"
- "os"
- "strings"
- "github.com/dop251/goja/ast"
- "github.com/dop251/goja/file"
- "github.com/dop251/goja/token"
- "github.com/go-sourcemap/sourcemap"
- )
- func (self *_parser) parseBlockStatement() *ast.BlockStatement {
- node := &ast.BlockStatement{}
- node.LeftBrace = self.expect(token.LEFT_BRACE)
- node.List = self.parseStatementList()
- node.RightBrace = self.expect(token.RIGHT_BRACE)
- return node
- }
- func (self *_parser) parseEmptyStatement() ast.Statement {
- idx := self.expect(token.SEMICOLON)
- return &ast.EmptyStatement{Semicolon: idx}
- }
- func (self *_parser) parseStatementList() (list []ast.Statement) {
- for self.token != token.RIGHT_BRACE && self.token != token.EOF {
- self.scope.allowLet = true
- list = append(list, self.parseStatement())
- }
- return
- }
- func (self *_parser) parseStatement() ast.Statement {
- if self.token == token.EOF {
- self.errorUnexpectedToken(self.token)
- return &ast.BadStatement{From: self.idx, To: self.idx + 1}
- }
- switch self.token {
- case token.SEMICOLON:
- return self.parseEmptyStatement()
- case token.LEFT_BRACE:
- return self.parseBlockStatement()
- case token.IF:
- return self.parseIfStatement()
- case token.DO:
- return self.parseDoWhileStatement()
- case token.WHILE:
- return self.parseWhileStatement()
- case token.FOR:
- return self.parseForOrForInStatement()
- case token.BREAK:
- return self.parseBreakStatement()
- case token.CONTINUE:
- return self.parseContinueStatement()
- case token.DEBUGGER:
- return self.parseDebuggerStatement()
- case token.WITH:
- return self.parseWithStatement()
- case token.VAR:
- return self.parseVariableStatement()
- case token.LET:
- tok := self.peek()
- if tok == token.LEFT_BRACKET || self.scope.allowLet && (token.IsId(tok) || tok == token.LEFT_BRACE) {
- return self.parseLexicalDeclaration(self.token)
- }
- self.insertSemicolon = true
- case token.CONST:
- return self.parseLexicalDeclaration(self.token)
- case token.ASYNC:
- if f := self.parseMaybeAsyncFunction(true); f != nil {
- return &ast.FunctionDeclaration{
- Function: f,
- }
- }
- case token.FUNCTION:
- return &ast.FunctionDeclaration{
- Function: self.parseFunction(true, false, self.idx),
- }
- case token.CLASS:
- return &ast.ClassDeclaration{
- Class: self.parseClass(true),
- }
- case token.SWITCH:
- return self.parseSwitchStatement()
- case token.RETURN:
- return self.parseReturnStatement()
- case token.THROW:
- return self.parseThrowStatement()
- case token.TRY:
- return self.parseTryStatement()
- }
- expression := self.parseExpression()
- if identifier, isIdentifier := expression.(*ast.Identifier); isIdentifier && self.token == token.COLON {
- // LabelledStatement
- colon := self.idx
- self.next() // :
- label := identifier.Name
- for _, value := range self.scope.labels {
- if label == value {
- self.error(identifier.Idx0(), "Label '%s' already exists", label)
- }
- }
- self.scope.labels = append(self.scope.labels, label) // Push the label
- self.scope.allowLet = false
- statement := self.parseStatement()
- self.scope.labels = self.scope.labels[:len(self.scope.labels)-1] // Pop the label
- return &ast.LabelledStatement{
- Label: identifier,
- Colon: colon,
- Statement: statement,
- }
- }
- self.optionalSemicolon()
- return &ast.ExpressionStatement{
- Expression: expression,
- }
- }
- func (self *_parser) parseTryStatement() ast.Statement {
- node := &ast.TryStatement{
- Try: self.expect(token.TRY),
- Body: self.parseBlockStatement(),
- }
- if self.token == token.CATCH {
- catch := self.idx
- self.next()
- var parameter ast.BindingTarget
- if self.token == token.LEFT_PARENTHESIS {
- self.next()
- parameter = self.parseBindingTarget()
- self.expect(token.RIGHT_PARENTHESIS)
- }
- node.Catch = &ast.CatchStatement{
- Catch: catch,
- Parameter: parameter,
- Body: self.parseBlockStatement(),
- }
- }
- if self.token == token.FINALLY {
- self.next()
- node.Finally = self.parseBlockStatement()
- }
- if node.Catch == nil && node.Finally == nil {
- self.error(node.Try, "Missing catch or finally after try")
- return &ast.BadStatement{From: node.Try, To: node.Body.Idx1()}
- }
- return node
- }
- func (self *_parser) parseFunctionParameterList() *ast.ParameterList {
- opening := self.expect(token.LEFT_PARENTHESIS)
- var list []*ast.Binding
- var rest ast.Expression
- if !self.scope.inFuncParams {
- self.scope.inFuncParams = true
- defer func() {
- self.scope.inFuncParams = false
- }()
- }
- for self.token != token.RIGHT_PARENTHESIS && self.token != token.EOF {
- if self.token == token.ELLIPSIS {
- self.next()
- rest = self.reinterpretAsDestructBindingTarget(self.parseAssignmentExpression())
- break
- }
- self.parseVariableDeclaration(&list)
- if self.token != token.RIGHT_PARENTHESIS {
- self.expect(token.COMMA)
- }
- }
- closing := self.expect(token.RIGHT_PARENTHESIS)
- return &ast.ParameterList{
- Opening: opening,
- List: list,
- Rest: rest,
- Closing: closing,
- }
- }
- func (self *_parser) parseMaybeAsyncFunction(declaration bool) *ast.FunctionLiteral {
- if self.peek() == token.FUNCTION {
- idx := self.idx
- self.next()
- return self.parseFunction(declaration, true, idx)
- }
- return nil
- }
- func (self *_parser) parseFunction(declaration, async bool, start file.Idx) *ast.FunctionLiteral {
- node := &ast.FunctionLiteral{
- Function: start,
- Async: async,
- }
- self.expect(token.FUNCTION)
- if self.token == token.MULTIPLY {
- node.Generator = true
- self.next()
- }
- if !declaration {
- if async != self.scope.allowAwait {
- self.scope.allowAwait = async
- defer func() {
- self.scope.allowAwait = !async
- }()
- }
- if node.Generator != self.scope.allowYield {
- self.scope.allowYield = node.Generator
- defer func() {
- self.scope.allowYield = !node.Generator
- }()
- }
- }
- self.tokenToBindingId()
- var name *ast.Identifier
- if self.token == token.IDENTIFIER {
- name = self.parseIdentifier()
- } else if declaration {
- // Use expect error handling
- self.expect(token.IDENTIFIER)
- }
- node.Name = name
- if declaration {
- if async != self.scope.allowAwait {
- self.scope.allowAwait = async
- defer func() {
- self.scope.allowAwait = !async
- }()
- }
- if node.Generator != self.scope.allowYield {
- self.scope.allowYield = node.Generator
- defer func() {
- self.scope.allowYield = !node.Generator
- }()
- }
- }
- node.ParameterList = self.parseFunctionParameterList()
- node.Body, node.DeclarationList = self.parseFunctionBlock(async, async, self.scope.allowYield)
- node.Source = self.slice(node.Idx0(), node.Idx1())
- return node
- }
- func (self *_parser) parseFunctionBlock(async, allowAwait, allowYield bool) (body *ast.BlockStatement, declarationList []*ast.VariableDeclaration) {
- self.openScope()
- self.scope.inFunction = true
- self.scope.inAsync = async
- self.scope.allowAwait = allowAwait
- self.scope.allowYield = allowYield
- defer self.closeScope()
- body = self.parseBlockStatement()
- declarationList = self.scope.declarationList
- return
- }
- func (self *_parser) parseArrowFunctionBody(async bool) (ast.ConciseBody, []*ast.VariableDeclaration) {
- if self.token == token.LEFT_BRACE {
- return self.parseFunctionBlock(async, async, false)
- }
- if async != self.scope.inAsync || async != self.scope.allowAwait {
- inAsync := self.scope.inAsync
- allowAwait := self.scope.allowAwait
- self.scope.inAsync = async
- self.scope.allowAwait = async
- allowYield := self.scope.allowYield
- self.scope.allowYield = false
- defer func() {
- self.scope.inAsync = inAsync
- self.scope.allowAwait = allowAwait
- self.scope.allowYield = allowYield
- }()
- }
- return &ast.ExpressionBody{
- Expression: self.parseAssignmentExpression(),
- }, nil
- }
- func (self *_parser) parseClass(declaration bool) *ast.ClassLiteral {
- if !self.scope.allowLet && self.token == token.CLASS {
- self.errorUnexpectedToken(token.CLASS)
- }
- node := &ast.ClassLiteral{
- Class: self.expect(token.CLASS),
- }
- self.tokenToBindingId()
- var name *ast.Identifier
- if self.token == token.IDENTIFIER {
- name = self.parseIdentifier()
- } else if declaration {
- // Use expect error handling
- self.expect(token.IDENTIFIER)
- }
- node.Name = name
- if self.token != token.LEFT_BRACE {
- self.expect(token.EXTENDS)
- node.SuperClass = self.parseLeftHandSideExpressionAllowCall()
- }
- self.expect(token.LEFT_BRACE)
- for self.token != token.RIGHT_BRACE && self.token != token.EOF {
- if self.token == token.SEMICOLON {
- self.next()
- continue
- }
- start := self.idx
- static := false
- if self.token == token.STATIC {
- switch self.peek() {
- case token.ASSIGN, token.SEMICOLON, token.RIGHT_BRACE, token.LEFT_PARENTHESIS:
- // treat as identifier
- default:
- self.next()
- if self.token == token.LEFT_BRACE {
- b := &ast.ClassStaticBlock{
- Static: start,
- }
- b.Block, b.DeclarationList = self.parseFunctionBlock(false, true, false)
- b.Source = self.slice(b.Block.LeftBrace, b.Block.Idx1())
- node.Body = append(node.Body, b)
- continue
- }
- static = true
- }
- }
- var kind ast.PropertyKind
- var async bool
- methodBodyStart := self.idx
- if self.literal == "get" || self.literal == "set" {
- if tok := self.peek(); tok != token.SEMICOLON && tok != token.LEFT_PARENTHESIS {
- if self.literal == "get" {
- kind = ast.PropertyKindGet
- } else {
- kind = ast.PropertyKindSet
- }
- self.next()
- }
- } else if self.token == token.ASYNC {
- if tok := self.peek(); tok != token.SEMICOLON && tok != token.LEFT_PARENTHESIS {
- async = true
- kind = ast.PropertyKindMethod
- self.next()
- }
- }
- generator := false
- if self.token == token.MULTIPLY && (kind == "" || kind == ast.PropertyKindMethod) {
- generator = true
- kind = ast.PropertyKindMethod
- self.next()
- }
- _, keyName, value, tkn := self.parseObjectPropertyKey()
- if value == nil {
- continue
- }
- computed := tkn == token.ILLEGAL
- _, private := value.(*ast.PrivateIdentifier)
- if static && !private && keyName == "prototype" {
- self.error(value.Idx0(), "Classes may not have a static property named 'prototype'")
- }
- if kind == "" && self.token == token.LEFT_PARENTHESIS {
- kind = ast.PropertyKindMethod
- }
- if kind != "" {
- // method
- if keyName == "constructor" && !computed {
- if !static {
- if kind != ast.PropertyKindMethod {
- self.error(value.Idx0(), "Class constructor may not be an accessor")
- } else if async {
- self.error(value.Idx0(), "Class constructor may not be an async method")
- } else if generator {
- self.error(value.Idx0(), "Class constructor may not be a generator")
- }
- } else if private {
- self.error(value.Idx0(), "Class constructor may not be a private method")
- }
- }
- md := &ast.MethodDefinition{
- Idx: start,
- Key: value,
- Kind: kind,
- Body: self.parseMethodDefinition(methodBodyStart, kind, generator, async),
- Static: static,
- Computed: computed,
- }
- node.Body = append(node.Body, md)
- } else {
- // field
- isCtor := !computed && keyName == "constructor"
- if !isCtor {
- if name, ok := value.(*ast.PrivateIdentifier); ok {
- isCtor = name.Name == "constructor"
- }
- }
- if isCtor {
- self.error(value.Idx0(), "Classes may not have a field named 'constructor'")
- }
- var initializer ast.Expression
- if self.token == token.ASSIGN {
- self.next()
- initializer = self.parseExpression()
- }
- if !self.implicitSemicolon && self.token != token.SEMICOLON && self.token != token.RIGHT_BRACE {
- self.errorUnexpectedToken(self.token)
- break
- }
- node.Body = append(node.Body, &ast.FieldDefinition{
- Idx: start,
- Key: value,
- Initializer: initializer,
- Static: static,
- Computed: computed,
- })
- }
- }
- node.RightBrace = self.expect(token.RIGHT_BRACE)
- node.Source = self.slice(node.Class, node.RightBrace+1)
- return node
- }
- func (self *_parser) parseDebuggerStatement() ast.Statement {
- idx := self.expect(token.DEBUGGER)
- node := &ast.DebuggerStatement{
- Debugger: idx,
- }
- self.semicolon()
- return node
- }
- func (self *_parser) parseReturnStatement() ast.Statement {
- idx := self.expect(token.RETURN)
- if !self.scope.inFunction {
- self.error(idx, "Illegal return statement")
- self.nextStatement()
- return &ast.BadStatement{From: idx, To: self.idx}
- }
- node := &ast.ReturnStatement{
- Return: idx,
- }
- if !self.implicitSemicolon && self.token != token.SEMICOLON && self.token != token.RIGHT_BRACE && self.token != token.EOF {
- node.Argument = self.parseExpression()
- }
- self.semicolon()
- return node
- }
- func (self *_parser) parseThrowStatement() ast.Statement {
- idx := self.expect(token.THROW)
- if self.implicitSemicolon {
- if self.chr == -1 { // Hackish
- self.error(idx, "Unexpected end of input")
- } else {
- self.error(idx, "Illegal newline after throw")
- }
- self.nextStatement()
- return &ast.BadStatement{From: idx, To: self.idx}
- }
- node := &ast.ThrowStatement{
- Throw: idx,
- Argument: self.parseExpression(),
- }
- self.semicolon()
- return node
- }
- func (self *_parser) parseSwitchStatement() ast.Statement {
- idx := self.expect(token.SWITCH)
- self.expect(token.LEFT_PARENTHESIS)
- node := &ast.SwitchStatement{
- Switch: idx,
- Discriminant: self.parseExpression(),
- Default: -1,
- }
- self.expect(token.RIGHT_PARENTHESIS)
- self.expect(token.LEFT_BRACE)
- inSwitch := self.scope.inSwitch
- self.scope.inSwitch = true
- defer func() {
- self.scope.inSwitch = inSwitch
- }()
- for index := 0; self.token != token.EOF; index++ {
- if self.token == token.RIGHT_BRACE {
- node.RightBrace = self.idx
- self.next()
- break
- }
- clause := self.parseCaseStatement()
- if clause.Test == nil {
- if node.Default != -1 {
- self.error(clause.Case, "Already saw a default in switch")
- }
- node.Default = index
- }
- node.Body = append(node.Body, clause)
- }
- return node
- }
- func (self *_parser) parseWithStatement() ast.Statement {
- node := &ast.WithStatement{}
- node.With = self.expect(token.WITH)
- self.expect(token.LEFT_PARENTHESIS)
- node.Object = self.parseExpression()
- self.expect(token.RIGHT_PARENTHESIS)
- self.scope.allowLet = false
- node.Body = self.parseStatement()
- return node
- }
- func (self *_parser) parseCaseStatement() *ast.CaseStatement {
- node := &ast.CaseStatement{
- Case: self.idx,
- }
- if self.token == token.DEFAULT {
- self.next()
- } else {
- self.expect(token.CASE)
- node.Test = self.parseExpression()
- }
- self.expect(token.COLON)
- for {
- if self.token == token.EOF ||
- self.token == token.RIGHT_BRACE ||
- self.token == token.CASE ||
- self.token == token.DEFAULT {
- break
- }
- self.scope.allowLet = true
- node.Consequent = append(node.Consequent, self.parseStatement())
- }
- return node
- }
- func (self *_parser) parseIterationStatement() ast.Statement {
- inIteration := self.scope.inIteration
- self.scope.inIteration = true
- defer func() {
- self.scope.inIteration = inIteration
- }()
- self.scope.allowLet = false
- return self.parseStatement()
- }
- func (self *_parser) parseForIn(idx file.Idx, into ast.ForInto) *ast.ForInStatement {
- // Already have consumed "<into> in"
- source := self.parseExpression()
- self.expect(token.RIGHT_PARENTHESIS)
- return &ast.ForInStatement{
- For: idx,
- Into: into,
- Source: source,
- Body: self.parseIterationStatement(),
- }
- }
- func (self *_parser) parseForOf(idx file.Idx, into ast.ForInto) *ast.ForOfStatement {
- // Already have consumed "<into> of"
- source := self.parseAssignmentExpression()
- self.expect(token.RIGHT_PARENTHESIS)
- return &ast.ForOfStatement{
- For: idx,
- Into: into,
- Source: source,
- Body: self.parseIterationStatement(),
- }
- }
- func (self *_parser) parseFor(idx file.Idx, initializer ast.ForLoopInitializer) *ast.ForStatement {
- // Already have consumed "<initializer> ;"
- var test, update ast.Expression
- if self.token != token.SEMICOLON {
- test = self.parseExpression()
- }
- self.expect(token.SEMICOLON)
- if self.token != token.RIGHT_PARENTHESIS {
- update = self.parseExpression()
- }
- self.expect(token.RIGHT_PARENTHESIS)
- return &ast.ForStatement{
- For: idx,
- Initializer: initializer,
- Test: test,
- Update: update,
- Body: self.parseIterationStatement(),
- }
- }
- func (self *_parser) parseForOrForInStatement() ast.Statement {
- idx := self.expect(token.FOR)
- self.expect(token.LEFT_PARENTHESIS)
- var initializer ast.ForLoopInitializer
- forIn := false
- forOf := false
- var into ast.ForInto
- if self.token != token.SEMICOLON {
- allowIn := self.scope.allowIn
- self.scope.allowIn = false
- tok := self.token
- if tok == token.LET {
- switch self.peek() {
- case token.IDENTIFIER, token.LEFT_BRACKET, token.LEFT_BRACE:
- default:
- tok = token.IDENTIFIER
- }
- }
- if tok == token.VAR || tok == token.LET || tok == token.CONST {
- idx := self.idx
- self.next()
- var list []*ast.Binding
- if tok == token.VAR {
- list = self.parseVarDeclarationList(idx)
- } else {
- list = self.parseVariableDeclarationList()
- }
- if len(list) == 1 {
- if self.token == token.IN {
- self.next() // in
- forIn = true
- } else if self.token == token.IDENTIFIER && self.literal == "of" {
- self.next()
- forOf = true
- }
- }
- if forIn || forOf {
- if list[0].Initializer != nil {
- self.error(list[0].Initializer.Idx0(), "for-in loop variable declaration may not have an initializer")
- }
- if tok == token.VAR {
- into = &ast.ForIntoVar{
- Binding: list[0],
- }
- } else {
- into = &ast.ForDeclaration{
- Idx: idx,
- IsConst: tok == token.CONST,
- Target: list[0].Target,
- }
- }
- } else {
- self.ensurePatternInit(list)
- if tok == token.VAR {
- initializer = &ast.ForLoopInitializerVarDeclList{
- List: list,
- }
- } else {
- initializer = &ast.ForLoopInitializerLexicalDecl{
- LexicalDeclaration: ast.LexicalDeclaration{
- Idx: idx,
- Token: tok,
- List: list,
- },
- }
- }
- }
- } else {
- expr := self.parseExpression()
- if self.token == token.IN {
- self.next()
- forIn = true
- } else if self.token == token.IDENTIFIER && self.literal == "of" {
- self.next()
- forOf = true
- }
- if forIn || forOf {
- switch e := expr.(type) {
- case *ast.Identifier, *ast.DotExpression, *ast.PrivateDotExpression, *ast.BracketExpression, *ast.Binding:
- // These are all acceptable
- case *ast.ObjectLiteral:
- expr = self.reinterpretAsObjectAssignmentPattern(e)
- case *ast.ArrayLiteral:
- expr = self.reinterpretAsArrayAssignmentPattern(e)
- default:
- self.error(idx, "Invalid left-hand side in for-in or for-of")
- self.nextStatement()
- return &ast.BadStatement{From: idx, To: self.idx}
- }
- into = &ast.ForIntoExpression{
- Expression: expr,
- }
- } else {
- initializer = &ast.ForLoopInitializerExpression{
- Expression: expr,
- }
- }
- }
- self.scope.allowIn = allowIn
- }
- if forIn {
- return self.parseForIn(idx, into)
- }
- if forOf {
- return self.parseForOf(idx, into)
- }
- self.expect(token.SEMICOLON)
- return self.parseFor(idx, initializer)
- }
- func (self *_parser) ensurePatternInit(list []*ast.Binding) {
- for _, item := range list {
- if _, ok := item.Target.(ast.Pattern); ok {
- if item.Initializer == nil {
- self.error(item.Idx1(), "Missing initializer in destructuring declaration")
- break
- }
- }
- }
- }
- func (self *_parser) parseVariableStatement() *ast.VariableStatement {
- idx := self.expect(token.VAR)
- list := self.parseVarDeclarationList(idx)
- self.ensurePatternInit(list)
- self.semicolon()
- return &ast.VariableStatement{
- Var: idx,
- List: list,
- }
- }
- func (self *_parser) parseLexicalDeclaration(tok token.Token) *ast.LexicalDeclaration {
- idx := self.expect(tok)
- if !self.scope.allowLet {
- self.error(idx, "Lexical declaration cannot appear in a single-statement context")
- }
- list := self.parseVariableDeclarationList()
- self.ensurePatternInit(list)
- self.semicolon()
- return &ast.LexicalDeclaration{
- Idx: idx,
- Token: tok,
- List: list,
- }
- }
- func (self *_parser) parseDoWhileStatement() ast.Statement {
- inIteration := self.scope.inIteration
- self.scope.inIteration = true
- defer func() {
- self.scope.inIteration = inIteration
- }()
- node := &ast.DoWhileStatement{}
- node.Do = self.expect(token.DO)
- if self.token == token.LEFT_BRACE {
- node.Body = self.parseBlockStatement()
- } else {
- self.scope.allowLet = false
- node.Body = self.parseStatement()
- }
- self.expect(token.WHILE)
- self.expect(token.LEFT_PARENTHESIS)
- node.Test = self.parseExpression()
- node.RightParenthesis = self.expect(token.RIGHT_PARENTHESIS)
- if self.token == token.SEMICOLON {
- self.next()
- }
- return node
- }
- func (self *_parser) parseWhileStatement() ast.Statement {
- idx := self.expect(token.WHILE)
- self.expect(token.LEFT_PARENTHESIS)
- node := &ast.WhileStatement{
- While: idx,
- Test: self.parseExpression(),
- }
- self.expect(token.RIGHT_PARENTHESIS)
- node.Body = self.parseIterationStatement()
- return node
- }
- func (self *_parser) parseIfStatement() ast.Statement {
- self.expect(token.IF)
- self.expect(token.LEFT_PARENTHESIS)
- node := &ast.IfStatement{
- Test: self.parseExpression(),
- }
- self.expect(token.RIGHT_PARENTHESIS)
- if self.token == token.LEFT_BRACE {
- node.Consequent = self.parseBlockStatement()
- } else {
- self.scope.allowLet = false
- node.Consequent = self.parseStatement()
- }
- if self.token == token.ELSE {
- self.next()
- self.scope.allowLet = false
- node.Alternate = self.parseStatement()
- }
- return node
- }
- func (self *_parser) parseSourceElements() (body []ast.Statement) {
- for self.token != token.EOF {
- self.scope.allowLet = true
- body = append(body, self.parseStatement())
- }
- return body
- }
- func (self *_parser) parseProgram() *ast.Program {
- prg := &ast.Program{
- Body: self.parseSourceElements(),
- DeclarationList: self.scope.declarationList,
- File: self.file,
- }
- self.file.SetSourceMap(self.parseSourceMap())
- return prg
- }
- func extractSourceMapLine(str string) string {
- for {
- p := strings.LastIndexByte(str, '\n')
- line := str[p+1:]
- if line != "" && line != "})" {
- if strings.HasPrefix(line, "//# sourceMappingURL=") {
- return line
- }
- break
- }
- if p >= 0 {
- str = str[:p]
- } else {
- break
- }
- }
- return ""
- }
- func (self *_parser) parseSourceMap() *sourcemap.Consumer {
- if self.opts.disableSourceMaps {
- return nil
- }
- if smLine := extractSourceMapLine(self.str); smLine != "" {
- urlIndex := strings.Index(smLine, "=")
- urlStr := smLine[urlIndex+1:]
- var data []byte
- var err error
- if strings.HasPrefix(urlStr, "data:application/json") {
- b64Index := strings.Index(urlStr, ",")
- b64 := urlStr[b64Index+1:]
- data, err = base64.StdEncoding.DecodeString(b64)
- } else {
- if sourceURL := file.ResolveSourcemapURL(self.file.Name(), urlStr); sourceURL != nil {
- if self.opts.sourceMapLoader != nil {
- data, err = self.opts.sourceMapLoader(sourceURL.String())
- } else {
- if sourceURL.Scheme == "" || sourceURL.Scheme == "file" {
- data, err = os.ReadFile(sourceURL.Path)
- } else {
- err = fmt.Errorf("unsupported source map URL scheme: %s", sourceURL.Scheme)
- }
- }
- }
- }
- if err != nil {
- self.error(file.Idx(0), "Could not load source map: %v", err)
- return nil
- }
- if data == nil {
- return nil
- }
- if sm, err := sourcemap.Parse(self.file.Name(), data); err == nil {
- return sm
- } else {
- self.error(file.Idx(0), "Could not parse source map: %v", err)
- }
- }
- return nil
- }
- func (self *_parser) parseBreakStatement() ast.Statement {
- idx := self.expect(token.BREAK)
- semicolon := self.implicitSemicolon
- if self.token == token.SEMICOLON {
- semicolon = true
- self.next()
- }
- if semicolon || self.token == token.RIGHT_BRACE {
- self.implicitSemicolon = false
- if !self.scope.inIteration && !self.scope.inSwitch {
- goto illegal
- }
- return &ast.BranchStatement{
- Idx: idx,
- Token: token.BREAK,
- }
- }
- self.tokenToBindingId()
- if self.token == token.IDENTIFIER {
- identifier := self.parseIdentifier()
- if !self.scope.hasLabel(identifier.Name) {
- self.error(idx, "Undefined label '%s'", identifier.Name)
- return &ast.BadStatement{From: idx, To: identifier.Idx1()}
- }
- self.semicolon()
- return &ast.BranchStatement{
- Idx: idx,
- Token: token.BREAK,
- Label: identifier,
- }
- }
- self.expect(token.IDENTIFIER)
- illegal:
- self.error(idx, "Illegal break statement")
- self.nextStatement()
- return &ast.BadStatement{From: idx, To: self.idx}
- }
- func (self *_parser) parseContinueStatement() ast.Statement {
- idx := self.expect(token.CONTINUE)
- semicolon := self.implicitSemicolon
- if self.token == token.SEMICOLON {
- semicolon = true
- self.next()
- }
- if semicolon || self.token == token.RIGHT_BRACE {
- self.implicitSemicolon = false
- if !self.scope.inIteration {
- goto illegal
- }
- return &ast.BranchStatement{
- Idx: idx,
- Token: token.CONTINUE,
- }
- }
- self.tokenToBindingId()
- if self.token == token.IDENTIFIER {
- identifier := self.parseIdentifier()
- if !self.scope.hasLabel(identifier.Name) {
- self.error(idx, "Undefined label '%s'", identifier.Name)
- return &ast.BadStatement{From: idx, To: identifier.Idx1()}
- }
- if !self.scope.inIteration {
- goto illegal
- }
- self.semicolon()
- return &ast.BranchStatement{
- Idx: idx,
- Token: token.CONTINUE,
- Label: identifier,
- }
- }
- self.expect(token.IDENTIFIER)
- illegal:
- self.error(idx, "Illegal continue statement")
- self.nextStatement()
- return &ast.BadStatement{From: idx, To: self.idx}
- }
- // Find the next statement after an error (recover)
- func (self *_parser) nextStatement() {
- for {
- switch self.token {
- case token.BREAK, token.CONTINUE,
- token.FOR, token.IF, token.RETURN, token.SWITCH,
- token.VAR, token.DO, token.TRY, token.WITH,
- token.WHILE, token.THROW, token.CATCH, token.FINALLY:
- // Return only if parser made some progress since last
- // sync or if it has not reached 10 next calls without
- // progress. Otherwise consume at least one token to
- // avoid an endless parser loop
- if self.idx == self.recover.idx && self.recover.count < 10 {
- self.recover.count++
- return
- }
- if self.idx > self.recover.idx {
- self.recover.idx = self.idx
- self.recover.count = 0
- return
- }
- // Reaching here indicates a parser bug, likely an
- // incorrect token list in this function, but it only
- // leads to skipping of possibly correct code if a
- // previous error is present, and thus is preferred
- // over a non-terminating parse.
- case token.EOF:
- return
- }
- self.next()
- }
- }
|