Exemple #1
0
def nth(list_: MalExpression, index: MalExpression) -> MalExpression:
    assert isinstance(list_, MalList) or isinstance(list_, MalVector)
    assert isinstance(index, MalInt)
    list_native = list_.native()
    if index.native() > len(list_native) - 1:
        raise MalIndexError(index.native())
    return list_native[index.native()]
Exemple #2
0
def EVAL(ast: MalExpression, env: Env) -> MalExpression:
    if not isinstance(ast, MalList):
        return eval_ast(ast, env)
    if len(ast.native()) == 0:
        return ast
    first = str(ast.native()[0])
    rest = ast.native()[1:]
    if first == "def!":
        key = str(ast.native()[1])
        value = EVAL(ast.native()[2], env)
        return env.set(key, value)
    if first == "let*":
        assert len(rest) == 2
        let_env = Env(env)
        bindings = rest[0]
        assert isinstance(bindings, MalList) or isinstance(bindings, MalVector)
        bindings_list = bindings.native()
        assert len(bindings_list) % 2 == 0
        for i in range(0, len(bindings_list), 2):
            assert isinstance(bindings_list[i], MalSymbol)
            assert isinstance(bindings_list[i + 1], MalExpression)
            let_env.set(str(bindings_list[i]),
                        EVAL(bindings_list[i + 1], let_env))
        expr = rest[1]
        return EVAL(expr, let_env)
    evaled_ast = eval_ast(ast, env)
    f = evaled_ast.native()[0]
    args = evaled_ast.native()[1:]
    try:
        return f.call(args)
    except AttributeError:
        raise MalInvalidArgumentException(f, "attribute error")
Exemple #3
0
def get(map: MalExpression, key: MalExpression) -> MalExpression:
    if isinstance(map, MalNil):
        return MalNil()
    if not isinstance(map, MalHash_map):
        raise MalInvalidArgumentException(map, "not a hash map")
    if key.native() in map.native():
        return map.native()[key.native()]
    else:
        return MalNil()
Exemple #4
0
def map_(func: MalExpression, map_list: MalExpression) -> MalExpression:
    assert isinstance(func, MalFunctionCompiled) or isinstance(
        func, MalFunctionRaw)
    assert isinstance(map_list, MalList) or isinstance(map_list, MalVector)
    result_list: List[MalExpression] = []
    for i in range(len(map_list.native())):
        elem = map_list.native()[i]
        result_list.append(func.call([elem]))
    return MalList(result_list)
Exemple #5
0
def EVAL(ast: MalExpression, env: Env) -> MalExpression:
    # print("EVAL: " + str(ast))
    if not isinstance(ast, MalList):
        return eval_ast(ast, env)
    if len(ast.native()) == 0:
        return ast
    first = str(ast.native()[0])
    rest = ast.native()[1:]
    if first == "def!":
        key = str(ast.native()[1])
        value = EVAL(ast.native()[2], env)
        return env.set(key, value)
    if first == "let*":
        assert len(rest) == 2
        let_env = Env(env)
        bindings = rest[0]
        assert isinstance(bindings, MalList) or isinstance(bindings, MalVector)
        bindings_list = bindings.native()
        assert len(bindings_list) % 2 == 0
        for i in range(0, len(bindings_list), 2):
            assert isinstance(bindings_list[i], MalSymbol)
            assert isinstance(bindings_list[i + 1], MalExpression)
            let_env.set(str(bindings_list[i]), EVAL(bindings_list[i + 1], let_env))
        expr = rest[1]
        return EVAL(expr, let_env)
    if first == "do":
        for x in range(0, len(rest) - 1):
            EVAL(rest[x], env)
        return EVAL(rest[len(rest) - 1], env)
    if first == "if":
        condition = EVAL(rest[0], env)

        if isinstance(condition, MalNil) or (
            isinstance(condition, MalBoolean) and condition.native() is False
        ):
            if len(rest) >= 3:
                return EVAL(rest[2], env)
            else:
                return MalNil()
        else:
            return EVAL(rest[1], env)
    if first == "fn*":

        def func_body(x):
            func_env = Env(outer=env, binds=rest[0].native(), exprs=x)
            return EVAL(rest[1], func_env)

        return MalFunctionCompiled(func_body)

    evaled_ast = eval_ast(ast, env)
    f = evaled_ast.native()[0]
    args = evaled_ast.native()[1:]
    try:
        return f.call(args)
    except AttributeError:
        raise MalInvalidArgumentException(f, "attribute error")
