def bql_string_complete_p(string): """True if `string` has at least one complete BQL phrase or error. False if empty or if the last BQL phrase is incomplete. """ scanner = scan.BQLScanner(StringIO.StringIO(string), '(string)') semantics = BQLSemantics() parser = grammar.Parser(semantics) nonsemi = False while not semantics.failed: token = scanner.read() if token[0] == -1: # error # Say it's complete so the caller will try to parse it and # choke on the error. return True elif token[0] == 0: # EOF. Hope we have a complete phrase. break elif token[0] != grammar.T_SEMI: # Got a non-semicolon token. Clear any previous phrase, # if we had one. nonsemi = True semantics.phrase = None parser.feed(token) if 0 < len(semantics.errors): return True if semantics.failed: return True return (not nonsemi) or (semantics.phrase is not None)
def parse_bql_phrases(scanner): semantics = BQLSemantics() parser = grammar.Parser(semantics) while not semantics.failed: token = scanner.read() semantics.context.append(token) if token[0] == -1: # error semantics.syntax_error(token) else: if token[0] == 0: # EOF # Implicit ; at EOF. parser.feed((grammar.T_SEMI, '')) parser.feed(token) if semantics.phrase is not None: phrase = semantics.phrase semantics.phrase = None if 0 < len(semantics.errors): # Keep parsing in order to detect more errors, but # don't yield any broken phrases in case the caller # will try to process them before we finish parsing # the whole thing. continue if 0 < scanner.n_numpar: n_numpar = scanner.n_numpar nampar_map = scanner.nampar_map yield ast.Parametrized(phrase, n_numpar, nampar_map) else: yield phrase if token[0] == 0: # EOF break if 0 < len(semantics.errors): raise BQLParseError(semantics.errors) if semantics.failed: raise BQLParseError(['parse failed mysteriously!'])