Permalink
Browse files

Clean up more word_parse.py error cases.

- Arithmetic errors
- Extended glob
- Double-quoted string
- Single-quoted string.  Now points to left token like " did.

Addresses issue #27 and #103.
  • Loading branch information...
Andy Chu
Andy Chu committed Aug 21, 2018
1 parent 82f52d8 commit 23906a3d1f1ad6cd1e6864ccc0396f8ac1387cb5
Showing with 65 additions and 33 deletions.
  1. +22 −30 osh/word_parse.py
  2. +43 −3 test/parse-errors.sh
View
@@ -340,6 +340,7 @@ def _ParseVarExpr(self, arg_lex_mode):
op_id = self.token_type
arg_word = self._ReadVarOpArg(arg_lex_mode)
if self.token_type != Id.Right_VarSub:
# NOTE: Not sure how to tickle this. May not be possible.
self._BadToken('Unexpected token after unary op: %s', self.cur_token)
return None
@@ -373,7 +374,7 @@ def _ParseVarExpr(self, arg_lex_mode):
# mode. It's redundantly checked above.
if self.token_type not in (Id.Right_VarSub, Id.Arith_RBrace):
# ${a.} or ${!a.}
p_die('Unexpected token after var sub: %r', self.cur_token.val,
p_die('Expected } after var sub, got %r', self.cur_token.val,
token=self.cur_token)
# Now look for ops
@@ -460,9 +461,8 @@ def _ReadBracedBracedVarSub(self, d_quoted=False):
self._Peek()
if self.token_type != Id.Right_VarSub:
self._BadToken("Expected } after length expression, got %r",
self.cur_token)
return None
p_die("Expected } after length expression, got %r",
self.cur_token.val, token=self.cur_token)
part.prefix_op = Id.VSub_Pound # length
@@ -521,8 +521,8 @@ def _ReadSingleQuotedPart(self, lex_mode):
tokens.append(self.cur_token)
elif self.token_kind == Kind.Eof:
self.AddErrorContext('Unexpected EOF in single-quoted string')
return False
p_die('Unexpected EOF in single-quoted string that began here',
token=left)
elif self.token_kind == Kind.Right:
done = True # assume Id.Right_SingleQuote
@@ -625,10 +625,8 @@ def _ReadExtGlobPart(self):
read_word = True
elif self.token_kind == Kind.Eof:
self.AddErrorContext(
'Unexpected EOF reading extended glob that began here',
token=left_token)
return None
p_die('Unexpected EOF reading extended glob that began here',
token=left_token)
else:
raise AssertionError('Unexpected token %r' % self.cur_token)
@@ -648,7 +646,7 @@ def _ReadDoubleQuotedPart(self, eof_type=Id.Undefined_Tok, here_doc=False):
right_spid = const.NO_INTEGER # gets set later
if self.cur_token is not None: # None in here doc case
left_spid = self.cur_token.span_id
left_token = self.cur_token
done = False
while not done:
@@ -690,10 +688,8 @@ def _ReadDoubleQuotedPart(self, eof_type=Id.Undefined_Tok, here_doc=False):
if here_doc: # here docs will have an EOF in their token stream
done = True
else:
self.AddErrorContext(
'Unexpected EOF reading double-quoted string that began here',
span_id=left_spid)
return False
p_die('Unexpected EOF reading double-quoted string that began here',
token=left_token)
else:
raise AssertionError(self.cur_token)
@@ -800,19 +796,18 @@ def _ReadArithSubPart(self):
return None
if self.token_type != Id.Arith_RParen:
self._BadToken('Expected first paren to end arith sub, got %s',
self.cur_token)
return None
p_die('Expected first ) to end arith sub, got %r', self.cur_token.val,
token=self.cur_token)
self._Next(lex_mode_e.OUTER) # TODO: This could be DQ or ARITH too
# PROBLEM: $(echo $(( 1 + 2 )) )
# Two right parens break the Id.Eof_RParen scheme
self._Peek()
if self.token_type != Id.Right_ArithSub:
self._BadToken('Expected second paren to end arith sub, got %s',
self.cur_token)
return None
p_die('Expected second ) to end arith sub, got %r', self.cur_token.val,
token=self.cur_token)
right_span_id = self.cur_token.span_id
node = ast.ArithSubPart(anode)
@@ -857,17 +852,15 @@ def ReadDParen(self):
#print('xx ((', self.cur_token)
if self.token_type != Id.Arith_RParen:
self._BadToken('Expected first paren to end arith sub, got %s',
self.cur_token)
return None
p_die('Expected first ) to end arith statement, got %r',
self.cur_token.val, token=self.cur_token)
self._Next(lex_mode_e.OUTER)
# PROBLEM: $(echo $(( 1 + 2 )) )
self._Peek()
if self.token_type != Id.Op_DRightParen:
self._BadToken('Expected second paren to end arith sub, got %s',
self.cur_token)
return None
p_die('Expected second ) to end arith statement, got %r',
self.cur_token.val, token=self.cur_token)
self._Next(lex_mode_e.OUTER)
return anode
@@ -921,9 +914,8 @@ def ReadForExpression(self):
# Second paren
self._Peek()
if self.token_type != Id.Arith_RParen:
self._BadToken('Expected right paren to end for loop expression, got %s',
self.cur_token)
return None
p_die('Expected ) to end for loop expression, got %r',
self.cur_token.val, token=self.cur_token)
self._Next(lex_mode_e.OUTER)
return ast.ForExpr(init_node, cond_node, update_node)
View
@@ -55,13 +55,51 @@ word-parse() {
_error-case 'echo ${x.}'
_error-case 'echo ${!x.}'
# NOTE: This is because of EOF
# Slicing
_error-case 'echo ${a:1;}'
# NOTE: Doesn't point to X
_error-case 'echo ${a:1:2;}'
# I don't seem to be able to tickle errors here
#_error-case 'echo ${a:-}'
#_error-case 'echo ${a#}'
_error-case 'echo ${#a.'
# $(( ))
_error-case 'echo $(( 1 + 2 ;'
_error-case 'echo $(( 1 + 2 );'
# (( ))
_error-case '(( 1 + 2 /'
_error-case '(( 1 + 2 )/'
# for (( ))
_error-case 'for (( i = 0; i < 10; i++ ;'
# Hm not sure about this
_error-case 'for (( i = 0; i < 10; i++ /'
_error-case 'echo @(extglob|foo'
}
quoted-strings() {
set +o errexit
_error-case '"unterminated double'
_error-case "'unterminated single"
_error-case '
"unterminated double multiline
line 1
line 2'
_error-case "
'unterminated single multiline
line 1
line 2"
}
cases-in-strings() {
set +o errexit
@@ -73,6 +111,8 @@ cases-in-strings() {
patsub
word-parse
quoted-strings
}
# Cases in their own file

0 comments on commit 23906a3

Please sign in to comment.