Permalink
Browse files

Change WordParser.ReadWord to throw an exception.

BoolParser now consumes it like this, and is greatly simplified.

Addresses issue #103.
  • Loading branch information...
Andy Chu
Andy Chu committed Aug 22, 2018
1 parent 1644279 commit 79c4bbdd9ba8536808a227a26518f93a43976ceb
Showing with 24 additions and 34 deletions.
  1. +21 −33 osh/bool_parse.py
  2. +3 −1 osh/word_parse.py
View
@@ -65,25 +65,21 @@ def __init__(self, w_parser):
self.error_stack = []
def _NextOne(self, lex_mode=lex_mode_e.DBRACKET):
#print('_Next', self.cur_word)
n = len(self.words)
if n == 2:
assert lex_mode == lex_mode_e.DBRACKET
self.words[0] = self.words[1]
self.cur_word = self.words[0]
del self.words[1]
elif n in (0, 1):
w = self.w_parser.ReadWord(lex_mode)
if not w:
err = self.w_parser.Error()
self.error_stack.extend(err)
return False
w = self.w_parser.ReadWord(lex_mode) # may raise
if n == 0:
self.words.append(w)
else:
self.words[0] = w
self.cur_word = w
assert self.cur_word is not None
self.op_id = word.BoolId(self.cur_word)
self.b_kind = LookupKind(self.op_id)
#log('--- word %s', self.cur_word)
@@ -98,9 +94,7 @@ def _Next(self, lex_mode=lex_mode_e.DBRACKET):
it's Id.WS_Newline -- we might have to unread tokens, etc.
"""
while True:
w = self._NextOne(lex_mode=lex_mode)
if not w:
return False
self._NextOne(lex_mode=lex_mode)
if self.op_id != Id.Op_Newline:
break
return True
@@ -110,12 +104,12 @@ def _LookAhead(self):
if n != 1:
raise AssertionError(self.words)
w = self.w_parser.ReadWord(lex_mode_e.DBRACKET)
w = self.w_parser.ReadWord(lex_mode_e.DBRACKET) # may raise
self.words.append(w) # Save it for _Next()
return w
def Parse(self):
if not self._Next(): return None
self._Next()
node = self.ParseExpr()
if self.op_id != Id.Lit_DRightBracket:
@@ -131,7 +125,7 @@ def _TestAtEnd(self):
def ParseForBuiltin(self):
"""For test builtin."""
if not self._Next(): return None
self._Next()
node = self.ParseExpr()
if self.op_id != Id.Eof_Real:
@@ -149,13 +143,10 @@ def ParseExpr(self):
Expr : Term (OR Expr)?
"""
left = self.ParseTerm()
if not left:
return None # TODO: An exception should handle this case.
# [[ uses || while [ uses -o
# [[ uses || but [ uses -o
if self.op_id in (Id.Op_DPipe, Id.BoolUnary_o):
if not self._Next(): return None
self._Next()
right = self.ParseExpr()
if not right: return None
return ast.LogicalOr(left, right)
else:
return left
@@ -168,13 +159,10 @@ def ParseTerm(self):
Term : Negated (AND Term)?
"""
left = self.ParseNegatedFactor()
if not left:
return None # TODO: An exception should handle this case.
# [[ uses && while [ uses -a
# [[ uses && but [ uses -a
if self.op_id in (Id.Op_DAmp, Id.BoolUnary_a):
if not self._Next(): return None
self._Next()
right = self.ParseTerm()
if not right: return None
return ast.LogicalAnd(left, right)
else:
return left
@@ -184,9 +172,8 @@ def ParseNegatedFactor(self):
Negated : '!'? Factor
"""
if self.op_id == Id.KW_Bang:
if not self._Next(): return None
self._Next()
child = self.ParseFactor()
if not child: return None
return ast.LogicalNot(child)
else:
return self.ParseFactor()
@@ -201,9 +188,9 @@ def ParseFactor(self):
if self.b_kind == Kind.BoolUnary:
# Just save the type and not the token itself?
op = self.op_id
if not self._Next(): return None
self._Next()
w = self.cur_word
if not self._Next(): return None
self._Next()
node = ast.BoolUnary(op, w)
return node
@@ -218,16 +205,16 @@ def ParseFactor(self):
if t2_b_kind in (Kind.BoolBinary, Kind.Redir):
left = self.cur_word
if not self._Next(): return None
self._Next()
op = self.op_id
# TODO: Need to change to lex_mode_e.BASH_REGEX.
# _Next(lex_mode) then?
is_regex = t2_op_id == Id.BoolBinary_EqualTilde
if is_regex:
if not self._Next(lex_mode=lex_mode_e.BASH_REGEX): return None
self._Next(lex_mode=lex_mode_e.BASH_REGEX)
else:
if not self._Next(): return None
self._Next()
right = self.cur_word
if is_regex:
@@ -238,24 +225,25 @@ def ParseFactor(self):
ok, regex_str, unused_quoted = word.StaticEval(right)
# TODO: Should raise exception with error?
# doesn't contain $foo, etc.
if ok and not libc.regex_parse(regex_str):
p_die("Invalid regex: %r" % regex_str, word=right)
if not self._Next(): return None
self._Next()
return ast.BoolBinary(op, left, right)
else:
# [[ foo ]]
w = self.cur_word
if not self._Next(): return None
self._Next()
return ast.WordTest(w)
if self.op_id == Id.Op_LParen:
if not self._Next(): return None
self._Next()
node = self.ParseExpr()
if self.op_id != Id.Op_RParen:
p_die('Expected ), got %s', self.cur_word, word=self.cur_word)
if not self._Next(): return None
self._Next()
return node
# It's not WORD, UNARY_OP, or '('
View
@@ -1215,8 +1215,10 @@ def ReadWord(self, lex_mode):
if not need_more:
break
# TODO: Just let it raise
if not w: # Assumes AddErrorContext was already called
return None
error_stack = self.Error()
p_die('ReadWord: %s', error_stack[-1])
self.cursor = w

0 comments on commit 79c4bbd

Please sign in to comment.