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 eval_(text: Value) -> Value: """ Evaluates `text` as Knight code, returning its result. """ value = Value.parse(Stream(str(text))) if value is None: raise ParseError('Nothing to parse.') else: return value.run()