diff --git a/fixtures/0002-loops.php b/fixtures/0002-loops.php index 31319f3..998acea 100644 --- a/fixtures/0002-loops.php +++ b/fixtures/0002-loops.php @@ -19,3 +19,7 @@ for($i = 0; $i < 3; ++$i) { // Loop with no separate body statement while (true) echo "hello"; + +// Loop with multiple initialiser conditions +for ($i = 0, $e = 3; $i < $e; ++$i) { +} diff --git a/node.go b/node.go index d4d23e3..a89a88b 100644 --- a/node.go +++ b/node.go @@ -233,16 +233,32 @@ func convert(n_ node.Node) (string, error) { return "return nil, " + child + "\n", nil case *stmt.For: - if len(n.Init) != 1 { + + var preinit, finit string + var err error = nil + + if len(n.Init) == 0 { + // No initialiser in loop + + } else if len(n.Init) == 1 { + finit, err = convert(n.Init[0]) + if err != nil { + return "", parseErr{n, err} + } + + } else { // We can handle the case of multiple init statements by hoisting them // above the loop. There is no negative impact on PHP scoping rules, but // it may cause an extra local variable after the loop that may result // in type mismatch (can be fixed by using an extra scope). - return "", parseErr{n, fmt.Errorf("for loop can only have 1 init clause, found %d", len(n.Init))} - } - finit, err := convert(n.Init[0]) - if err != nil { - return "", parseErr{n, err} + for _, initStmt := range n.Init { + singleInitStmt, err := convert(initStmt) + if err != nil { + return "", parseErr{initStmt, err} + } + + preinit += singleInitStmt + "\n" + } } if len(n.Cond) != 1 { @@ -275,7 +291,7 @@ func convert(n_ node.Node) (string, error) { return "", parseErr{n, err} } - return "for " + finit + "; " + fcond + "; " + floop + " " + body + "\n", nil + return preinit + "for " + finit + "; " + fcond + "; " + floop + " " + body + "\n", nil case *stmt.Foreach: iterand, err := convert(n.Expr)