Permalink
Browse files
Fix parsing of for (( )) loops.
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...
Showing
with
49 additions
and
20 deletions.
-
+12
−7
osh/word_parse.py
-
+36
−12
spec/for-expr.test.sh
-
+1
−1
test/spec.sh
|
|
@@ -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:
|
|
|
|
|
|
@@ -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
|
|
|
@@ -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
|
|
|
@@ -591,7 +591,7 @@ let() { |
|
|
|
|
|
for-expr() {
|
|
|
sh-spec spec/for-expr.test.sh \
|
|
|
$MKSH $BASH $OSH "$@"
|
|
|
$BASH $ZSH $OSH "$@"
|
|
|
}
|
|
|
|
|
|
empty-bodies() {
|
|
|
|
0 comments on commit
25ef33c