Skip to content

Commit

Permalink
JS: register directive prologues (use strict) as a separate statement
Browse files Browse the repository at this point in the history
  • Loading branch information
tdewolff committed Feb 9, 2021
1 parent 2cc8037 commit e167502
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 25 deletions.
48 changes: 29 additions & 19 deletions js/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -649,25 +649,35 @@ func (n ExportStmt) String() string {
return s + ")"
}

func (n BlockStmt) stmtNode() {}
func (n EmptyStmt) stmtNode() {}
func (n ExprStmt) stmtNode() {}
func (n IfStmt) stmtNode() {}
func (n DoWhileStmt) stmtNode() {}
func (n WhileStmt) stmtNode() {}
func (n ForStmt) stmtNode() {}
func (n ForInStmt) stmtNode() {}
func (n ForOfStmt) stmtNode() {}
func (n SwitchStmt) stmtNode() {}
func (n BranchStmt) stmtNode() {}
func (n ReturnStmt) stmtNode() {}
func (n WithStmt) stmtNode() {}
func (n LabelledStmt) stmtNode() {}
func (n ThrowStmt) stmtNode() {}
func (n TryStmt) stmtNode() {}
func (n DebuggerStmt) stmtNode() {}
func (n ImportStmt) stmtNode() {}
func (n ExportStmt) stmtNode() {}
// DirectivePrologueStmt is a string literal at the beginning of a function or module (usually "use strict").
type DirectivePrologueStmt struct {
Value []byte
}

func (n DirectivePrologueStmt) String() string {
return "Stmt(" + string(n.Value) + ")"
}

func (n BlockStmt) stmtNode() {}
func (n EmptyStmt) stmtNode() {}
func (n ExprStmt) stmtNode() {}
func (n IfStmt) stmtNode() {}
func (n DoWhileStmt) stmtNode() {}
func (n WhileStmt) stmtNode() {}
func (n ForStmt) stmtNode() {}
func (n ForInStmt) stmtNode() {}
func (n ForOfStmt) stmtNode() {}
func (n SwitchStmt) stmtNode() {}
func (n BranchStmt) stmtNode() {}
func (n ReturnStmt) stmtNode() {}
func (n WithStmt) stmtNode() {}
func (n LabelledStmt) stmtNode() {}
func (n ThrowStmt) stmtNode() {}
func (n TryStmt) stmtNode() {}
func (n DebuggerStmt) stmtNode() {}
func (n ImportStmt) stmtNode() {}
func (n ExportStmt) stmtNode() {}
func (n DirectivePrologueStmt) stmtNode() {}

////////////////////////////////////////////////////////////////

Expand Down
24 changes: 18 additions & 6 deletions js/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ type Parser struct {
l *Lexer
err error

data []byte
tt TokenType
prevLT bool
inFor bool
async, generator bool
assumeArrowFunc bool
data []byte
tt TokenType
prevLT bool
inFor bool
async, generator bool
assumeArrowFunc bool
allowDirectivePrologue bool

stmtLevel int
exprLevel int
Expand Down Expand Up @@ -167,6 +168,7 @@ func (p *Parser) exitScope(parent *Scope) {

func (p *Parser) parseModule() (module BlockStmt) {
p.enterScope(&module.Scope, true)
p.allowDirectivePrologue = true
for {
switch p.tt {
case ErrorToken:
Expand Down Expand Up @@ -535,6 +537,13 @@ func (p *Parser) parseStmt(allowDeclaration bool) (stmt IStmt) {
p.fail("expression")
return
}
if p.allowDirectivePrologue {
if lit, ok := stmt.(*ExprStmt).Value.(*LiteralExpr); ok && lit.TokenType == StringToken {
stmt = &DirectivePrologueStmt{lit.Data}
} else {
p.allowDirectivePrologue = false
}
}
}
}
if p.tt == SemicolonToken {
Expand Down Expand Up @@ -867,6 +876,7 @@ func (p *Parser) parseAnyFunc(async, inExpr bool) (funcDecl FuncDecl) {
funcDecl.Name, _ = p.scope.Declare(ExprDecl, name) // cannot fail
}
funcDecl.Params = p.parseFuncParams("function declaration")
p.allowDirectivePrologue = true
funcDecl.Body.List = p.parseStmtList("function declaration")

p.async, p.generator = parentAsync, parentGenerator
Expand Down Expand Up @@ -975,6 +985,7 @@ func (p *Parser) parseMethod() (method MethodDecl) {
p.async, p.generator = method.Async, method.Generator

method.Params = p.parseFuncParams("method definition")
p.allowDirectivePrologue = true
method.Body.List = p.parseStmtList("method definition")

p.async, p.generator = parentAsync, parentGenerator
Expand Down Expand Up @@ -1400,6 +1411,7 @@ func (p *Parser) parseArrowFuncBody() (list []IStmt) {
if p.tt == OpenBraceToken {
parentInFor := p.inFor
p.inFor = false
p.allowDirectivePrologue = true
list = p.parseStmtList("arrow function")
p.inFor = parentInFor
} else {
Expand Down
1 change: 1 addition & 0 deletions js/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestParse(t *testing.T) {
{"\n", ""},
{"/* comment */", ""},
{"{}", "Stmt({ })"},
{`"use strict"`, `Stmt("use strict")`},
{"var a = b;", "Decl(var Binding(a = b))"},
{"const a = b;", "Decl(const Binding(a = b))"},
{"let a = b;", "Decl(let Binding(a = b))"},
Expand Down

0 comments on commit e167502

Please sign in to comment.