Exemple #6
0
def macroexpand(ast: MalExpression, env: Env) -> MalExpression:
    while True:
        if not is_macro_call(ast, env):
            return ast
        assert isinstance(ast, MalList)
        macro_func = env.get(ast.native()[0].native())
        assert isinstance(macro_func, MalFunctionRaw) or isinstance(
            macro_func, MalFunctionCompiled)
        ast = macro_func.call(ast.native()[1:])
        continue
Exemple #7
0
def eval_ast(ast: MalExpression, env: Env) -> MalExpression:
    if isinstance(ast, MalSymbol):
        return env.get(ast)
    if isinstance(ast, MalList):
        return MalList([EVAL(x, env) for x in ast.native()])
    if isinstance(ast, MalVector):
        return MalVector([EVAL(x, env) for x in ast.native()])
    if isinstance(ast, MalHash_map):
        new_dict = {}  # type: Dict[str, MalExpression]
        for key in ast.native():
            new_dict[key] = EVAL(ast.native()[key], env)
        return MalHash_map(new_dict)
    return ast
Exemple #8
0
def quasiquote(ast: MalExpression) -> MalExpression:
    if isinstance(ast, MalList):
        lst = ast.native()
        if len(lst) == 2:
            fst = lst[0]
            if isinstance(fst, MalSymbol) and fst.native() == u'unquote':
                return lst[1]
        return qq_foldr(lst)
    elif isinstance(ast, MalVector):
        return MalList([MalSymbol("vec"), qq_foldr(ast.native())])
    elif isinstance(ast, MalSymbol) or isinstance(ast, MalHash_map):
        return MalList([MalSymbol("quote"), ast])
    else:
        return ast
Exemple #9
0
def equal(a: MalExpression, b: MalExpression) -> MalBoolean:
    if (isinstance(a, MalList) or isinstance(a, MalVector)) and (isinstance(
            b, MalList) or isinstance(b, MalVector)):
        a_native = a.native()
        b_native = b.native()
        if len(a_native) != len(b_native):
            return MalBoolean(False)
        for x in range(0, len(a_native)):
            if not equal(a_native[x], b_native[x]):
                return MalBoolean(False)
        return MalBoolean(True)
    if type(a) == type(b) and a.native() == b.native():
        return MalBoolean(True)
    return MalBoolean(False)
Exemple #10
0
def readline(arg: MalExpression) -> Union[MalString, MalNil]:
    try:
        assert isinstance(arg, MalString)
        line = input(arg.native())
    except EOFError:
        return MalNil()
    return MalString(line)
Exemple #11
0
def qq_loop(acc: MalList, elt: MalExpression) -> MalList:
    if isinstance(elt, MalList):
        lst = elt.native()
        if len(lst) == 2:
            fst = lst[0]
            if isinstance(fst, MalSymbol) and fst.native() == u"splice-unquote":
                return MalList([MalSymbol(u"concat"), lst[1], acc])
    return MalList([MalSymbol(u"cons"), quasiquote(elt), acc])
Exemple #12
0
def eval_ast(ast: MalExpression,
             env: Dict[str, MalFunctionCompiled]) -> MalExpression:
    if isinstance(ast, MalSymbol):
        try:
            return env[str(ast)]
        except KeyError:
            raise MalUnknownSymbolException(str(ast))
    if isinstance(ast, MalList):
        return MalList([EVAL(x, env) for x in ast.native()])
    if isinstance(ast, MalVector):
        return MalVector([EVAL(x, env) for x in ast.native()])
    if isinstance(ast, MalHash_map):
        new_dict = {}  # type: Dict[str, MalExpression]
        for key in ast.native():
            new_dict[key] = EVAL(ast.native()[key], env)
        return MalHash_map(new_dict)
    return ast
Exemple #13
0
def EVAL(ast: MalExpression, env: Dict[str,
                                       MalFunctionCompiled]) -> MalExpression:
    if not isinstance(ast, MalList):
        return eval_ast(ast, env)
    if len(ast.native()) == 0:
        return ast
    eval_result = eval_ast(ast, env)
    f = eval_result.native()[0]
    args = eval_result.native()[1:]
    return f.call(args)
