Skip to content

Commit 9c607fe

Browse files
committed
Fix the return keyword inside loops
1 parent 2fa4e45 commit 9c607fe

File tree

2 files changed

+98
-20
lines changed

2 files changed

+98
-20
lines changed

internal/sh/shell.go

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,7 @@ func (sh *Shell) executeNode(node ast.Node, builtin bool) (*Obj, error) {
646646
// invocation ignoring output
647647
_, err = sh.executeFnInv(node.(*ast.FnInvNode))
648648
case ast.NodeFor:
649-
err = sh.executeFor(node.(*ast.ForNode))
649+
obj, err = sh.executeFor(node.(*ast.ForNode))
650650
case ast.NodeBindFn:
651651
err = sh.executeBindFn(node.(*ast.BindFnNode))
652652
case ast.NodeDump:
@@ -1658,22 +1658,35 @@ func (sh *Shell) executeFnInv(n *ast.FnInvNode) (*Obj, error) {
16581658
return fn.Results(), nil
16591659
}
16601660

1661-
func (sh *Shell) executeInfLoop(tr *ast.Tree) error {
1662-
var err error
1661+
func (sh *Shell) executeInfLoop(tr *ast.Tree) (*Obj, error) {
1662+
var (
1663+
err error
1664+
obj *Obj
1665+
)
16631666

16641667
for {
1665-
_, err = sh.executeTree(tr, true)
1668+
obj, err = sh.executeTree(tr, false)
16661669

16671670
runtime.Gosched()
16681671

1669-
type interruptedError interface {
1670-
Interrupted() bool
1671-
}
1672+
type (
1673+
interruptedError interface {
1674+
Interrupted() bool
1675+
}
1676+
1677+
stopWalkingError interface {
1678+
StopWalking() bool
1679+
}
1680+
)
16721681

16731682
if errInterrupted, ok := err.(interruptedError); ok && errInterrupted.Interrupted() {
16741683
break
16751684
}
16761685

1686+
if errStopWalking, ok := err.(stopWalkingError); ok && errStopWalking.StopWalking() {
1687+
return obj, err
1688+
}
1689+
16771690
sh.Lock()
16781691

16791692
if sh.getIntr() {
@@ -1693,10 +1706,10 @@ func (sh *Shell) executeInfLoop(tr *ast.Tree) error {
16931706
}
16941707
}
16951708

1696-
return err
1709+
return nil, err
16971710
}
16981711

1699-
func (sh *Shell) executeFor(n *ast.ForNode) error {
1712+
func (sh *Shell) executeFor(n *ast.ForNode) (*Obj, error) {
17001713
sh.Lock()
17011714
sh.looping = true
17021715
sh.Unlock()
@@ -1720,24 +1733,34 @@ func (sh *Shell) executeFor(n *ast.ForNode) error {
17201733
obj, err := sh.evalVariable(argVar)
17211734

17221735
if err != nil {
1723-
return err
1736+
return nil, err
17241737
}
17251738

17261739
if obj.Type() != ListType {
1727-
return errors.NewError("Invalid variable type in for range: %s", obj.Type())
1740+
return nil, errors.NewError("Invalid variable type in for range: %s", obj.Type())
17281741
}
17291742

17301743
for _, val := range obj.List() {
17311744
sh.Setvar(id, val)
17321745

1733-
obj, err = sh.executeTree(n.Tree(), true)
1746+
obj, err = sh.executeTree(n.Tree(), false)
17341747

1735-
type interruptedError interface {
1736-
Interrupted() bool
1737-
}
1748+
type (
1749+
interruptedError interface {
1750+
Interrupted() bool
1751+
}
1752+
1753+
stopWalkingError interface {
1754+
StopWalking() bool
1755+
}
1756+
)
17381757

17391758
if errInterrupted, ok := err.(interruptedError); ok && errInterrupted.Interrupted() {
1740-
return err
1759+
return nil, err
1760+
}
1761+
1762+
if errStopWalking, ok := err.(stopWalkingError); ok && errStopWalking.StopWalking() {
1763+
return obj, err
17411764
}
17421765

17431766
sh.Lock()
@@ -1747,20 +1770,20 @@ func (sh *Shell) executeFor(n *ast.ForNode) error {
17471770
sh.Unlock()
17481771

17491772
if err != nil {
1750-
return newErrInterrupted(err.Error())
1773+
return nil, newErrInterrupted(err.Error())
17511774
}
17521775

1753-
return newErrInterrupted("loop interrupted")
1776+
return nil, newErrInterrupted("loop interrupted")
17541777
}
17551778

17561779
sh.Unlock()
17571780

17581781
if err != nil {
1759-
return err
1782+
return nil, err
17601783
}
17611784
}
17621785

1763-
return nil
1786+
return nil, nil
17641787
}
17651788

17661789
func (sh *Shell) executeFnDecl(n *ast.FnDeclNode) error {

internal/sh/shell_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,61 @@ echo -n $res`)
12941294
t.Errorf("Expected '1' but got '%s'", got)
12951295
return
12961296
}
1297+
1298+
out.Reset()
1299+
1300+
err = sh.Exec("ret from for", `fn test() {
1301+
values = (0 1 2 3 4 5 6 7 8 9)
1302+
1303+
for i in $values {
1304+
if $i == "5" {
1305+
return $i
1306+
}
1307+
}
1308+
1309+
return "0"
1310+
}
1311+
a <= test()
1312+
echo -n $a`)
1313+
1314+
if err != nil {
1315+
t.Error(err)
1316+
return
1317+
}
1318+
1319+
got = string(out.Bytes())
1320+
1321+
if "5" != got {
1322+
t.Errorf("Expected '5' but got '%s'", got)
1323+
return
1324+
}
1325+
1326+
out.Reset()
1327+
1328+
err = sh.Exec("inf loop ret", `fn test() {
1329+
for {
1330+
if "1" == "1" {
1331+
return "1"
1332+
}
1333+
}
1334+
1335+
# never happen
1336+
return "bleh"
1337+
}
1338+
a <= test()
1339+
echo -n $a`)
1340+
1341+
if err != nil {
1342+
t.Error(err)
1343+
return
1344+
}
1345+
1346+
got = string(out.Bytes())
1347+
1348+
if got != "1" {
1349+
t.Errorf("Expected '1' but got '%s'", got)
1350+
return
1351+
}
12971352
}
12981353

12991354
func TestExecuteFnAsFirstClass(t *testing.T) {

0 commit comments

Comments
 (0)