Permalink
Browse files

Simplify error handling.

- Remove unneeded None checks.
- Arithmetic word parsing raises exceptions.

Addresses issue #27 and #103.
  • Loading branch information...
Andy Chu
Andy Chu committed Aug 23, 2018
1 parent 423d220 commit 026429216630077564759297a9c2aeada4887694
Showing with 15 additions and 29 deletions.
  1. +1 −0 core/completion_test.py
  2. +1 −1 osh/cmd_parse.py
  3. +8 −28 osh/word_parse.py
  4. +5 −0 test/parse-errors.sh
View
@@ -268,6 +268,7 @@ def testCommandSub(self):
# CommandSubPart
print(f('echo $('))
print(f('echo $(ls '))
print(f('echo $(ls foo'))
#print(f('echo `'))
#print(f('echo `ls '))
View
@@ -1498,7 +1498,7 @@ def ParseWholeFile(self):
# This calls ParseAndOr(), but I think it should be a loop that calls
# ParseCommandLine(), like oil.InteractiveLoop.
node = self.ParseCommandTerm()
if node is None: return None
assert node is not None
assert node is not False
return node
View
@@ -276,8 +276,6 @@ def _ReadSubscript(self):
self._Peek()
else:
anode = self._ReadArithExpr()
if not anode:
return None
op = ast.ArrayIndex(anode)
if self.token_type != Id.Arith_RBracket: # Should be looking at ]
@@ -723,15 +721,7 @@ def _ReadCommandSubPart(self, token_type):
c_parser = parse_lib.MakeParserForCommandSub(self.line_reader, self.lexer)
node = c_parser.ParseWholeFile() # `` and $() allowed
if not node:
# Example of parse error:
# echo $(cat |) OR
# echo `cat |`
error_stack = c_parser.Error()
self.error_stack.extend(error_stack)
print(self.error_stack)
self.AddErrorContext('Error parsing commmand list in command sub')
return None
assert node is not None
# Hm this creates its own word parser, which is thrown away?
#print('X', self.cur_token)
@@ -789,10 +779,6 @@ def _ReadArithSubPart(self):
# $((echo / foo)) # looks like division
anode = self._ReadArithExpr()
if not anode:
self.AddErrorContext("Error parsing arith sub part")
return None
if self.token_type != Id.Arith_RParen:
p_die('Expected first ) to end arith sub, got %r', self.cur_token.val,
token=self.cur_token)
@@ -818,10 +804,6 @@ def _ReadArithSub2Part(self):
left_span_id = self.cur_token.span_id
anode = self._ReadArithExpr()
if not anode:
self.AddErrorContext("Error parsing arith sub part")
return None
if self.token_type != Id.Arith_RBracket:
p_die('Expected ], got %r', self.cur_token.val, token=self.cur_token)
@@ -1040,14 +1022,11 @@ def _ReadCompoundWord(self, eof_type=Id.Undefined_Tok,
def _ReadArithWord(self):
"""Helper function for ReadArithWord."""
#assert self.token_type != Id.Undefined_Tok
self._Peek()
#print('_ReadArithWord', self.cur_token)
if self.token_kind == Kind.Unknown:
self.AddErrorContext("Unknown token in arith context: %s",
self.cur_token, token=self.cur_token)
return None, False
p_die('Unexpected token in arithmetic context', token=self.cur_token)
elif self.token_kind == Kind.Eof:
# Just return EOF token
@@ -1079,8 +1058,7 @@ def _ReadArithWord(self):
return w, False
else:
self._BadToken("Unexpected token parsing arith sub: %s", self.cur_token)
return None, False
assert False, ("Unexpected token parsing arith sub: %s", self.cur_token)
raise AssertionError("Shouldn't get here")
@@ -1192,8 +1170,10 @@ def ReadWord(self, lex_mode):
if not need_more:
break
# TODO: Just let it raise
if not w: # Assumes AddErrorContext was already called
# TODO: Change the interface of _ReadArithWord and _ReadWord.
# Error cases should raise ParseError.
# Then they should return either the word, or None to try again?
if not w:
error_stack = self.Error()
p_die('ReadWord: %s', error_stack[-1])
View
@@ -125,6 +125,11 @@ arith-expr() {
# Triggered a crash!
_error-case '$(( - ; ))'
# NOTE: This is confusing, should point to ` for command context?
_error-case '$(( ` ))'
_error-case '$(( $ ))'
}
bool-expr() {

0 comments on commit 0264292

Please sign in to comment.