Skip to content

Commit

Permalink
Fix parsing of for (( )) loops.
Browse files Browse the repository at this point in the history
We weren't properly accounting for spaces in the conditions.

This was caught by a 'bashdb' source file with an empty initial
condition.

Added tests.
  • Loading branch information
Andy Chu committed Aug 25, 2018
1 parent 2bba597 commit 25ef33c
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 20 deletions.
19 changes: 12 additions & 7 deletions osh/word_parse.py
Expand Up @@ -846,33 +846,38 @@ def ReadDParen(self):

return anode

def _NextNonSpace(self):
"""Same logic as _ReadWord, but for ReadForExpresion."""
while True:
self._Next(lex_mode_e.ARITH)
self._Peek()
if self.token_kind not in (Kind.Ignored, Kind.WS):
break

def ReadForExpression(self):
"""Read ((i=0; i<5; ++i)) -- part of command context."""
# No PushHint because we're in arith state.
#self.lexer.PushHint(Id.Op_RParen, Id.Op_DRightParen)

self._Next(lex_mode_e.ARITH) # skip over ((
self._NextNonSpace() # skip over ((

self._Peek()
if self.token_type == Id.Arith_Semi: # for (( ; i < 10; i++ ))
init_node = None
else:
init_node = self._ReadArithExpr(do_next=False)
self._Next(lex_mode_e.ARITH)
self._NextNonSpace()

self._Peek()
if self.token_type == Id.Arith_Semi: # for (( ; ; i++ ))
cond_node = None
else:
cond_node = self._ReadArithExpr(do_next=False)
self._Next(lex_mode_e.ARITH)
self._NextNonSpace()

self._Peek()
if self.token_type == Id.Arith_RParen: # for (( ; ; ))
update_node = None
else:
update_node = self._ReadArithExpr(do_next=False)
self._Next(lex_mode_e.ARITH)
self._NextNonSpace()

self._Peek()
if self.token_type != Id.Arith_RParen:
Expand Down
48 changes: 36 additions & 12 deletions spec/for-expr.test.sh
Expand Up @@ -14,23 +14,22 @@ do
break
fi
echo $a
done # A construct borrowed from ksh93.
done
## status: 0
## STDOUT:
1
2
4
5
## N-I mksh status: 1
## N-I mksh stdout-json: ""
## END

#### For loop with and without semicolon
for ((a=1; a <= 3; a++)); do
echo $a
done # A construct borrowed from ksh93.
done
for ((a=1; a <= 3; a++)) do
echo $a
done # A construct borrowed from ksh93.
done
## status: 0
## STDOUT:
1
Expand All @@ -39,21 +38,46 @@ done # A construct borrowed from ksh93.
1
2
3
## N-I mksh status: 1
## N-I mksh stdout-json: ""
## END

#### For loop with empty head
#### Empty init
i=1
for (( ;i < 4; i++ )); do
echo $i
done
## status: 0
## STDOUT:
1
2
3
## END

#### Empty init and cond
i=1
for (( ; ; i++ )); do
if test $i = 4; then
break
fi
echo $i
done
## status: 0
## STDOUT:
1
2
3
## END

#### Infinite loop with ((;;))
a=1
for ((;;)); do
for (( ; ; )); do
if test $a = 4; then
break
fi
echo $((a++))
done # A construct borrowed from ksh93.
done
## status: 0
## STDOUT:
1
2
3
## N-I mksh status: 1
## N-I mksh stdout-json: ""
## END
2 changes: 1 addition & 1 deletion test/spec.sh
Expand Up @@ -591,7 +591,7 @@ let() {

for-expr() {
sh-spec spec/for-expr.test.sh \
$MKSH $BASH $OSH "$@"
$BASH $ZSH $OSH "$@"
}

empty-bodies() {
Expand Down

0 comments on commit 25ef33c

Please sign in to comment.