Support string concatenation with += operator

This commit is contained in:
joeduffy 2017-02-15 18:51:37 -08:00
parent 71a22509d7
commit 84c3f0f9bc
2 changed files with 32 additions and 3 deletions

View file

@ -569,9 +569,32 @@ func (a *astBinder) checkBinaryOperatorExpression(node *ast.BinaryOperatorExpres
a.b.Diag().Errorf(errors.ErrorIllegalAssignmentTypes.At(node), rhs, lhs)
}
a.b.ctx.RegisterType(node, lhs)
case ast.OpAssignSum, ast.OpAssignDifference, ast.OpAssignProduct, ast.OpAssignQuotient,
case ast.OpAssignSum:
// Lhs and rhs can be numbers (for addition) or strings (for concatenation).
if !a.isLValue(node.Left) {
a.b.Diag().Errorf(errors.ErrorIllegalAssignmentLValue.At(node))
a.b.ctx.RegisterType(node, types.Number)
} else if lhs == types.Number {
if rhs != types.Number {
a.b.Diag().Errorf(errors.ErrorBinaryOperatorInvalidForType.At(node),
node.Operator, "RHS", rhs, types.Number)
}
a.b.ctx.RegisterType(node, types.Number)
} else if lhs == types.String {
if rhs != types.String {
a.b.Diag().Errorf(errors.ErrorBinaryOperatorInvalidForType.At(node),
node.Operator, "RHS", rhs, types.String)
}
a.b.ctx.RegisterType(node, types.String)
} else {
a.b.Diag().Errorf(errors.ErrorBinaryOperatorInvalidForType.At(node),
node.Operator, "LHS", lhs, "string or number")
a.b.ctx.RegisterType(node, types.Number)
}
case ast.OpAssignDifference, ast.OpAssignProduct, ast.OpAssignQuotient,
ast.OpAssignRemainder, ast.OpAssignExponentiation, ast.OpAssignBitwiseShiftLeft, ast.OpAssignBitwiseShiftRight,
ast.OpAssignBitwiseAnd, ast.OpAssignBitwiseOr, ast.OpAssignBitwiseXor:
// These operators require numeric values.
if !a.isLValue(node.Left) {
a.b.Diag().Errorf(errors.ErrorIllegalAssignmentLValue.At(node))
} else if lhs != types.Number {

View file

@ -1477,9 +1477,15 @@ func (e *evaluator) evalBinaryOperatorExpression(node *ast.BinaryOperatorExpress
e.evalAssign(node.Left, *lhsloc, rhs)
return rhs, nil
case ast.OpAssignSum:
// The target is a numeric l-value; just += rhs to it, and yield the new value as the result.
var val *rt.Object
ptr := lhs.PointerValue()
val := e.alloc.NewNumber(ptr.Obj().NumberValue() + rhs.NumberValue())
if lhs.Type() == types.String {
// If the lhs/rhs are strings, just concatenate += and yield the new value as a result.
val = e.alloc.NewString(ptr.Obj().StringValue() + rhs.StringValue())
} else {
// Otherwise, the target is a numeric l-value; just += to it, and yield the new value as the result.
val = e.alloc.NewNumber(ptr.Obj().NumberValue() + rhs.NumberValue())
}
e.evalAssign(node.Left, *lhsloc, val)
return val, nil
case ast.OpAssignDifference: