def _read_float(self, reader): start = reader.get_cursor() result = "" while reader.can_read(): char = reader.peek() if char == ".": reader.skip() if reader.can_read() and reader.peek() == ".": break result += char elif char.isdigit() or char == "+" or char == "-": reader.skip() result += char else: break if not result: raise BuiltInExceptions.reader_expected_float( ).create_with_context(reader) # Verify result is a valid float try: return float(result) except ValueError: reader.set_cursor(start) raise BuiltInExceptions.reader_invalid_float().create_with_context( reader, result)
def parse_nodes(self, node, original_reader, context_so_far): source = context_so_far.get_source() errors = None potentials = None cursor = original_reader.get_cursor() for child in node.get_relevant_nodes(original_reader): if not child.can_use(source): continue context = context_so_far.copy() reader = StringReader(original_reader) try: try: child.parse(reader, context) # TODO: check if this one's appropriate except RuntimeError as e: raise BuiltInExceptions.dispatcher_parse_expection( ).create_with_context(reader, e) if reader.can_read(): if reader.peek() != ARGUMENT_SEPARATOR_CHAR: raise BuiltInExceptions.dispatcher_expected_argument_separator( ).create_with_context(reader) except CommandSyntaxException as e: if errors is None: errors = {} errors[child] = e reader.set_cursor(cursor) continue context.with_command(child.get_command()) if reader.can_read(2 if child.get_redirect() is None else 1): reader.skip() if child.get_redirect() is not None: child_context = CommandContextBuilder( self, source, child.get_redirect(), reader.get_cursor()) parse = self.parse_nodes(child.get_redirect(), reader, child_context) context.with_child(parse.get_context()) return ParseResult(context, parse.get_reader(), parse.get_exceptions()) else: parse = self.parse_nodes(child, reader, context) if potentials is None: potentials = [] potentials.append(parse) else: if potentials is None: potentials = [] potentials.append(ParseResult(context, reader, {})) if potentials: potentials.sort(key=functools.cmp_to_key(potentials_cmp)) return potentials[0] return ParseResult(context_so_far, original_reader, {} if errors is None else errors)
def parse(self, reader): start = reader.get_cursor() result = reader.read_double() if result < self.minimum: reader.set_cursor(start) raise BuiltInExceptions.float_too_low().create_with_context(reader, result, self.minimum) if result > self.minimum: reader.set_cursor(start) raise BuiltInExceptions.float_too_high().create_with_context(reader, result, self.maximum) return result
def read_int(self): start = self.cursor while self.can_read() and self.is_allowed_number(self.peek()): self.skip() number = self.string[start:self.cursor] if not number: raise BuiltInExceptions.reader_expected_int().create_with_context(self) try: return int(number) except ValueError: self.cursor = start raise BuiltInExceptions.reader_invalid_int().create_with_context(self, number)
def read_boolean(self): start = self.cursor value = self.read_unquoted_string() if not value: raise BuiltInExceptions.reader_expected_bool().create_with_context(self) if value == "true": return True elif value == "false": return False else: self.cursor = start raise BuiltInExceptions.reader_invalid_bool().create_with_context(self, value)
def parse(self, reader, context_builder): start = reader.get_cursor() end = self.__parse(reader) if end > -1: context_builder.with_node(self, between(start, end)) return raise BuiltInExceptions.literal_incorrect().create_with_context( reader, self.literal)
def test_execute_incorrect_literal(): subject = CommandDispatcher() subject.register(literal("foo").executes(command).then(literal("bar"))) try: subject.execute("foo baz", {}) except CommandSyntaxException as error: assert error.get_type() == BuiltInExceptions.dispatcher_unknown_argument() assert error.get_cursor() == 4
def test_execute_empty_command(): subject = CommandDispatcher() subject.register(literal("")) try: subject.execute("", {}) except CommandSyntaxException as error: assert error.get_type() == BuiltInExceptions.dispatcher_unknown_command() assert error.get_cursor() == 0
def test_execute_impermissible_command(): subject = CommandDispatcher() subject.register(literal("foo").requires(lambda _: False)) try: subject.execute("foo", {}) except CommandSyntaxException as error: assert error.get_type() == BuiltInExceptions.dispatcher_unknown_command() assert error.get_cursor() == 0
def read_string_until(self, terminator): result = "" escaped = False while self.can_read(): char = self.read() if escaped: if char == terminator or char == self.SYNTAX_ESCAPE: result += char else: self.set_cursor(self.get_cursor() - 1) raise BuiltInExceptions.reader_invalid_escape().create_with_context(self, str(char)) elif char == self.SYNTAX_ESCAPE: escaped = True elif char == terminator: return result else: result += char raise BuiltInExceptions.reader_expected_end_of_quote().create_with_context(self)
def read_quoted_string(self): if not self.can_read(): return "" next_char = self.peek() if not self.is_quoted_string_start(next_char): raise BuiltInExceptions.reader_expected_start_of_quote().create_with_context(self) self.skip() return self.read_string_until(next_char)
def execute_preparsed(self, parse): if parse.get_reader().can_read(): if len(parse.get_exceptions()) == 1: raise list(parse.get_exceptions().values())[0] elif not parse.get_context().get_range(): raise BuiltInExceptions.dispatcher_unknown_command( ).create_with_context(parse.get_reader()) else: raise BuiltInExceptions.dispatcher_unknown_argument( ).create_with_context(parse.get_reader()) result = 0 successful_forks = 0 forked = False found_command = False command = parse.get_reader().get_string() original = parse.get_context().build(command) contexts = [original] _next = None while contexts is not None: for context in contexts: child = context.get_child() if child is not None: forked |= context.is_forked() if child.has_nodes(): found_command = True modifier = context.get_redirect_modifier() if modifier is None: if _next is None: _next = [] _next.append(child.copy_for(context.get_source())) else: try: results = modifier(context) if results: if _next is None: _next = [] for source in results: _next.append(child.copy_for(source)) except CommandSyntaxException as e: self.consumer.on_command_complete( context, False, 0) if not forked: raise e elif context.get_command() is not None: found_command = True try: value = context.get_command()(context) result += value if value else 1 self.consumer.on_command_complete(context, True, value) successful_forks += 1 except CommandSyntaxException as e: self.consumer.on_command_complete(context, False, 0) if not forked: raise e contexts = _next _next = None if not found_command: self.consumer.on_command_complete(original, False, 0) raise BuiltInExceptions.dispatcher_unknown_command( ).create_with_context(parse.get_reader()) return successful_forks if forked else result
def expect(self, char): if not self.can_read() or self.peek() != char: raise BuiltInExceptions.reader_expected_symbol().create_with_context(self, str(char)) self.skip()