12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339 |
- package js
- import (
- "bytes"
- "errors"
- "fmt"
- "io"
- "github.com/tdewolff/parse/v2"
- "github.com/tdewolff/parse/v2/buffer"
- )
- type Options struct {
- WhileToFor bool
- Inline bool
- }
- // Parser is the state for the parser.
- type Parser struct {
- l *Lexer
- o Options
- err error
- data []byte
- tt TokenType
- prevLT bool
- in, await, yield, deflt, retrn bool
- assumeArrowFunc bool
- allowDirectivePrologue bool
- stmtLevel int
- exprLevel int
- scope *Scope
- }
- // Parse returns a JS AST tree of.
- func Parse(r *parse.Input, o Options) (*AST, error) {
- ast := &AST{}
- p := &Parser{
- l: NewLexer(r),
- o: o,
- tt: WhitespaceToken, // trick so that next() works
- in: true,
- await: true,
- }
- if o.Inline {
- p.next()
- p.retrn = true
- p.allowDirectivePrologue = true
- p.enterScope(&ast.BlockStmt.Scope, true)
- for {
- if p.tt == ErrorToken {
- break
- }
- ast.BlockStmt.List = append(ast.BlockStmt.List, p.parseStmt(true))
- }
- } else {
- // catch shebang in first line
- var shebang []byte
- if r.Peek(0) == '#' && r.Peek(1) == '!' {
- r.Move(2)
- p.l.consumeSingleLineComment() // consume till end-of-line
- shebang = r.Shift()
- }
- // parse JS module
- p.next()
- ast.BlockStmt = p.parseModule()
- if 0 < len(shebang) {
- ast.BlockStmt.List = append([]IStmt{&Comment{shebang}}, ast.BlockStmt.List...)
- }
- }
- if p.err == nil {
- p.err = p.l.Err()
- } else {
- offset := p.l.r.Offset() - len(p.data)
- p.err = parse.NewError(buffer.NewReader(p.l.r.Bytes()), offset, p.err.Error())
- }
- if p.err == io.EOF {
- p.err = nil
- }
- return ast, p.err
- }
- ////////////////////////////////////////////////////////////////
- func (p *Parser) next() {
- p.prevLT = false
- p.tt, p.data = p.l.Next()
- for p.tt == WhitespaceToken || p.tt == LineTerminatorToken || (p.tt == CommentToken || p.tt == CommentLineTerminatorToken) && (p.exprLevel != 0 || len(p.data) < 3 || p.data[2] != '!') {
- if p.tt == LineTerminatorToken || p.tt == CommentLineTerminatorToken {
- p.prevLT = true
- }
- p.tt, p.data = p.l.Next()
- }
- }
- func (p *Parser) failMessage(msg string, args ...interface{}) {
- if p.err == nil {
- p.err = fmt.Errorf(msg, args...)
- p.tt = ErrorToken
- }
- }
- func (p *Parser) fail(in string, expected ...TokenType) {
- if p.err == nil {
- msg := "unexpected"
- if 0 < len(expected) {
- msg = "expected"
- for i, tt := range expected[:len(expected)-1] {
- if 0 < i {
- msg += ","
- }
- msg += " " + tt.String() + ""
- }
- if 2 < len(expected) {
- msg += ", or"
- } else if 1 < len(expected) {
- msg += " or"
- }
- msg += " " + expected[len(expected)-1].String() + " instead of"
- }
- if p.tt == ErrorToken {
- if p.l.Err() == io.EOF {
- msg += " EOF"
- } else if lexerErr, ok := p.l.Err().(*parse.Error); ok {
- msg = lexerErr.Message
- } else {
- // does not happen
- }
- } else {
- msg += " " + string(p.data) + ""
- }
- if in != "" {
- msg += " in " + in
- }
- p.err = errors.New(msg)
- p.tt = ErrorToken
- }
- }
- func (p *Parser) consume(in string, tt TokenType) bool {
- if p.tt != tt {
- p.fail(in, tt)
- return false
- }
- p.next()
- return true
- }
- func (p *Parser) enterScope(scope *Scope, isFunc bool) *Scope {
- // create a new scope object and add it to the parent
- parent := p.scope
- p.scope = scope
- *scope = Scope{
- Parent: parent,
- }
- if isFunc {
- scope.Func = scope
- } else if parent != nil {
- scope.Func = parent.Func
- }
- return parent
- }
- func (p *Parser) exitScope(parent *Scope) {
- p.scope.HoistUndeclared()
- p.scope = parent
- }
- func (p *Parser) parseModule() (module BlockStmt) {
- p.enterScope(&module.Scope, true)
- p.allowDirectivePrologue = true
- for {
- switch p.tt {
- case ErrorToken:
- return
- case ImportToken:
- p.next()
- if p.tt == OpenParenToken {
- // could be an import call expression
- left := &LiteralExpr{ImportToken, []byte("import")}
- p.exprLevel++
- suffix := p.parseExpressionSuffix(left, OpExpr, OpCall)
- p.exprLevel--
- module.List = append(module.List, &ExprStmt{suffix})
- if !p.prevLT && p.tt == SemicolonToken {
- p.next()
- }
- } else {
- importStmt := p.parseImportStmt()
- module.List = append(module.List, &importStmt)
- }
- case ExportToken:
- exportStmt := p.parseExportStmt()
- module.List = append(module.List, &exportStmt)
- default:
- module.List = append(module.List, p.parseStmt(true))
- }
- }
- }
- func (p *Parser) parseStmt(allowDeclaration bool) (stmt IStmt) {
- p.stmtLevel++
- if 1000 < p.stmtLevel {
- p.failMessage("too many nested statements")
- return nil
- }
- allowDirectivePrologue := p.allowDirectivePrologue
- p.allowDirectivePrologue = false
- switch tt := p.tt; tt {
- case OpenBraceToken:
- stmt = p.parseBlockStmt("block statement")
- case ConstToken, VarToken:
- if !allowDeclaration && tt == ConstToken {
- p.fail("statement")
- return
- }
- p.next()
- varDecl := p.parseVarDecl(tt, true)
- stmt = varDecl
- if !p.prevLT && p.tt != SemicolonToken && p.tt != CloseBraceToken && p.tt != ErrorToken {
- if tt == ConstToken {
- p.fail("const declaration")
- } else {
- p.fail("var statement")
- }
- return
- }
- case LetToken:
- let := p.data
- p.next()
- if allowDeclaration && (IsIdentifier(p.tt) || p.tt == YieldToken || p.tt == AwaitToken || p.tt == OpenBracketToken || p.tt == OpenBraceToken) {
- stmt = p.parseVarDecl(tt, false)
- if !p.prevLT && p.tt != SemicolonToken && p.tt != CloseBraceToken && p.tt != ErrorToken {
- p.fail("let declaration")
- return
- }
- } else {
- // expression
- stmt = &ExprStmt{p.parseIdentifierExpression(OpExpr, let)}
- if !p.prevLT && p.tt != SemicolonToken && p.tt != CloseBraceToken && p.tt != ErrorToken {
- p.fail("expression")
- return
- }
- }
- case IfToken:
- p.next()
- if !p.consume("if statement", OpenParenToken) {
- return
- }
- cond := p.parseExpression(OpExpr)
- if !p.consume("if statement", CloseParenToken) {
- return
- }
- body := p.parseStmt(false)
- var elseBody IStmt
- if p.tt == ElseToken {
- p.next()
- elseBody = p.parseStmt(false)
- }
- stmt = &IfStmt{cond, body, elseBody}
- case ContinueToken, BreakToken:
- tt := p.tt
- p.next()
- var label []byte
- if !p.prevLT && p.isIdentifierReference(p.tt) {
- label = p.data
- p.next()
- }
- stmt = &BranchStmt{tt, label}
- case WithToken:
- p.next()
- if !p.consume("with statement", OpenParenToken) {
- return
- }
- cond := p.parseExpression(OpExpr)
- if !p.consume("with statement", CloseParenToken) {
- return
- }
- p.scope.Func.HasWith = true
- stmt = &WithStmt{cond, p.parseStmt(false)}
- case DoToken:
- stmt = &DoWhileStmt{}
- p.next()
- body := p.parseStmt(false)
- if !p.consume("do-while statement", WhileToken) {
- return
- }
- if !p.consume("do-while statement", OpenParenToken) {
- return
- }
- stmt = &DoWhileStmt{p.parseExpression(OpExpr), body}
- if !p.consume("do-while statement", CloseParenToken) {
- return
- }
- case WhileToken:
- p.next()
- if !p.consume("while statement", OpenParenToken) {
- return
- }
- cond := p.parseExpression(OpExpr)
- if !p.consume("while statement", CloseParenToken) {
- return
- }
- body := p.parseStmt(false)
- if p.o.WhileToFor {
- varDecl := &VarDecl{TokenType: VarToken, Scope: p.scope, InFor: true}
- p.scope.Func.VarDecls = append(p.scope.Func.VarDecls, varDecl)
- block, ok := body.(*BlockStmt)
- if !ok {
- block = &BlockStmt{List: []IStmt{body}}
- }
- stmt = &ForStmt{varDecl, cond, nil, block}
- } else {
- stmt = &WhileStmt{cond, body}
- }
- case ForToken:
- p.next()
- await := p.await && p.tt == AwaitToken
- if await {
- p.next()
- }
- if !p.consume("for statement", OpenParenToken) {
- return
- }
- body := &BlockStmt{}
- parent := p.enterScope(&body.Scope, false)
- var init IExpr
- p.in = false
- if p.tt == VarToken || p.tt == LetToken || p.tt == ConstToken {
- tt := p.tt
- p.next()
- varDecl := p.parseVarDecl(tt, true)
- if p.err != nil {
- return
- } else if p.tt != SemicolonToken && (1 < len(varDecl.List) || varDecl.List[0].Default != nil) {
- p.fail("for statement")
- return
- } else if p.tt == SemicolonToken && varDecl.List[0].Default == nil {
- // all but the first item were already verified
- if _, ok := varDecl.List[0].Binding.(*Var); !ok {
- p.fail("for statement")
- return
- }
- }
- init = varDecl
- } else if await {
- init = p.parseExpression(OpLHS)
- } else if p.tt != SemicolonToken {
- init = p.parseExpression(OpExpr)
- }
- p.in = true
- isLHSExpr := isLHSExpr(init)
- if isLHSExpr && p.tt == InToken {
- if await {
- p.fail("for statement", OfToken)
- return
- }
- p.next()
- value := p.parseExpression(OpExpr)
- if !p.consume("for statement", CloseParenToken) {
- return
- }
- p.scope.MarkForStmt()
- if p.tt == OpenBraceToken {
- body.List = p.parseStmtList("")
- } else if p.tt != SemicolonToken {
- body.List = []IStmt{p.parseStmt(false)}
- } else {
- p.next()
- }
- if varDecl, ok := init.(*VarDecl); ok {
- varDecl.InForInOf = true
- }
- stmt = &ForInStmt{init, value, body}
- } else if isLHSExpr && p.tt == OfToken {
- p.next()
- value := p.parseExpression(OpAssign)
- if !p.consume("for statement", CloseParenToken) {
- return
- }
- p.scope.MarkForStmt()
- if p.tt == OpenBraceToken {
- body.List = p.parseStmtList("")
- } else if p.tt != SemicolonToken {
- body.List = []IStmt{p.parseStmt(false)}
- } else {
- p.next()
- }
- if varDecl, ok := init.(*VarDecl); ok {
- varDecl.InForInOf = true
- }
- stmt = &ForOfStmt{await, init, value, body}
- } else if p.tt == SemicolonToken {
- var cond, post IExpr
- if await {
- p.fail("for statement", OfToken)
- return
- }
- p.next()
- if p.tt != SemicolonToken {
- cond = p.parseExpression(OpExpr)
- }
- if !p.consume("for statement", SemicolonToken) {
- return
- }
- if p.tt != CloseParenToken {
- post = p.parseExpression(OpExpr)
- }
- if !p.consume("for statement", CloseParenToken) {
- return
- }
- p.scope.MarkForStmt()
- if p.tt == OpenBraceToken {
- body.List = p.parseStmtList("")
- } else if p.tt != SemicolonToken {
- body.List = []IStmt{p.parseStmt(false)}
- } else {
- p.next()
- }
- if init == nil {
- varDecl := &VarDecl{TokenType: VarToken, Scope: p.scope, InFor: true}
- p.scope.Func.VarDecls = append(p.scope.Func.VarDecls, varDecl)
- init = varDecl
- } else if varDecl, ok := init.(*VarDecl); ok {
- varDecl.InFor = true
- }
- stmt = &ForStmt{init, cond, post, body}
- } else if isLHSExpr {
- p.fail("for statement", InToken, OfToken, SemicolonToken)
- return
- } else {
- p.fail("for statement", SemicolonToken)
- return
- }
- p.exitScope(parent)
- case SwitchToken:
- p.next()
- if !p.consume("switch statement", OpenParenToken) {
- return
- }
- init := p.parseExpression(OpExpr)
- if !p.consume("switch statement", CloseParenToken) {
- return
- }
- // case block
- if !p.consume("switch statement", OpenBraceToken) {
- return
- }
- switchStmt := &SwitchStmt{Init: init}
- parent := p.enterScope(&switchStmt.Scope, false)
- for {
- if p.tt == ErrorToken {
- p.fail("switch statement")
- return
- } else if p.tt == CloseBraceToken {
- p.next()
- break
- }
- clause := p.tt
- var list IExpr
- if p.tt == CaseToken {
- p.next()
- list = p.parseExpression(OpExpr)
- } else if p.tt == DefaultToken {
- p.next()
- } else {
- p.fail("switch statement", CaseToken, DefaultToken)
- return
- }
- if !p.consume("switch statement", ColonToken) {
- return
- }
- var stmts []IStmt
- for p.tt != CaseToken && p.tt != DefaultToken && p.tt != CloseBraceToken && p.tt != ErrorToken {
- stmts = append(stmts, p.parseStmt(true))
- }
- switchStmt.List = append(switchStmt.List, CaseClause{clause, list, stmts})
- }
- p.exitScope(parent)
- stmt = switchStmt
- case FunctionToken:
- if !allowDeclaration {
- p.fail("statement")
- return
- }
- stmt = p.parseFuncDecl()
- case AsyncToken: // async function
- if !allowDeclaration {
- p.fail("statement")
- return
- }
- async := p.data
- p.next()
- if p.tt == FunctionToken && !p.prevLT {
- stmt = p.parseAsyncFuncDecl()
- } else {
- // expression
- stmt = &ExprStmt{p.parseAsyncExpression(OpExpr, async)}
- if !p.prevLT && p.tt != SemicolonToken && p.tt != CloseBraceToken && p.tt != ErrorToken {
- p.fail("expression")
- return
- }
- }
- case ClassToken:
- if !allowDeclaration {
- p.fail("statement")
- return
- }
- stmt = p.parseClassDecl()
- case ThrowToken:
- p.next()
- if p.prevLT {
- p.failMessage("unexpected newline in throw statement")
- return
- }
- stmt = &ThrowStmt{p.parseExpression(OpExpr)}
- case TryToken:
- p.next()
- body := p.parseBlockStmt("try statement")
- var binding IBinding
- var catch, finally *BlockStmt
- if p.tt == CatchToken {
- p.next()
- catch = &BlockStmt{}
- parent := p.enterScope(&catch.Scope, false)
- if p.tt == OpenParenToken {
- p.next()
- binding = p.parseBinding(CatchDecl) // local to block scope of catch
- if !p.consume("try-catch statement", CloseParenToken) {
- return
- }
- }
- catch.List = p.parseStmtList("try-catch statement")
- p.exitScope(parent)
- } else if p.tt != FinallyToken {
- p.fail("try statement", CatchToken, FinallyToken)
- return
- }
- if p.tt == FinallyToken {
- p.next()
- finally = p.parseBlockStmt("try-finally statement")
- }
- stmt = &TryStmt{body, binding, catch, finally}
- case DebuggerToken:
- stmt = &DebuggerStmt{}
- p.next()
- case SemicolonToken:
- stmt = &EmptyStmt{}
- p.next()
- case CommentToken, CommentLineTerminatorToken:
- // bang comment
- stmt = &Comment{p.data}
- p.next()
- case ErrorToken:
- stmt = &EmptyStmt{}
- return
- default:
- if p.retrn && p.tt == ReturnToken {
- p.next()
- var value IExpr
- if !p.prevLT && p.tt != SemicolonToken && p.tt != CloseBraceToken && p.tt != ErrorToken {
- value = p.parseExpression(OpExpr)
- }
- stmt = &ReturnStmt{value}
- } else if p.isIdentifierReference(p.tt) {
- // LabelledStatement, Expression
- label := p.data
- p.next()
- if p.tt == ColonToken {
- p.next()
- prevDeflt := p.deflt
- if p.tt == FunctionToken {
- p.deflt = false
- }
- stmt = &LabelledStmt{label, p.parseStmt(true)} // allows illegal async function, generator function, let, const, or class declarations
- p.deflt = prevDeflt
- } else {
- // expression
- stmt = &ExprStmt{p.parseIdentifierExpression(OpExpr, label)}
- if !p.prevLT && p.tt != SemicolonToken && p.tt != CloseBraceToken && p.tt != ErrorToken {
- p.fail("expression")
- return
- }
- }
- } else {
- // expression
- stmt = &ExprStmt{p.parseExpression(OpExpr)}
- if !p.prevLT && p.tt != SemicolonToken && p.tt != CloseBraceToken && p.tt != ErrorToken {
- p.fail("expression")
- return
- } else if lit, ok := stmt.(*ExprStmt).Value.(*LiteralExpr); ok && allowDirectivePrologue && lit.TokenType == StringToken && len(lit.Data) == 12 && bytes.Equal(lit.Data[1:11], []byte("use strict")) {
- stmt = &DirectivePrologueStmt{lit.Data}
- p.allowDirectivePrologue = true
- }
- }
- }
- if !p.prevLT && p.tt == SemicolonToken {
- p.next()
- }
- p.stmtLevel--
- return
- }
- func (p *Parser) parseStmtList(in string) (list []IStmt) {
- if !p.consume(in, OpenBraceToken) {
- return
- }
- for {
- if p.tt == ErrorToken {
- p.fail("")
- return
- } else if p.tt == CloseBraceToken {
- p.next()
- break
- }
- list = append(list, p.parseStmt(true))
- }
- return
- }
- func (p *Parser) parseBlockStmt(in string) (blockStmt *BlockStmt) {
- blockStmt = &BlockStmt{}
- parent := p.enterScope(&blockStmt.Scope, false)
- blockStmt.List = p.parseStmtList(in)
- p.exitScope(parent)
- return
- }
- func (p *Parser) parseImportStmt() (importStmt ImportStmt) {
- // assume we're passed import
- if p.tt == StringToken {
- importStmt.Module = p.data
- p.next()
- } else {
- expectClause := true
- if IsIdentifier(p.tt) || p.tt == YieldToken {
- importStmt.Default = p.data
- p.next()
- expectClause = p.tt == CommaToken
- if expectClause {
- p.next()
- }
- }
- if expectClause && p.tt == MulToken {
- star := p.data
- p.next()
- if !p.consume("import statement", AsToken) {
- return
- }
- if !IsIdentifier(p.tt) && p.tt != YieldToken {
- p.fail("import statement", IdentifierToken)
- return
- }
- importStmt.List = []Alias{Alias{star, p.data}}
- p.next()
- } else if expectClause && p.tt == OpenBraceToken {
- p.next()
- importStmt.List = []Alias{}
- for IsIdentifierName(p.tt) || p.tt == StringToken {
- tt := p.tt
- var name, binding []byte = nil, p.data
- p.next()
- if p.tt == AsToken {
- p.next()
- if !IsIdentifier(p.tt) && p.tt != YieldToken {
- p.fail("import statement", IdentifierToken)
- return
- }
- name = binding
- binding = p.data
- p.next()
- } else if !IsIdentifier(tt) && tt != YieldToken || tt == StringToken {
- p.fail("import statement", IdentifierToken, StringToken)
- return
- }
- importStmt.List = append(importStmt.List, Alias{name, binding})
- if p.tt == CommaToken {
- p.next()
- if p.tt == CloseBraceToken {
- importStmt.List = append(importStmt.List, Alias{})
- break
- }
- }
- }
- if !p.consume("import statement", CloseBraceToken) {
- return
- }
- } else if expectClause && importStmt.Default != nil {
- p.fail("import statement", MulToken, OpenBraceToken)
- return
- } else if importStmt.Default == nil {
- p.fail("import statement", StringToken, IdentifierToken, MulToken, OpenBraceToken)
- return
- }
- if !p.consume("import statement", FromToken) {
- return
- }
- if p.tt != StringToken {
- p.fail("import statement", StringToken)
- return
- }
- importStmt.Module = p.data
- p.next()
- }
- if p.tt == SemicolonToken {
- p.next()
- }
- return
- }
- func (p *Parser) parseExportStmt() (exportStmt ExportStmt) {
- // assume we're at export
- p.next()
- prevYield, prevAwait, prevDeflt := p.yield, p.await, p.deflt
- p.yield, p.await, p.deflt = false, true, true
- if p.tt == MulToken || p.tt == OpenBraceToken {
- if p.tt == MulToken {
- star := p.data
- p.next()
- if p.tt == AsToken {
- p.next()
- if !IsIdentifierName(p.tt) && p.tt != StringToken {
- p.fail("export statement", IdentifierToken, StringToken)
- return
- }
- exportStmt.List = []Alias{Alias{star, p.data}}
- p.next()
- } else {
- exportStmt.List = []Alias{Alias{nil, star}}
- }
- if p.tt != FromToken {
- p.fail("export statement", FromToken)
- return
- }
- } else {
- p.next()
- for IsIdentifierName(p.tt) || p.tt == StringToken {
- var name, binding []byte = nil, p.data
- p.next()
- if p.tt == AsToken {
- p.next()
- if !IsIdentifierName(p.tt) && p.tt != StringToken {
- p.fail("export statement", IdentifierToken, StringToken)
- return
- }
- name = binding
- binding = p.data
- p.next()
- }
- exportStmt.List = append(exportStmt.List, Alias{name, binding})
- if p.tt == CommaToken {
- p.next()
- if p.tt == CloseBraceToken {
- exportStmt.List = append(exportStmt.List, Alias{})
- break
- }
- }
- }
- if !p.consume("export statement", CloseBraceToken) {
- return
- }
- }
- if p.tt == FromToken {
- p.next()
- if p.tt != StringToken {
- p.fail("export statement", StringToken)
- return
- }
- exportStmt.Module = p.data
- p.next()
- }
- } else if p.tt == VarToken || p.tt == ConstToken || p.tt == LetToken {
- tt := p.tt
- p.next()
- exportStmt.Decl = p.parseVarDecl(tt, false)
- } else if p.tt == FunctionToken {
- exportStmt.Decl = p.parseFuncDecl()
- } else if p.tt == AsyncToken { // async function
- p.next()
- if p.tt != FunctionToken || p.prevLT {
- p.fail("export statement", FunctionToken)
- return
- }
- exportStmt.Decl = p.parseAsyncFuncDecl()
- } else if p.tt == ClassToken {
- exportStmt.Decl = p.parseClassDecl()
- } else if p.tt == DefaultToken {
- exportStmt.Default = true
- p.next()
- if p.tt == FunctionToken {
- exportStmt.Decl = p.parseFuncDecl()
- } else if p.tt == AsyncToken { // async function or async arrow function
- async := p.data
- p.next()
- if p.tt == FunctionToken && !p.prevLT {
- exportStmt.Decl = p.parseAsyncFuncDecl()
- } else {
- // expression
- exportStmt.Decl = p.parseAsyncExpression(OpExpr, async)
- }
- } else if p.tt == ClassToken {
- exportStmt.Decl = p.parseClassDecl()
- } else {
- exportStmt.Decl = p.parseExpression(OpAssign)
- }
- } else {
- p.fail("export statement", MulToken, OpenBraceToken, VarToken, LetToken, ConstToken, FunctionToken, AsyncToken, ClassToken, DefaultToken)
- return
- }
- if p.tt == SemicolonToken {
- p.next()
- }
- p.yield, p.await, p.deflt = prevYield, prevAwait, prevDeflt
- return
- }
- func (p *Parser) parseVarDecl(tt TokenType, canBeHoisted bool) (varDecl *VarDecl) {
- // assume we're past var, let or const
- varDecl = &VarDecl{
- TokenType: tt,
- Scope: p.scope,
- }
- declType := LexicalDecl
- if tt == VarToken {
- declType = VariableDecl
- if canBeHoisted {
- p.scope.Func.VarDecls = append(p.scope.Func.VarDecls, varDecl)
- }
- }
- for {
- // binding element, var declaration in for-in or for-of can never have a default
- var bindingElement BindingElement
- bindingElement.Binding = p.parseBinding(declType)
- if p.tt == EqToken {
- p.next()
- bindingElement.Default = p.parseExpression(OpAssign)
- } else if _, ok := bindingElement.Binding.(*Var); !ok && (p.in || 0 < len(varDecl.List)) {
- p.fail("var statement", EqToken)
- return
- } else if tt == ConstToken && (p.in || !p.in && p.tt != OfToken && p.tt != InToken) {
- p.fail("const statement", EqToken)
- }
- varDecl.List = append(varDecl.List, bindingElement)
- if p.tt == CommaToken {
- p.next()
- } else {
- break
- }
- }
- return
- }
- func (p *Parser) parseFuncParams(in string) (params Params) {
- // FormalParameters
- if !p.consume(in, OpenParenToken) {
- return
- }
- for p.tt != CloseParenToken && p.tt != ErrorToken {
- if p.tt == EllipsisToken {
- // binding rest element
- p.next()
- params.Rest = p.parseBinding(ArgumentDecl)
- p.consume(in, CloseParenToken)
- return
- }
- params.List = append(params.List, p.parseBindingElement(ArgumentDecl))
- if p.tt != CommaToken {
- break
- }
- p.next()
- }
- if p.tt != CloseParenToken {
- p.fail(in)
- return
- }
- p.next()
- // mark undeclared vars as arguments in `function f(a=b){var b}` where the b's are different vars
- p.scope.MarkFuncArgs()
- return
- }
- func (p *Parser) parseFuncDecl() (funcDecl *FuncDecl) {
- return p.parseFunc(false, false)
- }
- func (p *Parser) parseAsyncFuncDecl() (funcDecl *FuncDecl) {
- return p.parseFunc(true, false)
- }
- func (p *Parser) parseFuncExpr() (funcDecl *FuncDecl) {
- return p.parseFunc(false, true)
- }
- func (p *Parser) parseAsyncFuncExpr() (funcDecl *FuncDecl) {
- return p.parseFunc(true, true)
- }
- func (p *Parser) parseFunc(async, expr bool) (funcDecl *FuncDecl) {
- // assume we're at function
- p.next()
- funcDecl = &FuncDecl{}
- funcDecl.Async = async
- funcDecl.Generator = p.tt == MulToken
- if funcDecl.Generator {
- p.next()
- }
- var ok bool
- var name []byte
- if expr && (IsIdentifier(p.tt) || p.tt == YieldToken || p.tt == AwaitToken) || !expr && p.isIdentifierReference(p.tt) {
- name = p.data
- if !expr {
- funcDecl.Name, ok = p.scope.Declare(FunctionDecl, p.data)
- if !ok {
- p.failMessage("identifier %s has already been declared", string(p.data))
- return
- }
- }
- p.next()
- } else if !expr && !p.deflt {
- p.fail("function declaration", IdentifierToken)
- return
- } else if p.tt != OpenParenToken {
- p.fail("function declaration", IdentifierToken, OpenParenToken)
- return
- }
- parent := p.enterScope(&funcDecl.Body.Scope, true)
- prevAwait, prevYield, prevRetrn := p.await, p.yield, p.retrn
- p.await, p.yield, p.retrn = funcDecl.Async, funcDecl.Generator, true
- if expr && name != nil {
- funcDecl.Name, _ = p.scope.Declare(ExprDecl, name) // cannot fail
- }
- funcDecl.Params = p.parseFuncParams("function declaration")
- prevAllowDirectivePrologue, prevExprLevel := p.allowDirectivePrologue, p.exprLevel
- p.allowDirectivePrologue, p.exprLevel = true, 0
- funcDecl.Body.List = p.parseStmtList("function declaration")
- p.allowDirectivePrologue, p.exprLevel = prevAllowDirectivePrologue, prevExprLevel
- p.await, p.yield, p.retrn = prevAwait, prevYield, prevRetrn
- p.exitScope(parent)
- return
- }
- func (p *Parser) parseClassDecl() (classDecl *ClassDecl) {
- return p.parseAnyClass(false)
- }
- func (p *Parser) parseClassExpr() (classDecl *ClassDecl) {
- return p.parseAnyClass(true)
- }
- func (p *Parser) parseAnyClass(expr bool) (classDecl *ClassDecl) {
- // assume we're at class
- p.next()
- classDecl = &ClassDecl{}
- if IsIdentifier(p.tt) || p.tt == YieldToken || p.tt == AwaitToken {
- if !expr {
- var ok bool
- classDecl.Name, ok = p.scope.Declare(LexicalDecl, p.data)
- if !ok {
- p.failMessage("identifier %s has already been declared", string(p.data))
- return
- }
- } else {
- //classDecl.Name, ok = p.scope.Declare(ExprDecl, p.data) // classes do not register vars
- classDecl.Name = &Var{p.data, nil, 1, ExprDecl}
- }
- p.next()
- } else if !expr && !p.deflt {
- p.fail("class declaration", IdentifierToken)
- return
- }
- if p.tt == ExtendsToken {
- p.next()
- classDecl.Extends = p.parseExpression(OpLHS)
- }
- if !p.consume("class declaration", OpenBraceToken) {
- return
- }
- for {
- if p.tt == ErrorToken {
- p.fail("class declaration")
- return
- } else if p.tt == SemicolonToken {
- p.next()
- continue
- } else if p.tt == CloseBraceToken {
- p.next()
- break
- }
- classDecl.List = append(classDecl.List, p.parseClassElement())
- }
- return
- }
- func (p *Parser) parseClassElement() ClassElement {
- method := &MethodDecl{}
- var data []byte // either static, async, get, or set
- if p.tt == StaticToken {
- method.Static = true
- data = p.data
- p.next()
- if p.tt == OpenBraceToken {
- prevYield, prevAwait, prevRetrn := p.yield, p.await, p.retrn
- p.yield, p.await, p.retrn = false, true, false
- elem := ClassElement{StaticBlock: p.parseBlockStmt("class static block")}
- p.yield, p.await, p.retrn = prevYield, prevAwait, prevRetrn
- return elem
- }
- }
- if p.tt == MulToken {
- method.Generator = true
- p.next()
- } else if p.tt == AsyncToken {
- data = p.data
- p.next()
- if !p.prevLT {
- method.Async = true
- if p.tt == MulToken {
- method.Generator = true
- data = nil
- p.next()
- }
- }
- } else if p.tt == GetToken {
- method.Get = true
- data = p.data
- p.next()
- } else if p.tt == SetToken {
- method.Set = true
- data = p.data
- p.next()
- }
- isField := false
- if data != nil && p.tt == OpenParenToken {
- // (static) method name is: static, async, get, or set
- method.Name.Literal = LiteralExpr{IdentifierToken, data}
- if method.Async || method.Get || method.Set {
- method.Async = false
- method.Get = false
- method.Set = false
- } else {
- method.Static = false
- }
- } else if data != nil && (p.tt == EqToken || p.tt == SemicolonToken || p.tt == CloseBraceToken) {
- // (static) field name is: static, async, get, or set
- method.Name.Literal = LiteralExpr{IdentifierToken, data}
- if !method.Async && !method.Get && !method.Set {
- method.Static = false
- }
- isField = true
- } else {
- if p.tt == PrivateIdentifierToken {
- method.Name.Literal = LiteralExpr{p.tt, p.data}
- p.next()
- } else {
- method.Name = p.parsePropertyName("method or field definition")
- }
- if (data == nil || method.Static) && p.tt != OpenParenToken {
- isField = true
- }
- }
- if isField {
- var init IExpr
- if p.tt == EqToken {
- p.next()
- init = p.parseExpression(OpAssign)
- }
- return ClassElement{Field: Field{Static: method.Static, Name: method.Name, Init: init}}
- }
- parent := p.enterScope(&method.Body.Scope, true)
- prevAwait, prevYield, prevRetrn := p.await, p.yield, p.retrn
- p.await, p.yield, p.retrn = method.Async, method.Generator, true
- method.Params = p.parseFuncParams("method definition")
- prevAllowDirectivePrologue, prevExprLevel := p.allowDirectivePrologue, p.exprLevel
- p.allowDirectivePrologue, p.exprLevel = true, 0
- method.Body.List = p.parseStmtList("method function")
- p.allowDirectivePrologue, p.exprLevel = prevAllowDirectivePrologue, prevExprLevel
- p.await, p.yield, p.retrn = prevAwait, prevYield, prevRetrn
- p.exitScope(parent)
- return ClassElement{Method: method}
- }
- func (p *Parser) parsePropertyName(in string) (propertyName PropertyName) {
- if IsIdentifierName(p.tt) {
- propertyName.Literal = LiteralExpr{IdentifierToken, p.data}
- p.next()
- } else if p.tt == StringToken {
- // reinterpret string as identifier or number if we can, except for empty strings
- if isIdent := AsIdentifierName(p.data[1 : len(p.data)-1]); isIdent {
- propertyName.Literal = LiteralExpr{IdentifierToken, p.data[1 : len(p.data)-1]}
- } else if isNum := AsDecimalLiteral(p.data[1 : len(p.data)-1]); isNum {
- propertyName.Literal = LiteralExpr{DecimalToken, p.data[1 : len(p.data)-1]}
- } else {
- propertyName.Literal = LiteralExpr{p.tt, p.data}
- }
- p.next()
- } else if IsNumeric(p.tt) {
- propertyName.Literal = LiteralExpr{p.tt, p.data}
- p.next()
- } else if p.tt == OpenBracketToken {
- p.next()
- propertyName.Computed = p.parseExpression(OpAssign)
- if !p.consume(in, CloseBracketToken) {
- return
- }
- } else {
- p.fail(in, IdentifierToken, StringToken, NumericToken, OpenBracketToken)
- return
- }
- return
- }
- func (p *Parser) parseBindingElement(decl DeclType) (bindingElement BindingElement) {
- // BindingElement
- bindingElement.Binding = p.parseBinding(decl)
- if p.tt == EqToken {
- p.next()
- bindingElement.Default = p.parseExpression(OpAssign)
- }
- return
- }
- func (p *Parser) parseBinding(decl DeclType) (binding IBinding) {
- // BindingIdentifier, BindingPattern
- if p.isIdentifierReference(p.tt) {
- var ok bool
- binding, ok = p.scope.Declare(decl, p.data)
- if !ok {
- p.failMessage("identifier %s has already been declared", string(p.data))
- return
- }
- p.next()
- } else if p.tt == OpenBracketToken {
- p.next()
- array := BindingArray{}
- if p.tt == CommaToken {
- array.List = append(array.List, BindingElement{})
- }
- last := 0
- for p.tt != CloseBracketToken {
- // elision
- for p.tt == CommaToken {
- p.next()
- if p.tt == CommaToken {
- array.List = append(array.List, BindingElement{})
- }
- }
- // binding rest element
- if p.tt == EllipsisToken {
- p.next()
- array.Rest = p.parseBinding(decl)
- if p.tt != CloseBracketToken {
- p.fail("array binding pattern", CloseBracketToken)
- return
- }
- break
- } else if p.tt == CloseBracketToken {
- array.List = array.List[:last]
- break
- }
- array.List = append(array.List, p.parseBindingElement(decl))
- last = len(array.List)
- if p.tt != CommaToken && p.tt != CloseBracketToken {
- p.fail("array binding pattern", CommaToken, CloseBracketToken)
- return
- }
- }
- p.next() // always CloseBracketToken
- binding = &array
- } else if p.tt == OpenBraceToken {
- p.next()
- object := BindingObject{}
- for p.tt != CloseBraceToken {
- // binding rest property
- if p.tt == EllipsisToken {
- p.next()
- if !p.isIdentifierReference(p.tt) {
- p.fail("object binding pattern", IdentifierToken)
- return
- }
- var ok bool
- object.Rest, ok = p.scope.Declare(decl, p.data)
- if !ok {
- p.failMessage("identifier %s has already been declared", string(p.data))
- return
- }
- p.next()
- if p.tt != CloseBraceToken {
- p.fail("object binding pattern", CloseBraceToken)
- return
- }
- break
- }
- item := BindingObjectItem{}
- if p.isIdentifierReference(p.tt) {
- name := p.data
- item.Key = &PropertyName{LiteralExpr{IdentifierToken, p.data}, nil}
- p.next()
- if p.tt == ColonToken {
- // property name + : + binding element
- p.next()
- item.Value = p.parseBindingElement(decl)
- } else {
- // single name binding
- var ok bool
- item.Key.Literal.Data = parse.Copy(item.Key.Literal.Data) // copy so that renaming doesn't rename the key
- item.Value.Binding, ok = p.scope.Declare(decl, name)
- if !ok {
- p.failMessage("identifier %s has already been declared", string(name))
- return
- }
- if p.tt == EqToken {
- p.next()
- item.Value.Default = p.parseExpression(OpAssign)
- }
- }
- } else {
- propertyName := p.parsePropertyName("object binding pattern")
- item.Key = &propertyName
- if !p.consume("object binding pattern", ColonToken) {
- return
- }
- item.Value = p.parseBindingElement(decl)
- }
- object.List = append(object.List, item)
- if p.tt == CommaToken {
- p.next()
- } else if p.tt != CloseBraceToken {
- p.fail("object binding pattern", CommaToken, CloseBraceToken)
- return
- }
- }
- p.next() // always CloseBracketToken
- binding = &object
- } else {
- p.fail("binding")
- return
- }
- return
- }
- func (p *Parser) parseArrayLiteral() (array ArrayExpr) {
- // assume we're on [
- p.next()
- prevComma := true
- for {
- if p.tt == ErrorToken {
- p.fail("expression")
- return
- } else if p.tt == CloseBracketToken {
- p.next()
- break
- } else if p.tt == CommaToken {
- if prevComma {
- array.List = append(array.List, Element{})
- }
- prevComma = true
- p.next()
- } else {
- spread := p.tt == EllipsisToken
- if spread {
- p.next()
- }
- array.List = append(array.List, Element{p.parseAssignExprOrParam(), spread})
- prevComma = false
- if spread && p.tt != CloseBracketToken {
- p.assumeArrowFunc = false
- }
- }
- }
- return
- }
- func (p *Parser) parseObjectLiteral() (object ObjectExpr) {
- // assume we're on {
- p.next()
- for {
- if p.tt == ErrorToken {
- p.fail("object literal", CloseBraceToken)
- return
- } else if p.tt == CloseBraceToken {
- p.next()
- break
- }
- property := Property{}
- if p.tt == EllipsisToken {
- p.next()
- property.Spread = true
- property.Value = p.parseAssignExprOrParam()
- if _, isIdent := property.Value.(*Var); !isIdent || p.tt != CloseBraceToken {
- p.assumeArrowFunc = false
- }
- } else {
- // try to parse as MethodDefinition, otherwise fall back to PropertyName:AssignExpr or IdentifierReference
- var data []byte
- method := MethodDecl{}
- if p.tt == MulToken {
- p.next()
- method.Generator = true
- } else if p.tt == AsyncToken {
- data = p.data
- p.next()
- if !p.prevLT {
- method.Async = true
- if p.tt == MulToken {
- p.next()
- method.Generator = true
- data = nil
- }
- } else {
- method.Name.Literal = LiteralExpr{IdentifierToken, data}
- data = nil
- }
- } else if p.tt == GetToken {
- data = p.data
- p.next()
- method.Get = true
- } else if p.tt == SetToken {
- data = p.data
- p.next()
- method.Set = true
- }
- // PropertyName
- if data != nil && !method.Generator && (p.tt == EqToken || p.tt == CommaToken || p.tt == CloseBraceToken || p.tt == ColonToken || p.tt == OpenParenToken) {
- method.Name.Literal = LiteralExpr{IdentifierToken, data}
- method.Async = false
- method.Get = false
- method.Set = false
- } else if !method.Name.IsSet() { // did not parse async [LT]
- method.Name = p.parsePropertyName("object literal")
- if !method.Name.IsSet() {
- return
- }
- }
- if p.tt == OpenParenToken {
- // MethodDefinition
- parent := p.enterScope(&method.Body.Scope, true)
- prevAwait, prevYield, prevRetrn := p.await, p.yield, p.retrn
- p.await, p.yield, p.retrn = method.Async, method.Generator, true
- method.Params = p.parseFuncParams("method definition")
- method.Body.List = p.parseStmtList("method definition")
- p.await, p.yield, p.retrn = prevAwait, prevYield, prevRetrn
- p.exitScope(parent)
- property.Value = &method
- p.assumeArrowFunc = false
- } else if p.tt == ColonToken {
- // PropertyName : AssignmentExpression
- p.next()
- property.Name = &method.Name
- property.Value = p.parseAssignExprOrParam()
- } else if method.Name.IsComputed() || !p.isIdentifierReference(method.Name.Literal.TokenType) {
- p.fail("object literal", ColonToken, OpenParenToken)
- return
- } else {
- // IdentifierReference (= AssignmentExpression)?
- name := method.Name.Literal.Data
- method.Name.Literal.Data = parse.Copy(method.Name.Literal.Data) // copy so that renaming doesn't rename the key
- property.Name = &method.Name // set key explicitly so after renaming the original is still known
- if p.assumeArrowFunc {
- var ok bool
- property.Value, ok = p.scope.Declare(ArgumentDecl, name)
- if !ok {
- property.Value = p.scope.Use(name)
- p.assumeArrowFunc = false
- }
- } else {
- property.Value = p.scope.Use(name)
- }
- if p.tt == EqToken {
- p.next()
- prevAssumeArrowFunc := p.assumeArrowFunc
- p.assumeArrowFunc = false
- property.Init = p.parseExpression(OpAssign)
- p.assumeArrowFunc = prevAssumeArrowFunc
- }
- }
- }
- object.List = append(object.List, property)
- if p.tt == CommaToken {
- p.next()
- } else if p.tt != CloseBraceToken {
- p.fail("object literal")
- return
- }
- }
- return
- }
- func (p *Parser) parseTemplateLiteral(precLeft OpPrec) (template TemplateExpr) {
- // assume we're on 'Template' or 'TemplateStart'
- template.Prec = OpMember
- if precLeft < OpMember {
- template.Prec = OpCall
- }
- for p.tt == TemplateStartToken || p.tt == TemplateMiddleToken {
- tpl := p.data
- p.next()
- template.List = append(template.List, TemplatePart{tpl, p.parseExpression(OpExpr)})
- }
- if p.tt != TemplateToken && p.tt != TemplateEndToken {
- p.fail("template literal", TemplateToken)
- return
- }
- template.Tail = p.data
- p.next() // TemplateEndToken
- return
- }
- func (p *Parser) parseArguments() (args Args) {
- // assume we're on (
- p.next()
- args.List = make([]Arg, 0, 4)
- for p.tt != CloseParenToken && p.tt != ErrorToken {
- rest := p.tt == EllipsisToken
- if rest {
- p.next()
- }
- args.List = append(args.List, Arg{
- Value: p.parseExpression(OpAssign),
- Rest: rest,
- })
- if p.tt != CloseParenToken {
- if p.tt != CommaToken {
- p.fail("arguments", CommaToken, CloseParenToken)
- return
- } else {
- p.next() // CommaToken
- }
- }
- }
- p.consume("arguments", CloseParenToken)
- return
- }
- func (p *Parser) parseAsyncArrowFunc() (arrowFunc *ArrowFunc) {
- // expect we're at Identifier or Yield or (
- arrowFunc = &ArrowFunc{}
- parent := p.enterScope(&arrowFunc.Body.Scope, true)
- prevAwait, prevYield := p.await, p.yield
- p.await, p.yield = true, false
- if IsIdentifier(p.tt) || !prevYield && p.tt == YieldToken {
- ref, _ := p.scope.Declare(ArgumentDecl, p.data) // cannot fail
- p.next()
- arrowFunc.Params.List = []BindingElement{{Binding: ref}}
- } else {
- arrowFunc.Params = p.parseFuncParams("arrow function")
- // CallExpression of 'async(params)' already handled
- }
- arrowFunc.Async = true
- arrowFunc.Body.List = p.parseArrowFuncBody()
- p.await, p.yield = prevAwait, prevYield
- p.exitScope(parent)
- return
- }
- func (p *Parser) parseIdentifierArrowFunc(v *Var) (arrowFunc *ArrowFunc) {
- // expect we're at =>
- arrowFunc = &ArrowFunc{}
- parent := p.enterScope(&arrowFunc.Body.Scope, true)
- prevAwait, prevYield := p.await, p.yield
- p.await, p.yield = false, false
- if 1 < v.Uses {
- v.Uses--
- v, _ = p.scope.Declare(ArgumentDecl, parse.Copy(v.Data)) // cannot fail
- } else {
- // if v.Uses==1 it must be undeclared and be the last added
- p.scope.Parent.Undeclared = p.scope.Parent.Undeclared[:len(p.scope.Parent.Undeclared)-1]
- v.Decl = ArgumentDecl
- p.scope.Declared = append(p.scope.Declared, v)
- }
- arrowFunc.Params.List = []BindingElement{{v, nil}}
- arrowFunc.Body.List = p.parseArrowFuncBody()
- p.await, p.yield = prevAwait, prevYield
- p.exitScope(parent)
- return
- }
- func (p *Parser) parseArrowFuncBody() (list []IStmt) {
- // expect we're at arrow
- if p.tt != ArrowToken {
- p.fail("arrow function", ArrowToken)
- return
- } else if p.prevLT {
- p.fail("expression")
- return
- }
- p.next()
- // mark undeclared vars as arguments in `function f(a=b){var b}` where the b's are different vars
- p.scope.MarkFuncArgs()
- if p.tt == OpenBraceToken {
- prevIn, prevRetrn := p.in, p.retrn
- p.in, p.retrn = true, true
- prevAllowDirectivePrologue, prevExprLevel := p.allowDirectivePrologue, p.exprLevel
- p.allowDirectivePrologue, p.exprLevel = true, 0
- list = p.parseStmtList("arrow function")
- p.allowDirectivePrologue, p.exprLevel = prevAllowDirectivePrologue, prevExprLevel
- p.in, p.retrn = prevIn, prevRetrn
- } else {
- list = []IStmt{&ReturnStmt{p.parseExpression(OpAssign)}}
- }
- return
- }
- func (p *Parser) parseIdentifierExpression(prec OpPrec, ident []byte) IExpr {
- var left IExpr
- left = p.scope.Use(ident)
- return p.parseExpressionSuffix(left, prec, OpPrimary)
- }
- func (p *Parser) parseAsyncExpression(prec OpPrec, async []byte) IExpr {
- // IdentifierReference, AsyncFunctionExpression, AsyncGeneratorExpression
- // CoverCallExpressionAndAsyncArrowHead, AsyncArrowFunction
- // assume we're at a token after async
- var left IExpr
- precLeft := OpPrimary
- if !p.prevLT && p.tt == FunctionToken {
- // primary expression
- left = p.parseAsyncFuncExpr()
- } else if !p.prevLT && prec <= OpAssign && (p.tt == OpenParenToken || IsIdentifier(p.tt) || p.tt == YieldToken || p.tt == AwaitToken) {
- // async arrow function expression or call expression
- if p.tt == AwaitToken || p.yield && p.tt == YieldToken {
- p.fail("arrow function")
- return nil
- } else if p.tt == OpenParenToken {
- return p.parseParenthesizedExpression(prec, async)
- }
- left = p.parseAsyncArrowFunc()
- precLeft = OpAssign
- } else {
- left = p.scope.Use(async)
- }
- // can be async(args), async => ..., or e.g. async + ...
- return p.parseExpressionSuffix(left, prec, precLeft)
- }
- // parseExpression parses an expression that has a precedence of prec or higher.
- func (p *Parser) parseExpression(prec OpPrec) IExpr {
- p.exprLevel++
- if 1000 < p.exprLevel {
- p.failMessage("too many nested expressions")
- return nil
- }
- // reparse input if we have / or /= as the beginning of a new expression, this should be a regular expression!
- if p.tt == DivToken || p.tt == DivEqToken {
- p.tt, p.data = p.l.RegExp()
- if p.tt == ErrorToken {
- p.fail("regular expression")
- return nil
- }
- }
- var left IExpr
- precLeft := OpPrimary
- if IsIdentifier(p.tt) && p.tt != AsyncToken {
- left = p.scope.Use(p.data)
- p.next()
- suffix := p.parseExpressionSuffix(left, prec, precLeft)
- p.exprLevel--
- return suffix
- } else if IsNumeric(p.tt) {
- left = &LiteralExpr{p.tt, p.data}
- p.next()
- suffix := p.parseExpressionSuffix(left, prec, precLeft)
- p.exprLevel--
- return suffix
- }
- switch tt := p.tt; tt {
- case StringToken, ThisToken, NullToken, TrueToken, FalseToken, RegExpToken:
- left = &LiteralExpr{p.tt, p.data}
- p.next()
- case OpenBracketToken:
- prevIn := p.in
- p.in = true
- array := p.parseArrayLiteral()
- p.in = prevIn
- left = &array
- case OpenBraceToken:
- prevIn := p.in
- p.in = true
- object := p.parseObjectLiteral()
- p.in = prevIn
- left = &object
- case OpenParenToken:
- // parenthesized expression or arrow parameter list
- if OpAssign < prec {
- // must be a parenthesized expression
- p.next()
- prevIn := p.in
- p.in = true
- left = &GroupExpr{p.parseExpression(OpExpr)}
- p.in = prevIn
- if !p.consume("expression", CloseParenToken) {
- return nil
- }
- break
- }
- suffix := p.parseParenthesizedExpression(prec, nil)
- p.exprLevel--
- return suffix
- case NotToken, BitNotToken, TypeofToken, VoidToken, DeleteToken:
- if OpUnary < prec {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &UnaryExpr{tt, p.parseExpression(OpUnary)}
- precLeft = OpUnary
- case AddToken:
- if OpUnary < prec {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &UnaryExpr{PosToken, p.parseExpression(OpUnary)}
- precLeft = OpUnary
- case SubToken:
- if OpUnary < prec {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &UnaryExpr{NegToken, p.parseExpression(OpUnary)}
- precLeft = OpUnary
- case IncrToken:
- if OpUpdate < prec {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &UnaryExpr{PreIncrToken, p.parseExpression(OpUnary)}
- precLeft = OpUnary
- case DecrToken:
- if OpUpdate < prec {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &UnaryExpr{PreDecrToken, p.parseExpression(OpUnary)}
- precLeft = OpUnary
- case AwaitToken:
- // either accepted as IdentifierReference or as AwaitExpression
- if p.await && prec <= OpUnary {
- p.next()
- left = &UnaryExpr{tt, p.parseExpression(OpUnary)}
- precLeft = OpUnary
- } else if p.await {
- p.fail("expression")
- return nil
- } else {
- left = p.scope.Use(p.data)
- p.next()
- }
- case NewToken:
- p.next()
- if p.tt == DotToken {
- p.next()
- if !p.consume("new.target expression", TargetToken) {
- return nil
- }
- left = &NewTargetExpr{}
- precLeft = OpMember
- } else {
- newExpr := &NewExpr{p.parseExpression(OpNew), nil}
- if p.tt == OpenParenToken {
- args := p.parseArguments()
- if len(args.List) != 0 {
- newExpr.Args = &args
- }
- precLeft = OpMember
- } else {
- precLeft = OpNew
- }
- left = newExpr
- }
- case ImportToken:
- // OpMember < prec does never happen
- left = &LiteralExpr{p.tt, p.data}
- p.next()
- if p.tt == DotToken {
- p.next()
- if !p.consume("import.meta expression", MetaToken) {
- return nil
- }
- left = &ImportMetaExpr{}
- precLeft = OpMember
- } else if p.tt != OpenParenToken {
- p.fail("import expression", OpenParenToken)
- return nil
- } else if OpCall < prec {
- p.fail("expression")
- return nil
- } else {
- precLeft = OpCall
- }
- case SuperToken:
- // OpMember < prec does never happen
- left = &LiteralExpr{p.tt, p.data}
- p.next()
- if OpCall < prec && p.tt != DotToken && p.tt != OpenBracketToken {
- p.fail("super expression", OpenBracketToken, DotToken)
- return nil
- } else if p.tt != DotToken && p.tt != OpenBracketToken && p.tt != OpenParenToken {
- p.fail("super expression", OpenBracketToken, OpenParenToken, DotToken)
- return nil
- }
- if OpCall < prec {
- precLeft = OpMember
- } else {
- precLeft = OpCall
- }
- case YieldToken:
- // either accepted as IdentifierReference or as YieldExpression
- if p.yield && prec <= OpAssign {
- // YieldExpression
- p.next()
- yieldExpr := YieldExpr{}
- if !p.prevLT {
- yieldExpr.Generator = p.tt == MulToken
- if yieldExpr.Generator {
- p.next()
- yieldExpr.X = p.parseExpression(OpAssign)
- } else if p.tt != CloseBraceToken && p.tt != CloseBracketToken && p.tt != CloseParenToken && p.tt != ColonToken && p.tt != CommaToken && p.tt != SemicolonToken {
- yieldExpr.X = p.parseExpression(OpAssign)
- }
- }
- left = &yieldExpr
- precLeft = OpAssign
- } else if p.yield {
- p.fail("expression")
- return nil
- } else {
- left = p.scope.Use(p.data)
- p.next()
- }
- case AsyncToken:
- async := p.data
- p.next()
- prevIn := p.in
- p.in = true
- left = p.parseAsyncExpression(prec, async)
- p.in = prevIn
- case ClassToken:
- prevIn := p.in
- p.in = true
- left = p.parseClassExpr()
- p.in = prevIn
- case FunctionToken:
- prevIn := p.in
- p.in = true
- left = p.parseFuncExpr()
- p.in = prevIn
- case TemplateToken, TemplateStartToken:
- prevIn := p.in
- p.in = true
- template := p.parseTemplateLiteral(precLeft)
- left = &template
- p.in = prevIn
- case PrivateIdentifierToken:
- if OpCompare < prec || !p.in {
- p.fail("expression")
- return nil
- }
- left = &LiteralExpr{p.tt, p.data}
- p.next()
- if p.tt != InToken {
- p.fail("relational expression", InToken)
- return nil
- }
- default:
- p.fail("expression")
- return nil
- }
- suffix := p.parseExpressionSuffix(left, prec, precLeft)
- p.exprLevel--
- return suffix
- }
- func (p *Parser) parseExpressionSuffix(left IExpr, prec, precLeft OpPrec) IExpr {
- for i := 0; ; i++ {
- if 1000 < p.exprLevel+i {
- p.failMessage("too many nested expressions")
- return nil
- }
- switch tt := p.tt; tt {
- case EqToken, MulEqToken, DivEqToken, ModEqToken, ExpEqToken, AddEqToken, SubEqToken, LtLtEqToken, GtGtEqToken, GtGtGtEqToken, BitAndEqToken, BitXorEqToken, BitOrEqToken, AndEqToken, OrEqToken, NullishEqToken:
- if OpAssign < prec {
- return left
- } else if precLeft < OpLHS {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &BinaryExpr{tt, left, p.parseExpression(OpAssign)}
- precLeft = OpAssign
- case LtToken, LtEqToken, GtToken, GtEqToken, InToken, InstanceofToken:
- if OpCompare < prec || !p.in && tt == InToken {
- return left
- } else if precLeft < OpCompare {
- // can only fail after a yield or arrow function expression
- p.fail("expression")
- return nil
- }
- p.next()
- left = &BinaryExpr{tt, left, p.parseExpression(OpShift)}
- precLeft = OpCompare
- case EqEqToken, NotEqToken, EqEqEqToken, NotEqEqToken:
- if OpEquals < prec {
- return left
- } else if precLeft < OpEquals {
- // can only fail after a yield or arrow function expression
- p.fail("expression")
- return nil
- }
- p.next()
- left = &BinaryExpr{tt, left, p.parseExpression(OpCompare)}
- precLeft = OpEquals
- case AndToken:
- if OpAnd < prec {
- return left
- } else if precLeft < OpAnd {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &BinaryExpr{tt, left, p.parseExpression(OpBitOr)}
- precLeft = OpAnd
- case OrToken:
- if OpOr < prec {
- return left
- } else if precLeft < OpOr {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &BinaryExpr{tt, left, p.parseExpression(OpAnd)}
- precLeft = OpOr
- case NullishToken:
- if OpCoalesce < prec {
- return left
- } else if precLeft < OpBitOr && precLeft != OpCoalesce {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &BinaryExpr{tt, left, p.parseExpression(OpBitOr)}
- precLeft = OpCoalesce
- case DotToken:
- // OpMember < prec does never happen
- if precLeft < OpCall {
- p.fail("expression")
- return nil
- }
- p.next()
- if !IsIdentifierName(p.tt) && p.tt != PrivateIdentifierToken {
- p.fail("dot expression", IdentifierToken)
- return nil
- }
- exprPrec := OpMember
- if precLeft < OpMember {
- exprPrec = OpCall
- }
- if p.tt != PrivateIdentifierToken {
- p.tt = IdentifierToken
- }
- left = &DotExpr{left, LiteralExpr{p.tt, p.data}, exprPrec, false}
- p.next()
- if precLeft < OpMember {
- precLeft = OpCall
- } else {
- precLeft = OpMember
- }
- case OpenBracketToken:
- // OpMember < prec does never happen
- if precLeft < OpCall {
- p.fail("expression")
- return nil
- }
- p.next()
- exprPrec := OpMember
- if precLeft < OpMember {
- exprPrec = OpCall
- }
- prevIn := p.in
- p.in = true
- left = &IndexExpr{left, p.parseExpression(OpExpr), exprPrec, false}
- p.in = prevIn
- if !p.consume("index expression", CloseBracketToken) {
- return nil
- }
- if precLeft < OpMember {
- precLeft = OpCall
- } else {
- precLeft = OpMember
- }
- case OpenParenToken:
- if OpCall < prec {
- return left
- } else if precLeft < OpCall {
- p.fail("expression")
- return nil
- }
- prevIn := p.in
- p.in = true
- left = &CallExpr{left, p.parseArguments(), false}
- precLeft = OpCall
- p.in = prevIn
- case TemplateToken, TemplateStartToken:
- // OpMember < prec does never happen
- if precLeft < OpCall {
- p.fail("expression")
- return nil
- }
- prevIn := p.in
- p.in = true
- template := p.parseTemplateLiteral(precLeft)
- template.Tag = left
- left = &template
- if precLeft < OpMember {
- precLeft = OpCall
- } else {
- precLeft = OpMember
- }
- p.in = prevIn
- case OptChainToken:
- if OpCall < prec {
- return left
- }
- p.next()
- if p.tt == OpenParenToken {
- left = &CallExpr{left, p.parseArguments(), true}
- } else if p.tt == OpenBracketToken {
- p.next()
- left = &IndexExpr{left, p.parseExpression(OpExpr), OpCall, true}
- if !p.consume("optional chaining expression", CloseBracketToken) {
- return nil
- }
- } else if p.tt == TemplateToken || p.tt == TemplateStartToken {
- template := p.parseTemplateLiteral(precLeft)
- template.Prec = OpCall
- template.Tag = left
- template.Optional = true
- left = &template
- } else if IsIdentifierName(p.tt) {
- left = &DotExpr{left, LiteralExpr{IdentifierToken, p.data}, OpCall, true}
- p.next()
- } else if p.tt == PrivateIdentifierToken {
- left = &DotExpr{left, LiteralExpr{p.tt, p.data}, OpCall, true}
- p.next()
- } else {
- p.fail("optional chaining expression", IdentifierToken, OpenParenToken, OpenBracketToken, TemplateToken)
- return nil
- }
- precLeft = OpCall
- case IncrToken:
- if p.prevLT || OpUpdate < prec {
- return left
- } else if precLeft < OpLHS {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &UnaryExpr{PostIncrToken, left}
- precLeft = OpUpdate
- case DecrToken:
- if p.prevLT || OpUpdate < prec {
- return left
- } else if precLeft < OpLHS {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &UnaryExpr{PostDecrToken, left}
- precLeft = OpUpdate
- case ExpToken:
- if OpExp < prec {
- return left
- } else if precLeft < OpUpdate {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &BinaryExpr{tt, left, p.parseExpression(OpExp)}
- precLeft = OpExp
- case MulToken, DivToken, ModToken:
- if OpMul < prec {
- return left
- } else if precLeft < OpMul {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &BinaryExpr{tt, left, p.parseExpression(OpExp)}
- precLeft = OpMul
- case AddToken, SubToken:
- if OpAdd < prec {
- return left
- } else if precLeft < OpAdd {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &BinaryExpr{tt, left, p.parseExpression(OpMul)}
- precLeft = OpAdd
- case LtLtToken, GtGtToken, GtGtGtToken:
- if OpShift < prec {
- return left
- } else if precLeft < OpShift {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &BinaryExpr{tt, left, p.parseExpression(OpAdd)}
- precLeft = OpShift
- case BitAndToken:
- if OpBitAnd < prec {
- return left
- } else if precLeft < OpBitAnd {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &BinaryExpr{tt, left, p.parseExpression(OpEquals)}
- precLeft = OpBitAnd
- case BitXorToken:
- if OpBitXor < prec {
- return left
- } else if precLeft < OpBitXor {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &BinaryExpr{tt, left, p.parseExpression(OpBitAnd)}
- precLeft = OpBitXor
- case BitOrToken:
- if OpBitOr < prec {
- return left
- } else if precLeft < OpBitOr {
- p.fail("expression")
- return nil
- }
- p.next()
- left = &BinaryExpr{tt, left, p.parseExpression(OpBitXor)}
- precLeft = OpBitOr
- case QuestionToken:
- if OpAssign < prec {
- return left
- } else if precLeft < OpCoalesce {
- p.fail("expression")
- return nil
- }
- p.next()
- prevIn := p.in
- p.in = true
- ifExpr := p.parseExpression(OpAssign)
- p.in = prevIn
- if !p.consume("conditional expression", ColonToken) {
- return nil
- }
- elseExpr := p.parseExpression(OpAssign)
- left = &CondExpr{left, ifExpr, elseExpr}
- precLeft = OpAssign
- case CommaToken:
- if OpExpr < prec {
- return left
- }
- p.next()
- if commaExpr, ok := left.(*CommaExpr); ok {
- commaExpr.List = append(commaExpr.List, p.parseExpression(OpAssign))
- i-- // adjust expression nesting limit
- } else {
- left = &CommaExpr{[]IExpr{left, p.parseExpression(OpAssign)}}
- }
- precLeft = OpExpr
- case ArrowToken:
- // handle identifier => ..., where identifier could also be yield or await
- if OpAssign < prec {
- return left
- } else if precLeft < OpPrimary || p.prevLT {
- p.fail("expression")
- return nil
- }
- v, ok := left.(*Var)
- if !ok {
- p.fail("expression")
- return nil
- }
- left = p.parseIdentifierArrowFunc(v)
- precLeft = OpAssign
- default:
- return left
- }
- }
- }
- func (p *Parser) parseAssignExprOrParam() IExpr {
- // this could be a BindingElement or an AssignmentExpression. Here we handle BindingIdentifier with a possible Initializer, BindingPattern will be handled by parseArrayLiteral or parseObjectLiteral
- if p.assumeArrowFunc && p.isIdentifierReference(p.tt) {
- tt := p.tt
- data := p.data
- p.next()
- if p.tt == EqToken || p.tt == CommaToken || p.tt == CloseParenToken || p.tt == CloseBraceToken || p.tt == CloseBracketToken {
- var ok bool
- var left IExpr
- left, ok = p.scope.Declare(ArgumentDecl, data)
- if ok {
- p.assumeArrowFunc = false
- left = p.parseExpressionSuffix(left, OpAssign, OpPrimary)
- p.assumeArrowFunc = true
- return left
- }
- }
- p.assumeArrowFunc = false
- if tt == AsyncToken {
- return p.parseAsyncExpression(OpAssign, data)
- }
- return p.parseIdentifierExpression(OpAssign, data)
- } else if p.tt != OpenBracketToken && p.tt != OpenBraceToken {
- p.assumeArrowFunc = false
- }
- return p.parseExpression(OpAssign)
- }
- func (p *Parser) parseParenthesizedExpression(prec OpPrec, async []byte) IExpr {
- // parse ArrowFunc, AsyncArrowFunc, AsyncCallExpr, ParenthesizedExpr
- var left IExpr
- precLeft := OpPrimary
- // expect to be at (
- p.next()
- isAsync := async != nil // prevLT is false before open parenthesis
- arrowFunc := &ArrowFunc{}
- parent := p.enterScope(&arrowFunc.Body.Scope, true)
- prevAssumeArrowFunc, prevIn := p.assumeArrowFunc, p.in
- p.assumeArrowFunc, p.in = true, true
- // parse an Arguments expression but assume we might be parsing an (async) arrow function or ParenthesisedExpression. If this is really an arrow function, parsing as an Arguments expression cannot fail as AssignmentExpression, ArrayLiteral, and ObjectLiteral are supersets of SingleNameBinding, ArrayBindingPattern, and ObjectBindingPattern respectively. Any identifier that would be a BindingIdentifier in case of an arrow function, will be added as such to the scope. If finally this is not an arrow function, we will demote those variables as undeclared and merge them with the parent scope.
- rests := 0
- var args Args
- for p.tt != CloseParenToken && p.tt != ErrorToken {
- if 0 < len(args.List) && args.List[len(args.List)-1].Rest {
- // only last parameter can have ellipsis
- p.assumeArrowFunc = false
- if !isAsync {
- p.fail("arrow function", CloseParenToken)
- }
- }
- rest := p.tt == EllipsisToken
- if rest {
- p.next()
- rests++
- }
- args.List = append(args.List, Arg{p.parseAssignExprOrParam(), rest})
- if p.tt != CommaToken {
- break
- }
- p.next()
- }
- if p.tt != CloseParenToken {
- p.fail("expression")
- return nil
- }
- p.next()
- isArrowFunc := !p.prevLT && p.tt == ArrowToken && p.assumeArrowFunc
- hasLastRest := 0 < rests && p.assumeArrowFunc
- p.assumeArrowFunc, p.in = prevAssumeArrowFunc, prevIn
- if isArrowFunc {
- prevAwait, prevYield := p.await, p.yield
- p.await, p.yield = isAsync, false
- // arrow function
- arrowFunc.Async = isAsync
- arrowFunc.Params = Params{List: make([]BindingElement, 0, len(args.List)-rests)}
- for _, arg := range args.List {
- if arg.Rest {
- arrowFunc.Params.Rest = p.exprToBinding(arg.Value)
- } else {
- arrowFunc.Params.List = append(arrowFunc.Params.List, p.exprToBindingElement(arg.Value)) // can not fail when assumArrowFunc is set
- }
- }
- arrowFunc.Body.List = p.parseArrowFuncBody()
- p.await, p.yield = prevAwait, prevYield
- p.exitScope(parent)
- left = arrowFunc
- precLeft = OpAssign
- } else if !isAsync && (len(args.List) == 0 || hasLastRest) {
- p.fail("arrow function", ArrowToken)
- return nil
- } else if isAsync && OpCall < prec || !isAsync && 0 < rests {
- p.fail("expression")
- return nil
- } else {
- // for any nested FuncExpr/ArrowFunc scope, Parent will point to the temporary scope created in case this was an arrow function instead of a parenthesized expression. This is not a problem as Parent is only used for defining new variables, and we already parsed all the nested scopes so that Parent (not Func) are not relevant anymore. Anyways, the Parent will just point to an empty scope, whose Parent/Func will point to valid scopes. This should not be a big deal.
- // Here we move all declared ArgumentDecls (in case of an arrow function) to its parent scope as undeclared variables (identifiers used in a parenthesized expression).
- p.exitScope(parent)
- arrowFunc.Body.Scope.UndeclareScope()
- if isAsync {
- // call expression
- left = p.scope.Use(async)
- left = &CallExpr{left, args, false}
- precLeft = OpCall
- } else {
- // parenthesized expression
- if 1 < len(args.List) {
- commaExpr := &CommaExpr{}
- for _, arg := range args.List {
- commaExpr.List = append(commaExpr.List, arg.Value)
- }
- left = &GroupExpr{commaExpr}
- } else {
- left = &GroupExpr{args.List[0].Value}
- }
- }
- }
- return p.parseExpressionSuffix(left, prec, precLeft)
- }
- // exprToBindingElement and exprToBinding convert a CoverParenthesizedExpressionAndArrowParameterList into FormalParameters.
- // Any unbound variables of the parameters (Initializer, ComputedPropertyName) are kept in the parent scope
- func (p *Parser) exprToBindingElement(expr IExpr) (bindingElement BindingElement) {
- if assign, ok := expr.(*BinaryExpr); ok && assign.Op == EqToken {
- bindingElement.Binding = p.exprToBinding(assign.X)
- bindingElement.Default = assign.Y
- } else {
- bindingElement.Binding = p.exprToBinding(expr)
- }
- return
- }
- func (p *Parser) exprToBinding(expr IExpr) (binding IBinding) {
- if expr == nil {
- // no-op
- } else if v, ok := expr.(*Var); ok {
- binding = v
- } else if array, ok := expr.(*ArrayExpr); ok {
- bindingArray := BindingArray{}
- for _, item := range array.List {
- if item.Spread {
- // can only BindingIdentifier or BindingPattern
- bindingArray.Rest = p.exprToBinding(item.Value)
- break
- }
- var bindingElement BindingElement
- bindingElement = p.exprToBindingElement(item.Value)
- bindingArray.List = append(bindingArray.List, bindingElement)
- }
- binding = &bindingArray
- } else if object, ok := expr.(*ObjectExpr); ok {
- bindingObject := BindingObject{}
- for _, item := range object.List {
- if item.Spread {
- // can only be BindingIdentifier
- bindingObject.Rest = item.Value.(*Var)
- break
- }
- bindingElement := p.exprToBindingElement(item.Value)
- if v, ok := item.Value.(*Var); item.Name == nil || (ok && item.Name.IsIdent(v.Data)) {
- // IdentifierReference : Initializer
- bindingElement.Default = item.Init
- }
- bindingObject.List = append(bindingObject.List, BindingObjectItem{Key: item.Name, Value: bindingElement})
- }
- binding = &bindingObject
- } else {
- p.failMessage("invalid parameters in arrow function")
- }
- return
- }
- func (p *Parser) isIdentifierReference(tt TokenType) bool {
- return IsIdentifier(tt) || !p.yield && tt == YieldToken || !p.await && tt == AwaitToken
- }
|