def parse(stream: Stream) -> Union[None, Function]: """ Parses a `Function` from the stream, returning `None` if the stream didn't start with a function character. This will both parse the function name, and its arguments. If not all the arguments could be parsed, a `ParseError` is raised. """ name = stream.peek() if name not in _FUNCS: return None func = _FUNCS[name] stream.matches(Function.REGEX) args = [] for arg in range(func.__code__.co_argcount): value = Value.parse(stream) if value is None: raise ParseError(f'Missing argument {arg} for function {name}') args.append(value) return Function(func, name, args)
def parse(cls, stream: Stream) -> Union[None, Number]: """ Parses a Number out from the stream. This returns `None` if the stream doesn't start with a digit. """ if match := stream.matches(Number.REGEX): return cls(int(match))
def parse(cls, stream: Stream) -> Union[None, Identifier]: """ Parses an Identifier out from the stream. This returns `None` if the stream doesn't start with a lowercase letter, or an underscore. """ if match := stream.matches(Identifier.REGEX): return cls(match)
def parse(cls, stream: Stream) -> Union[None, String]: """ Parses a `String` from the `stream`, returning `None` if the nothing can be parsed. If a starting quote is matched and no ending quote is, then a `ParseError` will be raised. """ quote = stream.matches(String.BEGIN_REGEX) if not quote: return None regex = String.SINGLE_REGEX if quote == "'" else String.DOUBLE_REGEX body = stream.matches(regex, 1) if body is None: raise ParseError(f'unterminated string encountered: {stream}') else: return String(body)
def parse(cls, stream: Stream) -> Union[None, Boolean]: """ Parses a `Boolean` if the stream starts with `T` or `F`. """ if match := stream.matches(Boolean.REGEX, 1): return cls(match == 'T')
def parse(cls, stream: Stream) -> Union[None, Boolean]: """ Attempts to parse a `Boolean """ if match := stream.matches(r'([TF])[A-Z]*', 1): return cls(match == 'T')
def parse(cls, stream: Stream) -> Union[None, Null]: """ Parses `Null` if the stream starts with `N`. """ if match := stream.matches(r'N[A-Z]*'): return cls()
def parse(cls, stream: Stream) -> Union[None, Null]: """ Parses `Null` if the stream starts with `N`. """ if stream.matches(Null.REGEX): return cls() else: return None