Repository: robertkrimen/otto
Pull request #505 (2023-07-21 01:54:16)

fix: positions of expressions
* Fix typo in `parseConditionlExpression`
* Fix Idx1 of ConditionalExpression to point to Alternate.Idx1()
* Fix Idx1 of SequenceExpression to point to Idx1 of the last Sequence element
* Fix Idx0 of UnaryExpression to point to the beginning of Operand in case of postfix operator
* Fix Idx1 of VariableExpression to point to the character immediately after Name if it does not have Initializer


Patch:
diff --git a/ast/node.go b/ast/node.go
index db37770..4ac013e 100644
--- a/ast/node.go
+++ b/ast/node.go
@@ -178,7 +178,7 @@ func (ce *ConditionalExpression) Idx0() file.Idx {
 
 // Idx1 implements Node.
 func (ce *ConditionalExpression) Idx1() file.Idx {
-	return ce.Test.Idx1()
+	return ce.Alternate.Idx1()
 }
 
 // expression implements Expression.
@@ -397,7 +397,7 @@ func (se *SequenceExpression) Idx0() file.Idx {
 
 // Idx1 implements Node.
 func (se *SequenceExpression) Idx1() file.Idx {
-	return se.Sequence[0].Idx1()
+	return se.Sequence[len(se.Sequence)-1].Idx1()
 }
 
 // expression implements Expression.
@@ -451,6 +451,9 @@ type UnaryExpression struct {
 
 // Idx0 implements Node.
 func (ue *UnaryExpression) Idx0() file.Idx {
+	if ue.Postfix {
+		return ue.Operand.Idx0()
+	}
 	return ue.Idx
 }
 
@@ -480,7 +483,7 @@ func (ve *VariableExpression) Idx0() file.Idx {
 // Idx1 implements Node.
 func (ve *VariableExpression) Idx1() file.Idx {
 	if ve.Initializer == nil {
-		return file.Idx(int(ve.Idx) + len(ve.Name) + 1)
+		return file.Idx(int(ve.Idx) + len(ve.Name))
 	}
 	return ve.Initializer.Idx1()
 }
diff --git a/parser/expression.go b/parser/expression.go
index dd8606e..bfff965 100644
--- a/parser/expression.go
+++ b/parser/expression.go
@@ -884,7 +884,7 @@ func (p *parser) parseLogicalOrExpression() ast.Expression {
 	return left
 }
 
-func (p *parser) parseConditionlExpression() ast.Expression {
+func (p *parser) parseConditionalExpression() ast.Expression {
 	left := p.parseLogicalOrExpression()
 
 	if p.token == token.QUESTION_MARK {
@@ -911,7 +911,7 @@ func (p *parser) parseConditionlExpression() ast.Expression {
 }
 
 func (p *parser) parseAssignmentExpression() ast.Expression {
-	left := p.parseConditionlExpression()
+	left := p.parseConditionalExpression()
 	var operator token.Token
 	switch p.token {
 	case token.ASSIGN:


Test patch:
diff --git a/parser/parser_test.go b/parser/parser_test.go
index 13f7328..e026030 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -1056,6 +1056,50 @@ func TestPosition(t *testing.T) {
 		node = program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.AssignExpression).Right.(*ast.ArrayLiteral)
 		is(node.Idx0(), 5)
 		is(parser.slice(node.Idx0(), node.Idx1()), "[1, 2]")
+
+		parser = newParser("", "x = true ? 1 : 2", 1, nil)
+		program, err = parser.parse()
+		is(err, nil)
+		node = program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.AssignExpression).Right.(*ast.ConditionalExpression)
+		is(node.Idx0(), 5)
+		is(parser.slice(node.Idx0(), node.Idx1()), "true ? 1 : 2")
+
+		parser = newParser("", "(function(){ x = 1, y = 2; })", 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.ExpressionStatement).Expression.(*ast.SequenceExpression)
+		is(node.Idx0(), 14)
+		is(parser.slice(node.Idx0(), node.Idx1()), "x = 1, y = 2")
+
+		parser = newParser("", "x = ~x", 1, nil)
+		program, err = parser.parse()
+		is(err, nil)
+		node = program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.AssignExpression).Right.(*ast.UnaryExpression)
+		is(node.Idx0(), 5)
+		is(parser.slice(node.Idx0(), node.Idx1()), "~x")
+
+		parser = newParser("", "(function(){ 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.ExpressionStatement).Expression.(*ast.UnaryExpression)
+		is(node.Idx0(), 14)
+		is(parser.slice(node.Idx0(), node.Idx1()), "xyz++")
+
+		parser = newParser("", "(function(){ var abc, xyz = 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.VariableStatement)
+		is(node.Idx0(), 14)
+		is(parser.slice(node.Idx0(), node.Idx1()), "var abc, xyz = 1")
+		node = block.List[0].(*ast.VariableStatement).List[0].(*ast.VariableExpression)
+		is(node.Idx0(), 18)
+		is(parser.slice(node.Idx0(), node.Idx1()), "abc")
+		node = block.List[0].(*ast.VariableStatement).List[1].(*ast.VariableExpression)
+		is(node.Idx0(), 23)
+		is(parser.slice(node.Idx0(), node.Idx1()), "xyz = 1")
 	})
 }