Skip to content

Commit

Permalink
Clean up more word_parse.py error cases.
Browse files Browse the repository at this point in the history
- 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 committed Aug 21, 2018
1 parent 82f52d8 commit 23906a3
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 33 deletions.
52 changes: 22 additions & 30 deletions osh/word_parse.py
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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:
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
46 changes: 43 additions & 3 deletions test/parse-errors.sh
Expand Up @@ -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

Expand All @@ -73,6 +111,8 @@ cases-in-strings() {

patsub
word-parse

quoted-strings
}

# Cases in their own file
Expand Down

0 comments on commit 23906a3

Please sign in to comment.