def _parse_set_seq(self, delimiters, tokens: abc.Generator) -> list: """The internal parsing of PVL Sets and Sequences are very similar, and this function provides that shared logic. *delimiters* are a two-tuple containing the start and end characters for the PVL Set or Sequence. """ t = next(tokens) if t != delimiters[0]: tokens.send(t) raise ValueError(f'Expecting a begin delimiter "{delimiters[0]}" ' f'but found: "{t}"') set_seq = list() # Initial WSC and/or empty if self.parse_WSC_until(delimiters[1], tokens): return set_seq # First item: set_seq.append(self.parse_value(tokens)) if self.parse_WSC_until(delimiters[1], tokens): return set_seq # Remaining items, if any for t in tokens: # print(f'in loop, t: {t}, set_seq: {set_seq}') if t == ',': self.parse_WSC_until(None, tokens) # consume WSC after ',' set_seq.append(self.parse_value(tokens)) if self.parse_WSC_until(delimiters[1], tokens): return set_seq else: tokens.send(t) tokens.throw(ValueError, 'While parsing, expected a comma (,)' f'but found: "{t}"')
def parse_module(self, tokens: abc.Generator): """Parses the tokens for a PVL Module. <PVL-Module-Contents> ::= ( <Assignment-Statement> | <WSC>* | <Aggregation-Block> )* [<End-Statement>] """ m = self.modcls() parsing = True while parsing: # print(f'top of while parsing: {m}') parsing = False for p in ( self.parse_aggregation_block, self.parse_assignment_statement, self.parse_end_statement, ): try: self.parse_WSC_until(None, tokens) # t = next(tokens) # print(f'next token: {t}, {t.pos}') # tokens.send(t) parsed = p(tokens) # print(f'parsed: {parsed}') if parsed is None: # because parse_end_statement returned return m else: m.append(*parsed) parsing = True except LexerError: raise except ValueError: pass try: (m, keep_parsing) = self.parse_module_post_hook(m, tokens) if keep_parsing: parsing = True else: return m except Exception: pass # print(f'got to bottom: {m}') t = next(tokens) tokens.throw( ValueError, "Expecting an Aggregation Block, an Assignment " "Statement, or an End Statement, but found " f'"{t}" ', )
def parse_end_aggregation( self, begin_agg: str, block_name: str, tokens: abc.Generator ) -> None: """Parses the tokens for an End Aggregation Statement. <End-Aggregation-Statement-block> ::= <End-Aggegation-Statement> [<WSC>* '=' <WSC>* <Block-Name>] [<Statement-Delimiter>] Where <Block-Name> ::= <Parameter-Name> """ end_agg = next(tokens) # Need to do a little song and dance to case-independently # match the keys: for k in self.grammar.aggregation_keywords.keys(): if k.casefold() == begin_agg.casefold(): truecase_begin = k break if ( end_agg.casefold() != self.grammar.aggregation_keywords[truecase_begin].casefold() ): tokens.send(end_agg) raise ValueError( "Expecting an End-Aggegation-Statement that " "matched the Begin-Aggregation_Statement, " f'"{begin_agg}" but found: {end_agg}' ) try: self.parse_around_equals(tokens) except (ParseError, ValueError): # No equals statement, which is fine. self.parse_statement_delimiter(tokens) return None t = next(tokens) if t != block_name: tokens.send(t) tokens.throw( ValueError, f'Expecting a Block-Name after "{end_agg} =" ' f'that matches "{block_name}", but found: ' f'"{t}"', ) self.parse_statement_delimiter(tokens) return None
def parse_value(self, tokens: abc.Generator): """Parses PVL Values. <Value> ::= (<Simple-Value> | <Set> | <Sequence>) [<WSC>* <Units Expression>] Returns the decoded <Value> as an appropriate Python object. """ value = None try: t = next(tokens) value = self.decoder.decode_simple_value(t) except ValueError: tokens.send(t) for p in ( self.parse_set, self.parse_sequence, self.parse_value_post_hook, ): try: value = p(tokens) break except LexerError: # A LexerError is a subclass of ValueError, but # if we get a LexerError, that's a problem and # we need to raise it, and not let it pass. raise except ValueError: # Getting a ValueError is a normal conseqence of # one of the parsing strategies not working, # this pass allows us to go to the next one. pass else: tokens.throw( ValueError, "Was expecting a Simple Value, or the " "beginning of a Set or Sequence, but " f'found: "{t}"', ) # print(f'in parse_value, value is: {value}') self.parse_WSC_until(None, tokens) try: return self.parse_units(value, tokens) except (ValueError, StopIteration): return value
def parse_units(self, value, tokens: abc.Generator) -> str: """Parses PVL Units Expression. <Units-Expression> ::= "<" [<white-space>] <Units-Value> [<white-space>] ">" and <Units-Value> ::= <units-character> [ [ <units-character> | <white-space> ]* <units-character> ] Returns the *value* and the <Units-Value> as a ``Units()`` object. """ t = next(tokens) if not t.startswith(self.grammar.units_delimiters[0]): tokens.send(t) raise ValueError( "Was expecting the start units delimiter, " + '"{}" '.format(self.grammar.units_delimiters[0]) + f'but found "{t}"' ) if not t.endswith(self.grammar.units_delimiters[1]): tokens.send(t) raise ValueError( "Was expecting the end units delimiter, " + '"{}" '.format(self.grammar.units_delimiters[1]) + f'at the end, but found "{t}"' ) delim_strip = t.strip("".join(self.grammar.units_delimiters)) units_value = delim_strip.strip("".join(self.grammar.whitespace)) for d in self.grammar.units_delimiters: if d in units_value: tokens.throw( ValueError, "Was expecting a units character, but found a " f'unit delimiter, "{d}" instead.', ) return self.decoder.decode_quantity(value, units_value)
def parse_begin_aggregation_statement( self, tokens: abc.Generator ) -> tuple: """Parses the tokens for a Begin Aggregation Statement, and returns the name Block Name as a ``str``. <Begin-Aggregation-Statement-block> ::= <Begin-Aggegation-Statement> <WSC>* '=' <WSC>* <Block-Name> [<Statement-Delimiter>] Where <Block-Name> ::= <Parameter-Name> """ try: begin = next(tokens) if not begin.is_begin_aggregation(): tokens.send(begin) raise ValueError( "Expecting a Begin-Aggegation-Statement, but " f"found: {begin}" ) except StopIteration: raise ValueError( "Ran out of tokens before starting to parse " "a Begin-Aggegation-Statement." ) try: self.parse_around_equals(tokens) except ValueError: tokens.throw( ValueError, f'Expecting an equals sign after "{begin}" ' ) block_name = next(tokens) if not block_name.is_parameter_name(): tokens.throw( ValueError, f'Expecting a Block-Name after "{begin} =" ' f'but found: "{block_name}"', ) self.parse_statement_delimiter(tokens) return begin, str(block_name)
def throw(self, *args, **kwargs): # noqa: D102 return Generator.throw(self, *args, **kwargs)
def throw(self, exception_type, value=None, trace_back=None): return Generator.throw(self, exception_type, value, trace_back)
def throw(self, *args, **kwargs): return Generator.throw(self, *args, **kwargs)