binary: implement all remaining binary operators

This commit is contained in:
mappu 2020-04-05 17:05:37 +12:00
parent 8f921436ed
commit d3f238cf01
1 changed files with 107 additions and 16 deletions

123
node.go
View File

@ -491,31 +491,122 @@ func convert(n_ node.Node) (string, error) {
// binary
//
case *binary.Plus:
// PHP uses + for numbers, `.` for strings; Go uses `+` in both cases
return convertBinaryCommon(n.Left, n.Right, `+`)
case *binary.BitwiseAnd:
return convertBinaryCommon(n.Left, n.Right, `&`)
case *binary.Smaller:
return convertBinaryCommon(n.Left, n.Right, `<`)
case *binary.BitwiseOr:
return convertBinaryCommon(n.Left, n.Right, `|`)
case *binary.SmallerOrEqual:
return convertBinaryCommon(n.Left, n.Right, `<=`)
case *binary.BitwiseXor:
return convertBinaryCommon(n.Left, n.Right, `^`) // n.b. Go only supports this for integers; PHP also supports it for bools
case *binary.Greater:
return convertBinaryCommon(n.Left, n.Right, `>`)
case *binary.BooleanAnd:
return convertBinaryCommon(n.Left, n.Right, `&&`)
case *binary.BooleanOr:
return convertBinaryCommon(n.Left, n.Right, `||`)
//case *binary.Coalesce:
// TODO this can't be expressed in an rvalue context in Go (unless we create a typed closure..?)
case *binary.Concat:
return convertBinaryCommon(n.Left, n.Right, `+`) // PHP uses + for numbers, `.` for strings; Go uses `+` in both cases
case *binary.Div:
return convertBinaryCommon(n.Left, n.Right, `/`) // PHP will upgrade ints to floats, Go won't
case *binary.Equal:
return convertBinaryCommon(n.Left, n.Right, `==`) // Type-lax equality comparator
case *binary.GreaterOrEqual:
return convertBinaryCommon(n.Left, n.Right, `>=`)
case *binary.Equal:
return convertBinaryCommon(n.Left, n.Right, `==`)
case *binary.Greater:
return convertBinaryCommon(n.Left, n.Right, `>`)
case *binary.Identical: // PHP triple-equals
return convertBinaryCommon(n.Left, n.Right, `===`)
case *binary.Identical:
return convertBinaryCommon(n.Left, n.Right, `==`) // PHP uses `===`, Go is already type-safe
case *binary.Concat:
// PHP uses + for numbers, `.` for strings; Go uses `+` in both cases
return convertBinaryCommon(n.Left, n.Right, `+`)
case *binary.LogicalAnd:
// This is the lexer token when using `and` in PHP. It's equivalent to
// `&&` but has different precedence
// e.g. $a = $b && $c ==> $a = ($b && $c)
// $a = $b and $c ==> ($a = $b) and $c
// So far, we are relying on the PHP parser having already having handled
// the precedence difference - transform to `&&` unconditionally
return convertBinaryCommon(n.Left, n.Right, `&&`)
case *binary.LogicalOr:
// As above
return convertBinaryCommon(n.Left, n.Right, `||`)
case *binary.LogicalXor:
// As above
return convertBinaryCommon(n.Left, n.Right, `^`) // n.b. Go only supports this for integers; PHP also supports it for bools
case *binary.Minus:
return convertBinaryCommon(n.Left, n.Right, `-`)
case *binary.Mod:
// Go doesn't have a built-in operator for mod - convert to a call to math.Mod()
rval, err := convert(n.Left)
if err != nil {
return "", parseErr{n, err}
}
modulo, err := convert(n.Right)
if err != nil {
return "", parseErr{n, err}
}
return `math.Mod(` + rval + `, ` + modulo + `)`, nil
case *binary.Mul:
return convertBinaryCommon(n.Left, n.Right, `*`)
case *binary.NotEqual:
return convertBinaryCommon(n.Left, n.Right, `!=`) // Type-lax equality comparator
case *binary.NotIdentical:
return convertBinaryCommon(n.Left, n.Right, `!=`) // PHP uses `!==`, Go is already type-safe
case *binary.Plus:
return convertBinaryCommon(n.Left, n.Right, `+`) // PHP uses + for numbers, `.` for strings; Go uses `+` in both cases
case *binary.Pow:
// Go doesn't have a built-in operator for mod - convert to a call to math.Pow()
base, err := convert(n.Left)
if err != nil {
return "", parseErr{n, err}
}
exponent, err := convert(n.Right)
if err != nil {
return "", parseErr{n, err}
}
return `math.Pow(` + base + `, ` + exponent + `)`, nil
case *binary.ShiftLeft:
return convertBinaryCommon(n.Left, n.Right, `<<`)
case *binary.ShiftRight:
return convertBinaryCommon(n.Left, n.Right, `>>`)
case *binary.SmallerOrEqual:
return convertBinaryCommon(n.Left, n.Right, `<=`)
case *binary.Smaller:
return convertBinaryCommon(n.Left, n.Right, `<`)
case *binary.Spaceship:
// The spaceship operator returns -1 / 0 / 1 based on a gteq/leq comparison
// Go doesn't have a built-in spaceship operator
// The primary use case is in user-definded sort comparators, where Go
// uses bools instead ints anyway.
// Subtraction is a reasonable substitute
return convertBinaryCommon(n.Left, n.Right, `-`)
//
// scalar