Exemplo n.º 1
0
def slurp(*args: t.MalType) -> t.MalType:
    if len(args) != 1 or not isinstance(args[0], t.MalString):
        raise MalError('Expected slurp arg to be string')
    try:
        with open(args[0].value, 'r') as f:
            return t.MalString(f.read())
    except FileNotFoundError:
        raise MalError(f'File {args[0].value} does not exist')
    except OSError:
        raise MalError(f'Failed to read file {args[0].value}')
Exemplo n.º 2
0
 def wrapper(*args: t.MalType) -> t.MalType:
     if not all(isinstance(i, t.MalInt) for i in args):
         raise MalError('Only ints are supported as arguments')
     acc, *rest = map(o.attrgetter('value'),
                      args)  # type: Tuple[int, List[int]]
     for i in rest:
         acc = op(acc, i)
     return t.MalInt(acc)
Exemplo n.º 3
0
def swap(*args: t.MalType) -> t.MalType:
    if (len(args) < 2 or not isinstance(args[0], t.MalAtom)
            or not isinstance(args[1], t.MalCallable)):
        raise MalError('Expected atom and function as arguments to swap!')
    atom, callable_, *rest = args
    assert isinstance(atom, t.MalAtom) and isinstance(callable_, t.MalCallable)
    if isinstance(callable_, t.MalTCOFunction):
        callable_ = callable_.fn
    assert isinstance(callable_, t.MalFunction), 'Unsupported callable'
    new_value = atom.inner = callable_.fn(atom.inner, *rest)
    return new_value