Exemple #14
0
def EVAL(ast: MalExpression, env: Env) -> MalExpression:
    dbgeval = env.get("DEBUG-EVAL")
    if (dbgeval is not None
        and not isinstance(dbgeval, MalNil)
        and (not isinstance(dbgeval, MalBoolean) or dbgeval.native())):
        print("EVAL: " + str(ast))
    if isinstance(ast, MalSymbol):
        key = str(ast)
        val = env.get(key)
        if val is None: raise MalUnknownSymbolException(key)
        return val
    if isinstance(ast, MalVector):
        return MalVector([EVAL(x, env) for x in ast.native()])
    if isinstance(ast, MalHash_map):
        new_dict = {}  # type: Dict[str, MalExpression]
        for key in ast.native():
            new_dict[key] = EVAL(ast.native()[key], env)
        return MalHash_map(new_dict)
    if not isinstance(ast, MalList):
        return ast
    if len(ast.native()) == 0:
        return ast
    first = str(ast.native()[0])
    rest = ast.native()[1:]
    if first == "def!":
        key = str(ast.native()[1])
        value = EVAL(ast.native()[2], env)
        return env.set(key, value)
    if first == "let*":
        assert len(rest) == 2
        let_env = Env(env)
        bindings = rest[0]
        assert isinstance(bindings, MalList) or isinstance(bindings, MalVector)
        bindings_list = bindings.native()
        assert len(bindings_list) % 2 == 0
        for i in range(0, len(bindings_list), 2):
            assert isinstance(bindings_list[i], MalSymbol)
            assert isinstance(bindings_list[i + 1], MalExpression)
            let_env.set(str(bindings_list[i]), EVAL(bindings_list[i + 1], let_env))
        expr = rest[1]
        return EVAL(expr, let_env)
    f, *args = (EVAL(form, env) for form in ast.native())
    try:
        return f.call(args)
    except AttributeError:
        raise MalInvalidArgumentException(f, "attribute error")
Exemple #15
0
def is_macro_call(ast: MalExpression, env: Env) -> bool:
    try:
        x = env.get(ast.native()[0].native())
        try:
            assert isinstance(x, MalFunctionRaw) or isinstance(
                x, MalFunctionCompiled)
        except AssertionError:
            return False
        return x.is_macro()  # type: ignore
    except (TypeError, MalUnknownSymbolException, AttributeError, IndexError,
            KeyError):
        return False
Exemple #16
0
def EVAL(ast: MalExpression, env: Dict[str,
                                       MalFunctionCompiled]) -> MalExpression:
    # print("EVAL: " + str(ast))
    if isinstance(ast, MalSymbol):
        try:
            return env[str(ast)]
        except KeyError:
            raise MalUnknownSymbolException(str(ast))
    if isinstance(ast, MalVector):
        return MalVector([EVAL(x, env) for x in ast.native()])
    if isinstance(ast, MalHash_map):
        new_dict = {}  # type: Dict[str, MalExpression]
        for key in ast.native():
            new_dict[key] = EVAL(ast.native()[key], env)
        return MalHash_map(new_dict)
    if not isinstance(ast, MalList):
        return ast
    if len(ast.native()) == 0:
        return ast
    f, *args = (EVAL(form, env) for form in ast.native())
    return f.call(args)
Exemple #17
0
def quasiquote(ast: MalExpression) -> MalExpression:
    if not is_pair(ast):
        return MalList([MalSymbol("quote"), ast])
    elif core.equal(ast.native()[0], MalSymbol("unquote")).native():
        return ast.native()[1]
    elif (is_pair(ast.native()[0])
          and core.equal(ast.native()[0].native()[0],
                         MalSymbol("splice-unquote")).native()):
        return MalList([
            MalSymbol("concat"),
            ast.native()[0].native()[1],
            quasiquote(MalList(ast.native()[1:])),
        ])
    else:
        return MalList([
            MalSymbol("cons"),
            quasiquote(ast.native()[0]),
            quasiquote(MalList(ast.native()[1:])),
        ])
