stmt: track conversion state in a struct

This commit is contained in:
mappu 2020-04-05 18:45:14 +12:00
parent 2a00699b2f
commit 45b694434d
2 changed files with 84 additions and 80 deletions

View File

@ -21,6 +21,7 @@ func ConvertFile(filename string) (string, error) {
namespaces := visitor.NewNamespaceResolver() namespaces := visitor.NewNamespaceResolver()
// scope := NewScope() // scope := NewScope()
state := conversionState{}
p, err := parser.NewParser([]byte(inputFile), "7.4") p, err := parser.NewParser([]byte(inputFile), "7.4")
if err != nil { if err != nil {
@ -40,7 +41,7 @@ func ConvertFile(filename string) (string, error) {
} }
// Walk and print (converted) // Walk and print (converted)
ret, err := convert(p.GetRootNode()) ret, err := state.convert(p.GetRootNode())
if err != nil { if err != nil {
return "", err return "", err
} }

161
node.go
View File

@ -36,7 +36,10 @@ func (pe parseErr) Unwrap() error {
// //
func convert(n_ node.Node) (string, error) { type conversionState struct {
}
func (this *conversionState) convert(n_ node.Node) (string, error) {
switch n := n_.(type) { switch n := n_.(type) {
// //
@ -50,7 +53,7 @@ func convert(n_ node.Node) (string, error) {
statements := []string{} statements := []string{}
for _, s := range n.Stmts { for _, s := range n.Stmts {
sm, err := convert(s) sm, err := this.convert(s)
if err != nil { if err != nil {
return "", parseErr{s, err} return "", parseErr{s, err}
} }
@ -91,7 +94,7 @@ func convert(n_ node.Node) (string, error) {
ret := "{\n" // new variable scope ret := "{\n" // new variable scope
for _, s := range n.Stmts { for _, s := range n.Stmts {
line, err := convert(s) line, err := this.convert(s)
if err != nil { if err != nil {
return "", parseErr{s, err} return "", parseErr{s, err}
} }
@ -167,7 +170,7 @@ func convert(n_ node.Node) (string, error) {
allStmts = append(allStmts, Literal{`return this, nil`}) allStmts = append(allStmts, Literal{`return this, nil`})
// Method body // Method body
funcStmt, err := convertFunctionCommon(s.Params, returnType, true /* always use ptr return */, allStmts) funcStmt, err := this.convertFunctionCommon(s.Params, returnType, true /* always use ptr return */, allStmts)
if err != nil { if err != nil {
return "", parseErr{s, err} return "", parseErr{s, err}
} }
@ -183,7 +186,7 @@ func convert(n_ node.Node) (string, error) {
} }
// Method body // Method body
funcStmt, err := convertFunctionCommon(s.Params, s.ReturnType, s.ReturnsRef, s.Stmt.(*stmt.StmtList).Stmts) funcStmt, err := this.convertFunctionCommon(s.Params, s.ReturnType, s.ReturnsRef, s.Stmt.(*stmt.StmtList).Stmts)
if err != nil { if err != nil {
return "", parseErr{s, err} return "", parseErr{s, err}
} }
@ -223,7 +226,7 @@ func convert(n_ node.Node) (string, error) {
funcName = toPublic(funcName) funcName = toPublic(funcName)
// Convert body // Convert body
funcStmt, err := convertFunctionCommon(n.Params, n.ReturnType, n.ReturnsRef, n.Stmts) funcStmt, err := this.convertFunctionCommon(n.Params, n.ReturnType, n.ReturnsRef, n.Stmts)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -232,7 +235,7 @@ func convert(n_ node.Node) (string, error) {
return ret, nil return ret, nil
case *stmt.Return: case *stmt.Return:
child, err := convert(n.Expr) child, err := this.convert(n.Expr)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -252,7 +255,7 @@ func convert(n_ node.Node) (string, error) {
return "return nil, errors.New(" + str.Value + ")\n", nil return "return nil, errors.New(" + str.Value + ")\n", nil
} }
child, err := convert(n.Expr) child, err := this.convert(n.Expr)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -268,7 +271,7 @@ func convert(n_ node.Node) (string, error) {
// No initialiser in loop // No initialiser in loop
} else if len(n.Init) == 1 { } else if len(n.Init) == 1 {
finit, err = convert(n.Init[0]) finit, err = this.convert(n.Init[0])
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -279,7 +282,7 @@ func convert(n_ node.Node) (string, error) {
// it may cause an extra local variable after the loop that may result // it may cause an extra local variable after the loop that may result
// in type mismatch (can be fixed by using an extra scope). // in type mismatch (can be fixed by using an extra scope).
for _, initStmt := range n.Init { for _, initStmt := range n.Init {
singleInitStmt, err := convert(initStmt) singleInitStmt, err := this.convert(initStmt)
if err != nil { if err != nil {
return "", parseErr{initStmt, err} return "", parseErr{initStmt, err}
} }
@ -291,7 +294,7 @@ func convert(n_ node.Node) (string, error) {
if len(n.Cond) != 1 { if len(n.Cond) != 1 {
return "", parseErr{n, fmt.Errorf("for loop can only have 1 cond clause, found %d", len(n.Cond))} return "", parseErr{n, fmt.Errorf("for loop can only have 1 cond clause, found %d", len(n.Cond))}
} }
fcond, err := convert(n.Cond[0]) fcond, err := this.convert(n.Cond[0])
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -308,12 +311,12 @@ func convert(n_ node.Node) (string, error) {
loopStmt = expr.NewPostDec(predec.Variable) loopStmt = expr.NewPostDec(predec.Variable)
} }
floop, err := convert(loopStmt) floop, err := this.convert(loopStmt)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
body, err := convert(convertToStmtList(n.Stmt)) body, err := this.convert(convertToStmtList(n.Stmt))
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -321,25 +324,25 @@ func convert(n_ node.Node) (string, error) {
return preinit + "for " + finit + "; " + fcond + "; " + floop + " " + body + "\n", nil return preinit + "for " + finit + "; " + fcond + "; " + floop + " " + body + "\n", nil
case *stmt.Foreach: case *stmt.Foreach:
iterand, err := convert(n.Expr) iterand, err := this.convert(n.Expr)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
valueReceiver, err := convert(n.Variable) valueReceiver, err := this.convert(n.Variable)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
keyReceiver := `_` keyReceiver := `_`
if n.Key != nil { if n.Key != nil {
keyReceiver, err = convert(n.Key) keyReceiver, err = this.convert(n.Key)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
} }
body, err := convert(convertToStmtList(n.Stmt)) body, err := this.convert(convertToStmtList(n.Stmt))
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -347,12 +350,12 @@ func convert(n_ node.Node) (string, error) {
return "for " + keyReceiver + ", " + valueReceiver + " := range " + iterand + " " + body + "\n", nil return "for " + keyReceiver + ", " + valueReceiver + " := range " + iterand + " " + body + "\n", nil
case *stmt.While: case *stmt.While:
cond, err := convert(n.Cond) cond, err := this.convert(n.Cond)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
body, err := convert(convertToStmtList(n.Stmt)) body, err := this.convert(convertToStmtList(n.Stmt))
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -360,7 +363,7 @@ func convert(n_ node.Node) (string, error) {
return "for " + cond + " " + body + "\n", nil return "for " + cond + " " + body + "\n", nil
case *stmt.Do: case *stmt.Do:
cond, err := convert(n.Cond) cond, err := this.convert(n.Cond)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -368,7 +371,7 @@ func convert(n_ node.Node) (string, error) {
bodyStmts := convertToStmtList(n.Stmt) bodyStmts := convertToStmtList(n.Stmt)
bodyStmts.Stmts = append(bodyStmts.Stmts, Literal{"if " + cond + "{\nbreak\n}"}) bodyStmts.Stmts = append(bodyStmts.Stmts, Literal{"if " + cond + "{\nbreak\n}"})
body, err := convert(bodyStmts) body, err := this.convert(bodyStmts)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -376,7 +379,7 @@ func convert(n_ node.Node) (string, error) {
return "for " + cond + " " + body + "\n", nil return "for " + cond + " " + body + "\n", nil
case *stmt.Expression: case *stmt.Expression:
child, err := convert(n.Expr) child, err := this.convert(n.Expr)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -388,7 +391,7 @@ func convert(n_ node.Node) (string, error) {
// Convert into fmt.Print // Convert into fmt.Print
args := make([]string, 0, len(n.Exprs)) args := make([]string, 0, len(n.Exprs))
for _, expr := range n.Exprs { for _, expr := range n.Exprs {
exprGo, err := convert(expr) exprGo, err := this.convert(expr)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -420,7 +423,7 @@ func convert(n_ node.Node) (string, error) {
case *assign.Assign: case *assign.Assign:
rvalue, err := convert(n.Expression) rvalue, err := this.convert(n.Expression)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -428,7 +431,7 @@ func convert(n_ node.Node) (string, error) {
if dimf, ok := n.Variable.(*expr.ArrayDimFetch); ok && dimf.Dim == nil { if dimf, ok := n.Variable.(*expr.ArrayDimFetch); ok && dimf.Dim == nil {
// Special handling for the case of foo[] = bar // Special handling for the case of foo[] = bar
// Transform into append() // Transform into append()
arrayVar, err := convert(dimf.Variable) arrayVar, err := this.convert(dimf.Variable)
if err != nil { if err != nil {
return "", parseErr{dimf, err} return "", parseErr{dimf, err}
} }
@ -439,7 +442,7 @@ func convert(n_ node.Node) (string, error) {
// Normal assignment // Normal assignment
lvalue, err := convert(n.Variable) // might be a more complicated lvalue lvalue, err := this.convert(n.Variable) // might be a more complicated lvalue
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -461,7 +464,7 @@ func convert(n_ node.Node) (string, error) {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
callParams, err := convertFuncCallArgsCommon(n.ArgumentList) callParams, err := this.convertFuncCallArgsCommon(n.ArgumentList)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -474,12 +477,12 @@ func convert(n_ node.Node) (string, error) {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
funcName, err := convert(n.Call) funcName, err := this.convert(n.Call)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
callParams, err := convertFuncCallArgsCommon(n.ArgumentList) callParams, err := this.convertFuncCallArgsCommon(n.ArgumentList)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -500,11 +503,11 @@ func convert(n_ node.Node) (string, error) {
// Convert resolved back to node.Name // Convert resolved back to node.Name
transparentNameNode := name.NewName([]node.Node{name.NewNamePart(nn)}) transparentNameNode := name.NewName([]node.Node{name.NewNamePart(nn)})
return convert(expr.NewFunctionCall(transparentNameNode, n.ArgumentList)) return this.convert(expr.NewFunctionCall(transparentNameNode, n.ArgumentList))
case *expr.PreInc: case *expr.PreInc:
// """In Go, i++ is a statement, not an expression. So you can't use its value in another expression such as a function call.""" // """In Go, i++ is a statement, not an expression. So you can't use its value in another expression such as a function call."""
v, err := convert(n.Variable) v, err := this.convert(n.Variable)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -513,7 +516,7 @@ func convert(n_ node.Node) (string, error) {
case *expr.PostInc: case *expr.PostInc:
// """In Go, i++ is a statement, not an expression. So you can't use its value in another expression such as a function call.""" // """In Go, i++ is a statement, not an expression. So you can't use its value in another expression such as a function call."""
v, err := convert(n.Variable) v, err := this.convert(n.Variable)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -522,17 +525,17 @@ func convert(n_ node.Node) (string, error) {
case *expr.MethodCall: case *expr.MethodCall:
// Foo->Bar(Baz) // Foo->Bar(Baz)
parent, err := convert(n.Variable) parent, err := this.convert(n.Variable)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
child, err := convert(n.Method) child, err := this.convert(n.Method)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
args, err := convertFuncCallArgsCommon(n.ArgumentList) args, err := this.convertFuncCallArgsCommon(n.ArgumentList)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -541,12 +544,12 @@ func convert(n_ node.Node) (string, error) {
case *expr.PropertyFetch: case *expr.PropertyFetch:
// Foo->Bar // Foo->Bar
parent, err := convert(n.Variable) parent, err := this.convert(n.Variable)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
child, err := convert(n.Property) child, err := this.convert(n.Property)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -560,16 +563,16 @@ func convert(n_ node.Node) (string, error) {
return resolveName(n.Constant) return resolveName(n.Constant)
case *expr.Array: case *expr.Array:
return convertArrayLiteralCommon(n.Items) return this.convertArrayLiteralCommon(n.Items)
case *expr.ShortArray: case *expr.ShortArray:
return convertArrayLiteralCommon(n.Items) return this.convertArrayLiteralCommon(n.Items)
case *expr.ArrayDimFetch: case *expr.ArrayDimFetch:
// Might be x[foo], might be x[] (i.e. append() call) // Might be x[foo], might be x[] (i.e. append() call)
// In order to make the append() transformation, we need to lookahead // In order to make the append() transformation, we need to lookahead
// for ArrayDimFetch in the `*assign.Assign` case // for ArrayDimFetch in the `*assign.Assign` case
vv, err := convert(n.Variable) vv, err := this.convert(n.Variable)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -578,7 +581,7 @@ func convert(n_ node.Node) (string, error) {
return "", parseErr{n, fmt.Errorf("found '%s[]' outside of lvalue assignment context", vv)} return "", parseErr{n, fmt.Errorf("found '%s[]' outside of lvalue assignment context", vv)}
} }
idx, err := convert(n.Dim) idx, err := this.convert(n.Dim)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -590,40 +593,40 @@ func convert(n_ node.Node) (string, error) {
// //
case *binary.BitwiseAnd: case *binary.BitwiseAnd:
return convertBinaryCommon(n.Left, n.Right, `&`) return this.convertBinaryCommon(n.Left, n.Right, `&`)
case *binary.BitwiseOr: case *binary.BitwiseOr:
return convertBinaryCommon(n.Left, n.Right, `|`) return this.convertBinaryCommon(n.Left, n.Right, `|`)
case *binary.BitwiseXor: case *binary.BitwiseXor:
return convertBinaryCommon(n.Left, n.Right, `^`) // n.b. Go only supports this for integers; PHP also supports it for bools return this.convertBinaryCommon(n.Left, n.Right, `^`) // n.b. Go only supports this for integers; PHP also supports it for bools
case *binary.BooleanAnd: case *binary.BooleanAnd:
return convertBinaryCommon(n.Left, n.Right, `&&`) return this.convertBinaryCommon(n.Left, n.Right, `&&`)
case *binary.BooleanOr: case *binary.BooleanOr:
return convertBinaryCommon(n.Left, n.Right, `||`) return this.convertBinaryCommon(n.Left, n.Right, `||`)
//case *binary.Coalesce: //case *binary.Coalesce:
// TODO this can't be expressed in an rvalue context in Go (unless we create a typed closure..?) // TODO this can't be expressed in an rvalue context in Go (unless we create a typed closure..?)
case *binary.Concat: case *binary.Concat:
return convertBinaryCommon(n.Left, n.Right, `+`) // PHP uses + for numbers, `.` for strings; Go uses `+` in both cases return this.convertBinaryCommon(n.Left, n.Right, `+`) // PHP uses + for numbers, `.` for strings; Go uses `+` in both cases
case *binary.Div: case *binary.Div:
return convertBinaryCommon(n.Left, n.Right, `/`) // PHP will upgrade ints to floats, Go won't return this.convertBinaryCommon(n.Left, n.Right, `/`) // PHP will upgrade ints to floats, Go won't
case *binary.Equal: case *binary.Equal:
return convertBinaryCommon(n.Left, n.Right, `==`) // Type-lax equality comparator return this.convertBinaryCommon(n.Left, n.Right, `==`) // Type-lax equality comparator
case *binary.GreaterOrEqual: case *binary.GreaterOrEqual:
return convertBinaryCommon(n.Left, n.Right, `>=`) return this.convertBinaryCommon(n.Left, n.Right, `>=`)
case *binary.Greater: case *binary.Greater:
return convertBinaryCommon(n.Left, n.Right, `>`) return this.convertBinaryCommon(n.Left, n.Right, `>`)
case *binary.Identical: case *binary.Identical:
return convertBinaryCommon(n.Left, n.Right, `==`) // PHP uses `===`, Go is already type-safe return this.convertBinaryCommon(n.Left, n.Right, `==`) // PHP uses `===`, Go is already type-safe
case *binary.LogicalAnd: case *binary.LogicalAnd:
// This is the lexer token when using `and` in PHP. It's equivalent to // This is the lexer token when using `and` in PHP. It's equivalent to
@ -632,27 +635,27 @@ func convert(n_ node.Node) (string, error) {
// $a = $b and $c ==> ($a = $b) and $c // $a = $b and $c ==> ($a = $b) and $c
// So far, we are relying on the PHP parser having already having handled // So far, we are relying on the PHP parser having already having handled
// the precedence difference - transform to `&&` unconditionally // the precedence difference - transform to `&&` unconditionally
return convertBinaryCommon(n.Left, n.Right, `&&`) return this.convertBinaryCommon(n.Left, n.Right, `&&`)
case *binary.LogicalOr: case *binary.LogicalOr:
// As above // As above
return convertBinaryCommon(n.Left, n.Right, `||`) return this.convertBinaryCommon(n.Left, n.Right, `||`)
case *binary.LogicalXor: case *binary.LogicalXor:
// As above // As above
return convertBinaryCommon(n.Left, n.Right, `^`) // n.b. Go only supports this for integers; PHP also supports it for bools return this.convertBinaryCommon(n.Left, n.Right, `^`) // n.b. Go only supports this for integers; PHP also supports it for bools
case *binary.Minus: case *binary.Minus:
return convertBinaryCommon(n.Left, n.Right, `-`) return this.convertBinaryCommon(n.Left, n.Right, `-`)
case *binary.Mod: case *binary.Mod:
// Go doesn't have a built-in operator for mod - convert to a call to math.Mod() // Go doesn't have a built-in operator for mod - convert to a call to math.Mod()
rval, err := convert(n.Left) rval, err := this.convert(n.Left)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
modulo, err := convert(n.Right) modulo, err := this.convert(n.Right)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -660,26 +663,26 @@ func convert(n_ node.Node) (string, error) {
return `math.Mod(` + rval + `, ` + modulo + `)`, nil return `math.Mod(` + rval + `, ` + modulo + `)`, nil
case *binary.Mul: case *binary.Mul:
return convertBinaryCommon(n.Left, n.Right, `*`) return this.convertBinaryCommon(n.Left, n.Right, `*`)
case *binary.NotEqual: case *binary.NotEqual:
return convertBinaryCommon(n.Left, n.Right, `!=`) // Type-lax equality comparator return this.convertBinaryCommon(n.Left, n.Right, `!=`) // Type-lax equality comparator
case *binary.NotIdentical: case *binary.NotIdentical:
return convertBinaryCommon(n.Left, n.Right, `!=`) // PHP uses `!==`, Go is already type-safe return this.convertBinaryCommon(n.Left, n.Right, `!=`) // PHP uses `!==`, Go is already type-safe
case *binary.Plus: case *binary.Plus:
return convertBinaryCommon(n.Left, n.Right, `+`) // PHP uses + for numbers, `.` for strings; Go uses `+` in both cases return this.convertBinaryCommon(n.Left, n.Right, `+`) // PHP uses + for numbers, `.` for strings; Go uses `+` in both cases
case *binary.Pow: case *binary.Pow:
// Go doesn't have a built-in operator for mod - convert to a call to math.Pow() // Go doesn't have a built-in operator for mod - convert to a call to math.Pow()
base, err := convert(n.Left) base, err := this.convert(n.Left)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
exponent, err := convert(n.Right) exponent, err := this.convert(n.Right)
if err != nil { if err != nil {
return "", parseErr{n, err} return "", parseErr{n, err}
} }
@ -687,16 +690,16 @@ func convert(n_ node.Node) (string, error) {
return `math.Pow(` + base + `, ` + exponent + `)`, nil return `math.Pow(` + base + `, ` + exponent + `)`, nil
case *binary.ShiftLeft: case *binary.ShiftLeft:
return convertBinaryCommon(n.Left, n.Right, `<<`) return this.convertBinaryCommon(n.Left, n.Right, `<<`)
case *binary.ShiftRight: case *binary.ShiftRight:
return convertBinaryCommon(n.Left, n.Right, `>>`) return this.convertBinaryCommon(n.Left, n.Right, `>>`)
case *binary.SmallerOrEqual: case *binary.SmallerOrEqual:
return convertBinaryCommon(n.Left, n.Right, `<=`) return this.convertBinaryCommon(n.Left, n.Right, `<=`)
case *binary.Smaller: case *binary.Smaller:
return convertBinaryCommon(n.Left, n.Right, `<`) return this.convertBinaryCommon(n.Left, n.Right, `<`)
case *binary.Spaceship: case *binary.Spaceship:
// The spaceship operator returns -1 / 0 / 1 based on a gteq/leq comparison // The spaceship operator returns -1 / 0 / 1 based on a gteq/leq comparison
@ -704,7 +707,7 @@ func convert(n_ node.Node) (string, error) {
// The primary use case is in user-definded sort comparators, where Go // The primary use case is in user-definded sort comparators, where Go
// uses bools instead ints anyway. // uses bools instead ints anyway.
// Subtraction is a reasonable substitute // Subtraction is a reasonable substitute
return convertBinaryCommon(n.Left, n.Right, `-`) return this.convertBinaryCommon(n.Left, n.Right, `-`)
// //
// scalar // scalar
@ -820,15 +823,15 @@ func convertToStmtList(n node.Node) *stmt.StmtList {
return stmt.NewStmtList([]node.Node{n}) return stmt.NewStmtList([]node.Node{n})
} }
func convertBinaryCommon(left, right node.Node, goBinaryOperator string) (string, error) { func (this *conversionState) convertBinaryCommon(left, right node.Node, goBinaryOperator string) (string, error) {
// PHP uses + for numbers, `.` for strings; Go uses `+` in both cases // PHP uses + for numbers, `.` for strings; Go uses `+` in both cases
// Assume PHP/Go have the same associativity here // Assume PHP/Go have the same associativity here
lhs, err := convert(left) lhs, err := this.convert(left)
if err != nil { if err != nil {
return "", parseErr{left, err} return "", parseErr{left, err}
} }
rhs, err := convert(right) rhs, err := this.convert(right)
if err != nil { if err != nil {
return "", parseErr{right, err} return "", parseErr{right, err}
} }
@ -836,7 +839,7 @@ func convertBinaryCommon(left, right node.Node, goBinaryOperator string) (string
return "(" + lhs + " " + goBinaryOperator + " " + rhs + ")", nil return "(" + lhs + " " + goBinaryOperator + " " + rhs + ")", nil
} }
func convertFuncCallArgsCommon(args *node.ArgumentList) (string, error) { func (this *conversionState) convertFuncCallArgsCommon(args *node.ArgumentList) (string, error) {
callParams := make([]string, 0, len(args.Arguments)) callParams := make([]string, 0, len(args.Arguments))
for _, arg_ := range args.Arguments { for _, arg_ := range args.Arguments {
@ -845,7 +848,7 @@ func convertFuncCallArgsCommon(args *node.ArgumentList) (string, error) {
return "", parseErr{arg_, fmt.Errorf("expected node.Argument")} return "", parseErr{arg_, fmt.Errorf("expected node.Argument")}
} }
rvalue, err := convert(arg.Expr) rvalue, err := this.convert(arg.Expr)
if err != nil { if err != nil {
return "", parseErr{arg, err} return "", parseErr{arg, err}
} }
@ -862,7 +865,7 @@ func convertFuncCallArgsCommon(args *node.ArgumentList) (string, error) {
return "(" + strings.Join(callParams, `, `) + ")", nil // expr only, no semicolon/newline return "(" + strings.Join(callParams, `, `) + ")", nil // expr only, no semicolon/newline
} }
func convertArrayLiteralCommon(items []node.Node) (string, error) { func (this *conversionState) convertArrayLiteralCommon(items []node.Node) (string, error) {
// Array literal // Array literal
// We need to know the type. See if we can guess it from the first child element // We need to know the type. See if we can guess it from the first child element
// At least, we may be able to determine if this is a map or an array // At least, we may be able to determine if this is a map or an array
@ -886,13 +889,13 @@ func convertArrayLiteralCommon(items []node.Node) (string, error) {
} }
} }
vv, err := convert(itm.Val) vv, err := this.convert(itm.Val)
if err != nil { if err != nil {
return "", parseErr{itm, err} return "", parseErr{itm, err}
} }
if itm.Key != nil { if itm.Key != nil {
kv, err := convert(itm.Key) kv, err := this.convert(itm.Key)
if err != nil { if err != nil {
return "", parseErr{itm, err} return "", parseErr{itm, err}
} }
@ -910,7 +913,7 @@ func convertArrayLiteralCommon(items []node.Node) (string, error) {
} }
} }
func convertFunctionCommon(params []node.Node, returnType node.Node, returnsRef bool, bodyStmts []node.Node) (string, error) { func (this *conversionState) convertFunctionCommon(params []node.Node, returnType node.Node, returnsRef bool, bodyStmts []node.Node) (string, error) {
// TODO scan function and see if it contains any return statements at all // TODO scan function and see if it contains any return statements at all
// If not, then we only need an err return parameter, not anything else // If not, then we only need an err return parameter, not anything else
@ -954,7 +957,7 @@ func convertFunctionCommon(params []node.Node, returnType node.Node, returnsRef
// Recurse through body statements // Recurse through body statements
fullBody, err := convert(stmt.NewStmtList(bodyStmts)) fullBody, err := this.convert(stmt.NewStmtList(bodyStmts))
if err != nil { if err != nil {
return "", err return "", err
} }