Skip to content

Commit

Permalink
Support patterns in catch clause. See #305
Browse files Browse the repository at this point in the history
  • Loading branch information
dop251 committed Jul 25, 2021
1 parent 26be9bf commit b8e8f56
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 27 deletions.
2 changes: 1 addition & 1 deletion ast/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ type (

CatchStatement struct {
Catch file.Idx
Parameter *Identifier
Parameter BindingTarget
Body *BlockStatement
}

Expand Down
35 changes: 22 additions & 13 deletions compiler_stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,6 @@ func (c *compiler) updateEnterBlock(enter *enterBlock) {
}

func (c *compiler) compileTryStatement(v *ast.TryStatement, needResult bool) {
if c.scope.strict && v.Catch != nil && v.Catch.Parameter != nil {
switch v.Catch.Parameter.Name {
case "arguments", "eval":
c.throwSyntaxError(int(v.Catch.Parameter.Idx)-1, "Catch variable may not be eval or arguments in strict mode")
}
}
c.block = &block{
typ: blockTry,
outer: c.block,
Expand Down Expand Up @@ -146,16 +140,31 @@ func (c *compiler) compileTryStatement(v *ast.TryStatement, needResult bool) {
c.newBlockScope()
list := v.Catch.Body.List
funcs := c.extractFunctions(list)
c.createFunctionBindings(funcs)
c.scope.bindNameLexical(v.Catch.Parameter.Name, true, int(v.Catch.Parameter.Idx)-1)
bindings := c.scope.bindings
if l := len(bindings); l > 1 {
// make sure the catch variable always goes first
bindings[0], bindings[l-1] = bindings[l-1], bindings[0]
if _, ok := v.Catch.Parameter.(ast.Pattern); ok {
// add anonymous binding for the catch parameter, note it must be first
c.scope.addBinding(int(v.Catch.Idx0()) - 1)
}
c.compileLexicalDeclarations(list, true)
c.createBindings(v.Catch.Parameter, func(name unistring.String, offset int) {
if c.scope.strict {
switch name {
case "arguments", "eval":
c.throwSyntaxError(offset, "Catch variable may not be eval or arguments in strict mode")
}
}
c.scope.bindNameLexical(name, true, offset)
})
enter := &enterBlock{}
c.emit(enter)
if pattern, ok := v.Catch.Parameter.(ast.Pattern); ok {
c.scope.bindings[0].emitGet()
c.emitPattern(pattern, func(target, init compiledExpr) {
c.emitPatternLexicalAssign(target, init, false)
}, false)
}
for _, decl := range funcs {
c.scope.bindNameLexical(decl.Function.Name.Name, true, int(decl.Function.Name.Idx1())-1)
}
c.compileLexicalDeclarations(list, true)
c.compileFunctions(funcs)
c.compileStatements(list, bodyNeedResult)
c.leaveScopeBlock(enter)
Expand Down
16 changes: 16 additions & 0 deletions compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4031,6 +4031,22 @@ func TestVariadicUseStackVars(t *testing.T) {
testScript1(SCRIPT, asciiString("C"), t)
}

func TestCatchParamPattern(t *testing.T) {
const SCRIPT = `
function f() {
let x = 3;
try {
throw {a: 1, b: 2};
} catch ({a, b, c = x}) {
let x = 99;
return ""+a+" "+b+" "+c;
}
}
f();
`
testScript1(SCRIPT, asciiString("1 2 3"), t)
}

/*
func TestBabel(t *testing.T) {
src, err := ioutil.ReadFile("babel7.js")
Expand Down
11 changes: 7 additions & 4 deletions parser/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,10 @@ func (self *_parser) parseRegExpLiteral() *ast.RegExpLiteral {
}
}

func (self *_parser) parseVariableDeclaration(declarationList *[]*ast.Binding) ast.Expression {
func (self *_parser) parseBindingTarget() (target ast.BindingTarget) {
if self.token == token.LET {
self.token = token.IDENTIFIER
}
var target ast.BindingTarget
switch self.token {
case token.IDENTIFIER:
target = &ast.Identifier{
Expand All @@ -161,11 +160,15 @@ func (self *_parser) parseVariableDeclaration(declarationList *[]*ast.Binding) a
default:
idx := self.expect(token.IDENTIFIER)
self.nextStatement()
return &ast.BadExpression{From: idx, To: self.idx}
target = &ast.BadExpression{From: idx, To: self.idx}
}

return
}

func (self *_parser) parseVariableDeclaration(declarationList *[]*ast.Binding) ast.Expression {
node := &ast.Binding{
Target: target,
Target: self.parseBindingTarget(),
}

if declarationList != nil {
Expand Down
12 changes: 3 additions & 9 deletions parser/statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,17 +128,11 @@ func (self *_parser) parseTryStatement() ast.Statement {
if self.token == token.CATCH {
catch := self.idx
self.next()
var parameter *ast.Identifier
var parameter ast.BindingTarget
if self.token == token.LEFT_PARENTHESIS {
self.next()
if self.token != token.IDENTIFIER {
self.expect(token.IDENTIFIER)
self.nextStatement()
return &ast.BadStatement{From: catch, To: self.idx}
} else {
parameter = self.parseIdentifier()
self.expect(token.RIGHT_PARENTHESIS)
}
parameter = self.parseBindingTarget()
self.expect(token.RIGHT_PARENTHESIS)
}
node.Catch = &ast.CatchStatement{
Catch: catch,
Expand Down
5 changes: 5 additions & 0 deletions tc39_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ var (
"test/language/statements/for-of/dstr/let-obj-ptrn-id-init-fn-name-class.js": true,
"test/language/statements/for-of/dstr/const-ary-ptrn-elem-id-init-fn-name-class.js": true,
"test/language/statements/for-of/dstr/let-ary-ptrn-elem-id-init-fn-name-class.js": true,
"test/language/statements/try/dstr/obj-ptrn-id-init-fn-name-class.js": true,
"test/language/statements/try/dstr/ary-ptrn-elem-id-init-fn-name-class.js": true,

// arrow-function
"test/built-ins/Object/prototype/toString/proxy-function.js": true,
Expand Down Expand Up @@ -247,6 +249,8 @@ var (
"test/language/statements/for-of/dstr/let-obj-ptrn-id-init-fn-name-arrow.js": true,
"test/language/statements/for-of/dstr/array-elem-init-fn-name-arrow.js": true,
"test/language/expressions/call/spread-obj-spread-order.js": true,
"test/language/statements/try/dstr/obj-ptrn-id-init-fn-name-arrow.js": true,
"test/language/statements/try/dstr/ary-ptrn-elem-id-init-fn-name-arrow.js": true,

// template strings
"test/built-ins/String/raw/zero-literal-segments.js": true,
Expand Down Expand Up @@ -403,6 +407,7 @@ var (
"sec-with-statement*",
"sec-switch-*",
"sec-try-*",
"sec-runtime-semantics-catchclauseevaluation",
"sec-strict-mode-of-ecmascript",
"sec-let-and-const-declarations*",
"sec-arguments-exotic-objects-defineownproperty-p-desc",
Expand Down

0 comments on commit b8e8f56

Please sign in to comment.