diff --git a/node.go b/node.go index 4037bff..a3030ac 100644 --- a/node.go +++ b/node.go @@ -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