From 11288b75643653b03ba5852ee56392a2cb81eb57 Mon Sep 17 00:00:00 2001 From: Tomoki Yamaguchi Date: Wed, 26 Jul 2023 02:25:01 +0900 Subject: [PATCH] fix: positions of statements (#506) Fix the positions of various statements: * Fix Idx1 of BranchStatement so that it points to the character after the label if Label exists, or the one after Token if Label does not exist. * Fix Idx1 of LabelledStatement so that it points to the character after the statement. * Fix Idx1 of ReturnStatement so that it points to the character after the argument if Argument exists, or the one after return keyword if Argument does not exist. * Set Idx0 of SwitchStatement and fix Idx1 of SwitchStatement so that it points to the character after the right brace. * Fix Idx0 of ThrowStatement to point to the start of throw keyword and fix Idx1 of ThrowStatement so that it points to the next character after Argument. * Fix Idx1 of TryStatement to point to the character after Finally if Finally exists, or after Catch if Finally does not exist. * Set Idx0 of WithStatement which was not previously set. * Set WhileStatement.While so that Idx0 points to the right place. * Set Idx0 of DoWhileStatement and fix Idx1 to point to the next character after the right parenthesis. --- ast/node.go | 39 ++++++++++++------- parser/parser_test.go | 88 ++++++++++++++++++++++++++++++++++++++++++- parser/statement.go | 20 ++++++---- 3 files changed, 124 insertions(+), 23 deletions(-) diff --git a/ast/node.go b/ast/node.go index 4ac013e..ec49c73 100644 --- a/ast/node.go +++ b/ast/node.go @@ -543,16 +543,19 @@ type BranchStatement struct { Label *Identifier } -// Idx1 implements Node. -func (bs *BranchStatement) Idx1() file.Idx { - return bs.Idx -} - // Idx0 implements Node. func (bs *BranchStatement) Idx0() file.Idx { return bs.Idx } +// Idx1 implements Node. +func (bs *BranchStatement) Idx1() file.Idx { + if bs.Label == nil { + return file.Idx(int(bs.Idx) + len(bs.Token.String())) + } + return bs.Label.Idx1() +} + // expression implements Statement. func (*BranchStatement) statement() {} @@ -616,9 +619,10 @@ func (*DebuggerStatement) statement() {} // DoWhileStatement represents a do while statement. type DoWhileStatement struct { - Do file.Idx - Test Expression - Body Statement + Do file.Idx + Test Expression + Body Statement + RightParenthesis file.Idx } // Idx0 implements Node. @@ -628,7 +632,7 @@ func (dws *DoWhileStatement) Idx0() file.Idx { // Idx1 implements Node. func (dws *DoWhileStatement) Idx1() file.Idx { - return dws.Test.Idx1() + return dws.RightParenthesis + 1 } // expression implements Statement. @@ -769,7 +773,7 @@ func (ls *LabelledStatement) Idx0() file.Idx { // Idx1 implements Node. func (ls *LabelledStatement) Idx1() file.Idx { - return ls.Colon + 1 + return ls.Statement.Idx1() } // expression implements Statement. @@ -788,7 +792,10 @@ func (rs *ReturnStatement) Idx0() file.Idx { // Idx1 implements Node. func (rs *ReturnStatement) Idx1() file.Idx { - return rs.Return + if rs.Argument != nil { + return rs.Argument.Idx1() + } + return rs.Return + 6 } // expression implements Statement. @@ -800,6 +807,7 @@ type SwitchStatement struct { Discriminant Expression Default int Body []*CaseStatement + RightBrace file.Idx } // Idx0 implements Node. @@ -809,7 +817,7 @@ func (ss *SwitchStatement) Idx0() file.Idx { // Idx1 implements Node. func (ss *SwitchStatement) Idx1() file.Idx { - return ss.Body[len(ss.Body)-1].Idx1() + return ss.RightBrace + 1 } // expression implements Statement. @@ -828,7 +836,7 @@ func (ts *ThrowStatement) Idx0() file.Idx { // Idx1 implements Node. func (ts *ThrowStatement) Idx1() file.Idx { - return ts.Throw + return ts.Argument.Idx1() } // expression implements Statement. @@ -849,7 +857,10 @@ func (ts *TryStatement) Idx0() file.Idx { // Idx1 implements Node. func (ts *TryStatement) Idx1() file.Idx { - return ts.Try + if ts.Finally != nil { + return ts.Finally.Idx1() + } + return ts.Catch.Idx1() } // expression implements Statement. diff --git a/parser/parser_test.go b/parser/parser_test.go index e026030..727d83c 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -1025,7 +1025,8 @@ func TestPosition(t *testing.T) { is(node.Idx0(), 14) is(parser.slice(node.Idx0(), node.Idx1()), "if (abc) { throw 'failed'; }") node = node.(*ast.IfStatement).Consequent.(*ast.BlockStatement).List[0].(*ast.ThrowStatement) - is(node.Idx0(), 39) + is(node.Idx0(), 25) + is(parser.slice(node.Idx0(), node.Idx1()), "throw 'failed'") parser = newParser("", "(function(){ for (x=1; x<=4; x++) { console.log(x); } })", 1, nil) program, err = parser.parse() @@ -1100,6 +1101,91 @@ func TestPosition(t *testing.T) { node = block.List[0].(*ast.VariableStatement).List[1].(*ast.VariableExpression) is(node.Idx0(), 23) is(parser.slice(node.Idx0(), node.Idx1()), "xyz = 1") + + parser = newParser("", "for (i = 0; i < 10; i++) { if (i == 5) break; }", 1, nil) + program, err = parser.parse() + is(err, nil) + block = program.Body[0].(*ast.ForStatement).Body.(*ast.BlockStatement) + node = block.List[0].(*ast.IfStatement).Consequent.(*ast.BranchStatement) + is(node.Idx0(), 40) + is(parser.slice(node.Idx0(), node.Idx1()), "break") + + parser = newParser("", "(function(){ xyz: for (i = 0; i < 10; i++) { if (i == 5) continue xyz; } })", 1, nil) + program, err = parser.parse() + is(err, nil) + block = program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.FunctionLiteral).Body.(*ast.BlockStatement) + node = block.List[0].(*ast.LabelledStatement) + is(node.Idx0(), 14) + is(parser.slice(node.Idx0(), node.Idx1()), "xyz: for (i = 0; i < 10; i++) { if (i == 5) continue xyz; }") + block = node.(*ast.LabelledStatement).Statement.(*ast.ForStatement).Body.(*ast.BlockStatement) + node = block.List[0].(*ast.IfStatement).Consequent.(*ast.BranchStatement) + is(node.Idx0(), 58) + is(parser.slice(node.Idx0(), node.Idx1()), "continue xyz") + + parser = newParser("", "(function(){ return; })", 1, nil) + program, err = parser.parse() + is(err, nil) + block = program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.FunctionLiteral).Body.(*ast.BlockStatement) + node = block.List[0].(*ast.ReturnStatement) + is(node.Idx0(), 14) + is(parser.slice(node.Idx0(), node.Idx1()), "return") + + parser = newParser("", "(function(){ return 10; })", 1, nil) + program, err = parser.parse() + is(err, nil) + block = program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.FunctionLiteral).Body.(*ast.BlockStatement) + node = block.List[0].(*ast.ReturnStatement) + is(node.Idx0(), 14) + is(parser.slice(node.Idx0(), node.Idx1()), "return 10") + + parser = newParser("", "(function(){ switch (a) { default: return; }})", 1, nil) + program, err = parser.parse() + is(err, nil) + block = program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.FunctionLiteral).Body.(*ast.BlockStatement) + node = block.List[0].(*ast.SwitchStatement) + is(node.Idx0(), 14) + is(parser.slice(node.Idx0(), node.Idx1()), "switch (a) { default: return; }") + + parser = newParser("", "(function(){ try { a(); } catch (error) { b(); } })", 1, nil) + program, err = parser.parse() + is(err, nil) + block = program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.FunctionLiteral).Body.(*ast.BlockStatement) + node = block.List[0].(*ast.TryStatement) + is(node.Idx0(), 14) + is(parser.slice(node.Idx0(), node.Idx1()), "try { a(); } catch (error) { b(); }") + node = block.List[0].(*ast.TryStatement).Catch + is(node.Idx0(), 27) + is(parser.slice(node.Idx0(), node.Idx1()), "catch (error) { b(); }") + + parser = newParser("", "(function(){ try { a(); } catch (error) { b(); } finally { c(); } })", 1, nil) + program, err = parser.parse() + is(err, nil) + block = program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.FunctionLiteral).Body.(*ast.BlockStatement) + node = block.List[0].(*ast.TryStatement) + is(node.Idx0(), 14) + is(parser.slice(node.Idx0(), node.Idx1()), "try { a(); } catch (error) { b(); } finally { c(); }") + + parser = newParser("", "(function(){ with (1) {} })", 1, nil) + program, err = parser.parse() + is(err, nil) + block = program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.FunctionLiteral).Body.(*ast.BlockStatement) + node = block.List[0].(*ast.WithStatement) + is(node.Idx0(), 14) + is(parser.slice(node.Idx0(), node.Idx1()), "with (1) {}") + + parser = newParser("", "while (i < 10) { i++; }", 1, nil) + program, err = parser.parse() + is(err, nil) + node = program.Body[0].(*ast.WhileStatement) + is(node.Idx0(), 1) + is(parser.slice(node.Idx0(), node.Idx1()), "while (i < 10) { i++; }") + + parser = newParser("", "do { i++; } while (i < 10 )", 1, nil) + program, err = parser.parse() + is(err, nil) + node = program.Body[0].(*ast.DoWhileStatement) + is(node.Idx0(), 1) + is(parser.slice(node.Idx0(), node.Idx1()), "do { i++; } while (i < 10 )") }) } diff --git a/parser/statement.go b/parser/statement.go index f853afc..3abe175 100644 --- a/parser/statement.go +++ b/parser/statement.go @@ -356,7 +356,7 @@ func (p *parser) parseThrowStatement() ast.Statement { } node := &ast.ThrowStatement{ - Throw: p.idx, + Throw: idx, Argument: p.parseExpression(), } if p.mode&StoreComments != 0 { @@ -373,12 +373,13 @@ func (p *parser) parseSwitchStatement() ast.Statement { if p.mode&StoreComments != 0 { comments = p.comments.FetchAll() } - p.expect(token.SWITCH) + idx := p.expect(token.SWITCH) if p.mode&StoreComments != 0 { comments = append(comments, p.comments.FetchAll()...) } p.expect(token.LEFT_PARENTHESIS) node := &ast.SwitchStatement{ + Switch: idx, Discriminant: p.parseExpression(), Default: -1, } @@ -397,6 +398,7 @@ func (p *parser) parseSwitchStatement() ast.Statement { for index := 0; p.token != token.EOF; index++ { if p.token == token.RIGHT_BRACE { + node.RightBrace = p.idx p.next() break } @@ -423,7 +425,7 @@ func (p *parser) parseWithStatement() ast.Statement { if p.mode&StoreComments != 0 { comments = p.comments.FetchAll() } - p.expect(token.WITH) + idx := p.expect(token.WITH) var withComments []*ast.Comment if p.mode&StoreComments != 0 { withComments = p.comments.FetchAll() @@ -432,6 +434,7 @@ func (p *parser) parseWithStatement() ast.Statement { p.expect(token.LEFT_PARENTHESIS) node := &ast.WithStatement{ + With: idx, Object: p.parseExpression(), } p.expect(token.RIGHT_PARENTHESIS) @@ -658,13 +661,13 @@ func (p *parser) parseDoWhileStatement() ast.Statement { if p.mode&StoreComments != 0 { comments = p.comments.FetchAll() } - p.expect(token.DO) + idx := p.expect(token.DO) var doComments []*ast.Comment if p.mode&StoreComments != 0 { doComments = p.comments.FetchAll() } - node := &ast.DoWhileStatement{} + node := &ast.DoWhileStatement{Do: idx} if p.token == token.LEFT_BRACE { node.Body = p.parseBlockStatement() } else { @@ -678,7 +681,7 @@ func (p *parser) parseDoWhileStatement() ast.Statement { } p.expect(token.LEFT_PARENTHESIS) node.Test = p.parseExpression() - p.expect(token.RIGHT_PARENTHESIS) + node.RightParenthesis = p.expect(token.RIGHT_PARENTHESIS) p.implicitSemicolon = true p.optionalSemicolon() @@ -697,7 +700,7 @@ func (p *parser) parseWhileStatement() ast.Statement { if p.mode&StoreComments != 0 { comments = p.comments.FetchAll() } - p.expect(token.WHILE) + idx := p.expect(token.WHILE) var whileComments []*ast.Comment if p.mode&StoreComments != 0 { @@ -706,7 +709,8 @@ func (p *parser) parseWhileStatement() ast.Statement { p.expect(token.LEFT_PARENTHESIS) node := &ast.WhileStatement{ - Test: p.parseExpression(), + While: idx, + Test: p.parseExpression(), } p.expect(token.RIGHT_PARENTHESIS) node.Body = p.parseIterationStatement()