node: implement switch, break, continue (basic)

This commit is contained in:
mappu 2020-04-12 14:41:23 +12:00
parent cbcfb46de7
commit 78bd54ad13
2 changed files with 79 additions and 0 deletions

16
fixtures/0014-switch.php Normal file
View File

@ -0,0 +1,16 @@
<?php
$x = true;
switch($x) {
case true:
echo "true";
break;
echo "unreached";
case false:
echo "false";
// fallthrough
default:
echo "default";
}

63
node.go
View File

@ -845,6 +845,69 @@ func (this *conversionState) convertNoFreeFloating(n_ node.Node) (string, error)
return ret, nil
case *stmt.Switch:
cond, err := this.convert(n.Cond)
if err != nil {
return "", parseErr{n, err}
}
cases := make([]string, 0, len(n.CaseList.Cases))
for _, ncase := range n.CaseList.Cases {
switch ncase.(type) {
case *stmt.Default, *stmt.Case:
caseStr, err := this.convert(ncase)
if err != nil {
return "", parseErr{n, err}
}
cases = append(cases, caseStr)
default:
return "", parseErr{ncase, fmt.Errorf("expected Case/Default")}
}
}
// TODO use dead code elimination after `break` to clean up redundant fallthrough statements
return "switch " + cond + " {\n" + strings.Join(cases, "\n") + "}\n", nil
case *stmt.Case:
// Add a `fallthrough` to the end
// TODO then use dead code elimination to clean them up
stmtBody, err := this.convert(stmt.NewStmtList(n.Stmts))
if err != nil {
return "", parseErr{n, err}
}
cond, err := this.convert(n.Cond)
if err != nil {
return "", parseErr{n, err}
}
return "case " + cond + ":\n" + stmtBody + "\nfallthrough\n", nil
case *stmt.Default:
// Add a `fallthrough` to the end
// TODO then use dead code elimination to clean them up
stmtBody, err := this.convert(stmt.NewStmtList(n.Stmts))
if err != nil {
return "", parseErr{n, err}
}
return "default: " + stmtBody + "\nfallthrough\n", nil
case *stmt.Break:
if n.Expr != nil {
return "", parseErr{n, fmt.Errorf("break {expr} is not yet supported")} // TODO implement numbered break
}
return "break\n", nil
case *stmt.Continue:
if n.Expr != nil {
return "", parseErr{n, fmt.Errorf("continue {expr} is not yet supported")} // TODO implement numbered continue
}
return "continue\n", nil
case *stmt.Try:
// Generate an if err != nil {} block that we can bring up whenever