Exemple #18
0
def EVAL(ast: MalExpression, env: Env) -> MalExpression:
    while True:
        ast = macroexpand(ast, env)
        ast_native = ast.native()
        if not isinstance(ast, MalList):
            return eval_ast(ast, env)
        elif len(ast_native) == 0:
            return ast

        first_str = str(ast_native[0])
        if first_str == "macroexpand":
            return macroexpand(ast.native()[1], env)
        elif first_str == "def!":
            name: str = str(ast_native[1])
            value: MalExpression = EVAL(ast_native[2], env)
            return env.set(name, value)
        if first_str == "defmacro!":
            name = str(ast_native[1])
            value = EVAL(ast_native[2], env)
            assert isinstance(value, MalFunctionCompiled) or isinstance(
                value, MalFunctionRaw)
            value.make_macro()
            return env.set(name, value)
        elif first_str == "let*":
            assert len(ast_native) == 3
            let_env = Env(env)
            bindings: MalExpression = ast_native[1]
            assert isinstance(bindings, MalList) or isinstance(
                bindings, MalVector)
            bindings_list: List[MalExpression] = bindings.native()
            assert len(bindings_list) % 2 == 0
            for i in range(0, len(bindings_list), 2):
                assert isinstance(bindings_list[i], MalSymbol)
                assert isinstance(bindings_list[i + 1], MalExpression)
                let_env.set(str(bindings_list[i]),
                            EVAL(bindings_list[i + 1], let_env))
            env = let_env
            ast = ast_native[2]
            continue
        elif first_str == "do":
            for x in range(1, len(ast_native) - 1):
                EVAL(ast_native[x], env)
            ast = ast_native[len(ast_native) - 1]
            continue
        elif first_str == "if":
            condition = EVAL(ast_native[1], env)

            if isinstance(condition,
                          MalNil) or (isinstance(condition, MalBoolean)
                                      and condition.native() is False):
                if len(ast_native) >= 4:
                    ast = ast_native[3]
                    continue
                else:
                    return MalNil()
            else:
                ast = ast_native[2]
                continue
        elif first_str == "fn*":
            raw_ast = ast_native[2]
            raw_params = ast_native[1]

            def fn(args: List[MalExpression]) -> MalExpression:
                f_ast = raw_ast
                f_env = Env(outer=env, binds=raw_params.native(), exprs=args)
                return EVAL(f_ast, f_env)

            return MalFunctionRaw(fn=fn,
                                  ast=raw_ast,
                                  params=raw_params,
                                  env=env)
        elif first_str == "quote":
            return (MalList(ast_native[1].native()) if isinstance(
                ast_native[1], MalVector) else ast_native[1])
        elif first_str == "quasiquote":
            ast = quasiquote(ast_native[1])
            continue
        elif first_str == "try*":
            try:
                return EVAL(ast_native[1], env)
            except MalException as e:
                if len(ast_native) < 3:
                    raise e
                catch_block = ast_native[2]
                assert (isinstance(catch_block, MalList)
                        and isinstance(catch_block.native()[0], MalSymbol)
                        and str(catch_block.native()[0]) == "catch*"
                        and len(catch_block.native()) == 3)
                exception_symbol = catch_block.native()[1]
                assert isinstance(exception_symbol, MalSymbol)
                env = Env(env)
                env.set(str(exception_symbol), e.native())
                ast = catch_block.native()[2]
                continue
        else:
            evaled_ast = eval_ast(ast, env)
            f = evaled_ast.native()[0]
            args = evaled_ast.native()[1:]
            if isinstance(f, MalFunctionRaw):
                ast = f.ast()

                env = Env(
                    outer=f.env(),
                    binds=f.params().native(),
                    exprs=evaled_ast.native()[1:],
                )
                continue
            elif isinstance(f, MalFunctionCompiled):
                return f.call(args)
            else:
                raise MalInvalidArgumentException(f, "not a function")
Exemple #19
0
def is_pair(x: MalExpression) -> bool:
    if (isinstance(x, MalList)
            or isinstance(x, MalVector)) and len(x.native()) > 0:
        return True
    return False
Exemple #20
0
def not_(expr: MalExpression) -> MalExpression:
    if isinstance(expr, MalNil) or (isinstance(expr, MalBoolean)
                                    and expr.native() is False):
        return MalBoolean(True)
    else:
        return MalBoolean(False)
Exemple #21
0
def true_q(arg: MalExpression) -> MalExpression:
    return MalBoolean(isinstance(arg, MalBoolean) and arg.native())
Exemple #22
0
def false_q(arg: MalExpression) -> MalExpression:
    return MalBoolean(isinstance(arg, MalBoolean) and not arg.native())
Exemple #23
0
def read_string(a: MalExpression) -> MalExpression:
    if isinstance(a, MalString):
        result = reader.read(a.native())
        return result
    raise MalInvalidArgumentException(a, "not a string")
Exemple #24
0
def less_equal(a: MalExpression, b: MalExpression) -> MalBoolean:
    if not isinstance(a, MalInt):
        raise MalInvalidArgumentException(a, "not an int")
    if not isinstance(b, MalInt):
        raise MalInvalidArgumentException(b, "not an int")
    return MalBoolean(a.native() <= b.native())
Exemple #25
0
def keyword_q(arg: MalExpression) -> MalExpression:
    return MalBoolean(isinstance(arg, MalString) and arg.is_keyword())
