Skip to content

Commit

Permalink
fix: positions of statements (#506)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tyamagu2 authored Jul 25, 2023
1 parent 589611c commit 11288b7
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 23 deletions.
39 changes: 25 additions & 14 deletions ast/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}

Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -800,6 +807,7 @@ type SwitchStatement struct {
Discriminant Expression
Default int
Body []*CaseStatement
RightBrace file.Idx
}

// Idx0 implements Node.
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand Down
88 changes: 87 additions & 1 deletion parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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 )")
})
}

Expand Down
20 changes: 12 additions & 8 deletions parser/statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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,
}
Expand All @@ -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
}
Expand All @@ -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()
Expand All @@ -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)
Expand Down Expand Up @@ -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 {
Expand All @@ -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()
Expand All @@ -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 {
Expand All @@ -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()
Expand Down

0 comments on commit 11288b7

Please sign in to comment.