Exemplo n.º 4
0
def EVAL(in_: t.MalType, env: Env) -> t.MalType:
    if not isinstance(in_, t.MalList):
        return eval_ast(in_, env)
    if not in_.items:
        return in_
    f, *args = in_.items
    if isinstance(f, t.MalSymbol):
        if f.name == 'def!':
            if len(args) != 2:
                raise MalError('Expected 2 arguments to "def!"')
            dest, val = args
            if not isinstance(dest, t.MalSymbol):
                raise MalError('Expected symbol name to "def!"')
            res = env[dest.name] = EVAL(val, env)
            return res
        elif f.name == 'let*':
            if len(args) != 2:
                raise MalError('Expected 2 arguments to "let*"')
            new_env = env.new_child()
            bindings, body = args
            if (not isinstance(bindings, (t.MalVector, t.MalList))
                    or len(bindings.items) % 2 != 0):
                raise MalError('Expected let* bindings to be even length list')
            for i in range(0, len(bindings.items) // 2 + 1, 2):
                name, value = bindings.items[i:i + 2]
                if not isinstance(name, t.MalSymbol):
                    raise MalError('Expected symbol name in let* binding')
                new_env[name.name] = EVAL(value, new_env)
            return EVAL(body, new_env)
    f, *args = cast(t.MalList, eval_ast(in_, env)).items
    if isinstance(f, t.MalFunction):
        return f.fn(*args)
    raise MalError(f'Value {pr_str(f)} is not callable')
Exemplo n.º 5
0
def eval_ast(ast: t.MalType, env: Env):
    if isinstance(ast, t.MalSymbol):
        if ast.name in env:
            return env[ast.name]
        raise MalError(f'Unbound symbol {ast.name}')
    if isinstance(ast, (t.MalList, t.MalVector)):
        return type(ast)([EVAL(i, env) for i in ast.items])
    if isinstance(ast, t.MalHashMap):
        items = []
        for k, v in ast.items.items():
            items.append(k)
            items.append(EVAL(v, env))
        return t.MalHashMap(items)
    return ast
Exemplo n.º 6
0
Arquivo: step5_tco.py Projeto: p7g/mal
def eval_ast(ast: t.MalType, env: Env) -> t.MalType:
    if isinstance(ast, t.MalSymbol):
        try:
            return env[ast.name]
        except KeyError:
            raise MalError(f'{ast.name} not found')
    if isinstance(ast, (t.MalList, t.MalVector)):
        return type(ast)([EVAL(i, env) for i in ast.items])
    if isinstance(ast, t.MalHashMap):
        items = []
        for k, v in ast.items.items():
            items.append(k)
            items.append(EVAL(v, env))
        return t.MalHashMap(items)
    return ast
Exemplo n.º 7
0
def list_p(*args: t.MalType) -> t.MalType:
    if len(args) != 1:
        raise MalError(f'Expected 1 argument to list?, got {len(args)}')
    return t.MalBool(isinstance(args[0], t.MalList))
Exemplo n.º 8
0
def atom_p(*args: t.MalType) -> t.MalType:
    if len(args) != 1:
        raise MalError('Expected one argument to atom?')
    return t.MalBool(isinstance(args[0], t.MalAtom))
Exemplo n.º 9
0
Arquivo: step5_tco.py Projeto: p7g/mal
def EVAL(in_: t.MalType, env: Env) -> t.MalType:
    while True:
        if not isinstance(in_, t.MalList):
            return eval_ast(in_, env)
        if not in_.items:
            return in_
        f, *args = in_.items
        if isinstance(f, t.MalSymbol):
            if f.name == 'def!':
                if len(args) != 2:
                    raise MalError('Expected 2 arguments to "def!"')
                dest, val = args
                if not isinstance(dest, t.MalSymbol):
                    raise MalError('Expected symbol name to "def!"')
                res = env[dest.name] = EVAL(val, env)
                return res

            if f.name == 'let*':
                if len(args) != 2:
                    raise MalError('Expected 2 arguments to "let*"')
                new_env = env.new_child()
                bindings, body = args
                if (not isinstance(bindings, (t.MalVector, t.MalList))
                        or len(bindings.items) % 2 != 0):
                    raise MalError(
                        'Expected let* bindings to be even length list')
                for i in range(0, len(bindings.items) // 2 + 1, 2):
                    name, value = bindings.items[i:i + 2]
                    if not isinstance(name, t.MalSymbol):
                        raise MalError('Expected symbol name in let* binding')
                    new_env[name.name] = EVAL(value, new_env)
                env = new_env
                in_ = body
                continue

            if f.name == 'do':
                if not args:
                    raise MalError('Expected body in do expr')
                eval_ast(t.MalList(args[:-1]), env)
                in_ = args[-1]
                continue

            if f.name == 'if':
                if len(args) not in (2, 3):
                    raise MalError('Expected 2 or 3 arguments to if')
                cond, then, *else_ = args
                if EVAL(cond, env).is_truthy():
                    in_ = then
                elif else_:
                    in_ = else_[0]
                else:
                    in_ = t.MalNil()
                continue

            if f.name == 'fn*':
                if len(args) != 2:
                    raise MalError('Expected 2 arguments to fn*')
                params, body = args
                if not isinstance(params, (t.MalList, t.MalVector)):
                    raise MalError('Parameters must be list or vector')
                if not all(isinstance(p, t.MalSymbol) for p in params.items):
                    raise MalError('Parameters must be symbols')
                return t.MalTCOFunction(
                    ast=body,
                    params=params,
                    env=env,
                    fn=t.MalFunction(
                        _make_closure(
                            env,
                            [cast(t.MalSymbol, p).name
                             for p in params.items], body)),
                )
        f, *args = cast(t.MalList, eval_ast(in_, env)).items
        if isinstance(f, t.MalFunction):
            return f.fn(*args)
        if isinstance(f, t.MalTCOFunction):
            in_ = f.ast
            binds = [
                cast(t.MalSymbol, p).name
                for p in cast(t.MalSequence, f.params).items
            ]
            env = f.env.new_child(_make_fn_bindings(binds, list(args)))
            continue
        raise MalError(f'Value {pr_str(f)} is not callable')
Exemplo n.º 10
0
def deref(*args: t.MalType) -> t.MalType:
    if len(args) != 1 or not isinstance(args[0], t.MalAtom):
        raise MalError('Expected deref argument to be atom')
    return args[0].inner
Exemplo n.º 11
0
def count(*args: t.MalType) -> t.MalType:
    if len(args) != 1 or not isinstance(args[0], (t.MalSequence, t.MalNil)):
        raise MalError('Expected argument to count to be sequence')
    if isinstance(args[0], t.MalNil):
        return t.MalInt(0)
    return t.MalInt(len(args[0].items))
Exemplo n.º 12
0
def read_string(*args: t.MalType) -> t.MalType:
    if len(args) != 1 or not isinstance(args[0], t.MalString):
        raise MalError('Expected read-string arg to be string')
    return read_str(args[0].value)
Exemplo n.º 13
0
def empty_p(*args: t.MalType) -> t.MalType:
    if len(args) != 1 or not isinstance(args[0], t.MalSequence):
        raise MalError('Expected argument to empty? to be sequence')
    return t.MalBool(len(args[0].items) == 0)
Exemplo n.º 14
0
def atom(*args: t.MalType) -> t.MalType:
    if len(args) != 1:
        raise MalError('Expected one argument to atom')
    return t.MalAtom(args[0])
Exemplo n.º 15
0
 def evil(*args: t.MalType) -> t.MalType:
     if len(args) != 1:
         raise MalError('Expected one argument to eval')
     return EVAL(args[0])
Exemplo n.º 16
0
 def _cmp_fn(*args: t.MalType) -> t.MalType:
     try:
         return t.MalBool(all(op(a, b) for a, b in _pairwise(args)))
     except TypeError:
         types = ', '.join([type(v).__name__ for v in args])
         raise MalError(f'Cannot compare values of types {types}')
Exemplo n.º 17
0
def reset(*args: t.MalType) -> t.MalType:
    if len(args) != 2 or not isinstance(args[0], t.MalAtom):
        raise MalError('Expected atom and value as arguments to reset!')
    args[0].inner = args[1]
    return args[1]