Exemple #26
0
def count(x: MalExpression) -> MalInt:
    if isinstance(x, MalList) or isinstance(x, MalVector):
        return MalInt(len(x.native()))
    elif isinstance(x, MalNil):
        return MalInt(0)
    raise MalInvalidArgumentException(x, "not a list")
Exemple #27
0
def keyword(arg: MalExpression) -> MalExpression:
    assert isinstance(arg, MalString)
    if arg.is_keyword():
        return arg
    else:
        return MalString(arg.unreadable_str(), keyword=True)
Exemple #28
0
def symbol(arg: MalExpression) -> MalExpression:
    assert isinstance(arg, MalString)
    return MalSymbol(arg.unreadable_str())
Exemple #29
0
def EVAL(ast: MalExpression, env: Env) -> MalExpression:
    while True:
        dbgeval = env.get("DEBUG-EVAL")
        if (dbgeval is not None and not isinstance(dbgeval, MalNil)
                and (not isinstance(dbgeval, MalBoolean) or dbgeval.native())):
            print("EVAL: " + str(ast))
        ast_native = ast.native()
        if isinstance(ast, MalSymbol):
            key = str(ast)
            val = env.get(key)
            if val is None: raise MalUnknownSymbolException(key)
            return val
        if isinstance(ast, MalVector):
            return MalVector([EVAL(x, env) for x in ast_native])
        if isinstance(ast, MalHash_map):
            new_dict = {}  # type: Dict[str, MalExpression]
            for key in ast_native:
                new_dict[key] = EVAL(ast_native[key], env)
            return MalHash_map(new_dict)
        if not isinstance(ast, MalList):
            return ast
        elif len(ast_native) == 0:
            return ast

        first_str = str(ast_native[0])
        if first_str == "def!":
            name: str = str(ast_native[1])
            value: MalExpression = EVAL(ast_native[2], env)
            return env.set(name, value)
        elif first_str == "let*":
            assert len(ast_native) == 3
            let_env = Env(env)
            bindings: MalExpression = ast_native[1]
            assert isinstance(bindings, MalList) or isinstance(
                bindings, MalVector)
            bindings_list: List[MalExpression] = bindings.native()
            assert len(bindings_list) % 2 == 0
            for i in range(0, len(bindings_list), 2):
                assert isinstance(bindings_list[i], MalSymbol)
                assert isinstance(bindings_list[i + 1], MalExpression)
                let_env.set(str(bindings_list[i]),
                            EVAL(bindings_list[i + 1], let_env))
            env = let_env
            ast = ast_native[2]
            continue
        elif first_str == "do":
            for x in range(1, len(ast_native) - 1):
                EVAL(ast_native[x], env)
            ast = ast_native[len(ast_native) - 1]
            continue
        elif first_str == "if":
            condition = EVAL(ast_native[1], env)

            if isinstance(condition,
                          MalNil) or (isinstance(condition, MalBoolean)
                                      and condition.native() is False):
                if len(ast_native) >= 4:
                    ast = ast_native[3]
                    continue
                else:
                    return MalNil()
            else:
                ast = ast_native[2]
                continue
        elif first_str == "fn*":
            raw_ast = ast_native[2]
            raw_params = ast_native[1]

            def fn(args: List[MalExpression]) -> MalExpression:
                f_ast = raw_ast
                f_env = Env(outer=env, binds=raw_params.native(), exprs=args)
                return EVAL(f_ast, f_env)

            return MalFunctionRaw(fn=fn,
                                  ast=raw_ast,
                                  params=raw_params,
                                  env=env)
        elif first_str == "quote":
            return (MalList(ast_native[1].native()) if isinstance(
                ast_native[1], MalVector) else ast_native[1])
        elif first_str == "quasiquote":
            ast = quasiquote(ast_native[1])
            continue
        else:
            f, *args = (EVAL(form, env) for form in ast_native)
            if isinstance(f, MalFunctionRaw):
                ast = f.ast()

                env = Env(
                    outer=f.env(),
                    binds=f.params().native(),
                    exprs=args,
                )
                continue
            elif isinstance(f, MalFunctionCompiled):
                return f.call(args)
            else:
                raise MalInvalidArgumentException(f, "not a function")
Exemple #30
0
def empty_q(x: MalExpression) -> MalBoolean:
    if sequential_q(x):
        return MalBoolean(len(x.native()) == 0)
    raise MalInvalidArgumentException(x, "not a list")