Ejemplo n.º 1
0
def rep(line):
    try:
        print(pr_str(eval(read_str(line), repl_env)))
    except Exception as e:
        if isinstance(e.args[0], Val):
            print(pr_str(Val("error", e.args[0])))
        else:
            print(pr_str(Val("error", Val("string", str(e)))))
Ejemplo n.º 2
0
def eval(ast, env):
    if ast.type != "list":
        return eval_ast(ast, env)
    if len(ast.value) == 0:
        return ast

    symbol = ast.value[0].value
    if symbol == "def!":
        evaluated = eval(ast.value[2], env)
        env.set(ast.value[1].value, evaluated)
        return evaluated

    if symbol == "let*":
        new_env = Env(env)
        params = ast.value[1].value

        i = 0
        while i < len(params):
            new_env.set(params[i].value, eval(params[i + 1], new_env))
            i += 2
        return eval(ast.value[2], new_env)

    if symbol == "do":
        evaluated = None
        for i in ast.value[1:]:
            evaluated = eval(i, env)
        return evaluated

    if symbol == "if":
        evaluated = None
        cond = eval(ast.value[1], env)
        if cond.type != "nil" and (cond.type != "bool" or cond.value == True):
            return eval(ast.value[2], env)
        if len(ast.value) > 3:
            return eval(ast.value[3], env)
        return Val("nil", [])
    if symbol == "fn*":
        def func(*exprs_t):
            new_env = Env(env)
            params = ast.value[1].value
            exprs = list(exprs_t)
            i = 0
            while i < len(params):
                if params[i].value == "&":
                    new_env.set(params[i + 1].value, Val("list", exprs[i:]))
                    break
                new_env.set(params[i].value, exprs[i])
                i += 1

            return eval(ast.value[2], new_env)

        return Val("fn", func)
    new_ast = eval_ast(ast, env)
    fn = new_ast.value[0]

    return fn.value(*new_ast.value[1:])
Ejemplo n.º 3
0
def rep(line):
    if len(line) == 0 or line[0] == ";":
        return
    try:
        return pr_str(eval(read_str(line), repl_env))
    except Exception as e:
        if isinstance(e.args[0], Val):
            return pr_str(Val("error", e.args[0]))
        else:
            return pr_str(Val("error", Val("string", str(e))))
Ejemplo n.º 4
0
def seq(col):
    if len(col.value) == 0:
        return Val("nil", [])
    if col.type in ('vector', 'list'):
        return Val("list", col.value)

    res = []
    for i in col.value:
        res.append(Val("string", i))
    return Val("list", res)
Ejemplo n.º 5
0
def eval_ast(ast, env):
    if ast.type == "symbol":
        return env.get(ast.value)
    if ast.type in ("list", "vector"):
        items = map(lambda ast: eval(ast, env), ast.value)
        return Val(ast.type, items)
    if ast.type == "hashmap":
        new_val = {}
        for key, value in ast.value.items():
            new_val[key] = eval(value, env)
        return Val("hashmap", new_val)
    return ast
Ejemplo n.º 6
0
def conj(col, *args):
    if (col.type == "vector"):
        res = []
        for i in col.value:
            res.append(i)
        for i in list(args):
            res.append(i)
        return Val("vector", res)
    res = []
    for i in col.value:
        res.append(i)
    for i in list(args):
        res.insert(0, i)
    return Val("list", res)
Ejemplo n.º 7
0
def dissoc(d, *args):
    keys_to_remove = map(lambda a: a.value, args)
    res = {}
    for key in d.value:
        if key not in keys_to_remove:
            res[key] = d.value[key]
    return Val("hashmap", res)
Ejemplo n.º 8
0
def hashmap(*args):
    arg_list = list(args)
    i = 0
    res = {}
    while i < len(arg_list):
        res[args[i].value] = args[i + 1]
        i += 2
    return Val("hashmap", res)
Ejemplo n.º 9
0
def map_fn(fn, col):
    res = []
    for i in col.value:
        if fn.type == 'fn':
            res.append(*fn.value(i))
        else:
            res.append(fn.value["fn"](i))
    return Val("list", res)
Ejemplo n.º 10
0
def assoc(d, *args):
    res = {}
    for key in d.value:
        res[key] = d.value[key]
    arg_list = list(args)
    i = 0
    while i < len(arg_list):
        res[arg_list[i].value] = arg_list[i + 1]
        i += 2
    return Val("hashmap", res)
Ejemplo n.º 11
0
            def func(*exprs_t):
                new_env = Env(env)
                params = ast.value[1].value
                exprs = list(exprs_t)
                i = 0
                while i < len(params):
                    if params[i].value == "&":
                        new_env.set(params[i + 1].value, Val("list", exprs[i:]))
                        break
                    new_env.set(params[i].value, exprs[i])
                    i += 1

                return eval(ast.value[2], new_env)
Ejemplo n.º 12
0
def quasiquote(ast):
    if not is_pair(ast):
        return Val("list", [Val("symbol", "quote"), ast])

    if ast.value[0].value == "unquote":
        return ast.value[1]

    if is_pair(
            ast.value[0]) and ast.value[0].value[0].value == "splice-unquote":
        return Val("list", [
            Val("symbol", "concat"), ast.value[0].value[1],
            quasiquote(Val("list", ast.value[1:]))
        ])

    return Val("list", [
        Val("symbol", "cons"),
        quasiquote(ast.value[0]),
        quasiquote(Val("list", ast.value[1:]))
    ])
Ejemplo n.º 13
0
def equal_fn(a, b):
    if a.type in ("vector", "list") and b.type in ("vector", "list"):
        if len(a.value) != len(b.value):
            return False
        for i, v in enumerate(a.value):
            if not equal_fn(v, b.value[i]):
                return False
        return True
    if a.type != b.type:
        return False

    if a.type == "hashmap":
        if len(a.value) != len(b.value):
            return False
        for key in a.value:
            if not equal_fn(a.value[key], b.value[key]):
                return False
        return True

    return a.value == b.value

    return Val("list", list(args))
Ejemplo n.º 14
0
def concat(*arg):
    result = []
    for l in list(arg):
        result += l.value
    return Val("list", result)
Ejemplo n.º 15
0
def slurp(arg):
    content = ""
    with open(arg.value, "r") as f:
        content = f.read()
    return Val("string", content)
Ejemplo n.º 16
0
def list_fn(*args):
    return Val("list", list(args))
Ejemplo n.º 17
0
def prn(*args):
    print(" ".join(map(lambda a: pr_str(a, True), list(args))))
    return Val("nil", [])
Ejemplo n.º 18
0
def seq(col):
    if len(col.value) == 0:
        return Val("nil", [])
    if col.type in ('vector', 'list'):
        return Val("list", col.value)

    res = []
    for i in col.value:
        res.append(Val("string", i))
    return Val("list", res)


raw_ns = {
    "+":
    lambda a, b: Val("number", a.value + b.value),
    "-":
    lambda a, b: Val("number", a.value - b.value),
    "*":
    lambda a, b: Val("number", a.value * b.value),
    "/":
    lambda a, b: Val("number", a.value / b.value),
    "<":
    lambda a, b: Val("bool", a.value < b.value),
    "<=":
    lambda a, b: Val("bool", a.value <= b.value),
    ">=":
    lambda a, b: Val("bool", a.value >= b.value),
    ">":
    lambda a, b: Val("bool", a.value > b.value),
    "list":
Ejemplo n.º 19
0
def vector(*args):
    return Val("vector", list(args))
Ejemplo n.º 20
0
def with_meta(value, meta):
    return Val(value.type, value.value, meta)
Ejemplo n.º 21
0
import sys
from reader import read_str, Val
from printer import pr_str
from env import Env
from core import ns

repl_env = Env()
for key in ns:
    repl_env.set(key, ns[key])
repl_env.set("eval", Val("fn", lambda a: eval(a, repl_env)))


def eval_ast(ast, env):
    if ast.type == "symbol":
        return env.get(ast.value)
    if ast.type in ("list", "vector"):
        items = map(lambda ast: eval(ast, env), ast.value)
        return Val(ast.type, items)
    if ast.type == "hashmap":
        new_val = {}
        for key, value in ast.value.items():
            new_val[key] = eval(value, env)
        return Val("hashmap", new_val)
    return ast


def is_pair(ast):
    return ast.type in ("list", "vector") and len(ast.value) > 0


def quasiquote(ast):
Ejemplo n.º 22
0
#!/usr/bin/python3
# -*- coding: utf-8 -*-

import sys
from reader import read_str, Val
from printer import pr_str
from env import Env
from core import ns

repl_env = Env()
for key in ns:
    repl_env.set(key, ns[key])
repl_env.set("eval", Val("fn", lambda a: eval(a, repl_env)))
repl_env.set("*host-language*", Val("string", "Python"))


def eval_ast(ast, env):
    if ast.type == "symbol":
        return env.get(ast.value)
    if ast.type in ("list", "vector"):
        items = map(lambda ast: eval(ast, env), ast.value)
        return Val(ast.type, items)
    if ast.type == "hashmap":
        new_val = {}
        for key, value in ast.value.items():
            new_val[key] = eval(value, env)
        return Val("hashmap", new_val)
    return ast


def is_pair(ast):
Ejemplo n.º 23
0
def str_fn(*args):
    return Val("string", "".join(map(lambda a: pr_str(a, False), list(args))))
Ejemplo n.º 24
0
def eval(ast, env):
    while True:
        if ast.type != "list":
            return eval_ast(ast, env)
        if len(ast.value) == 0:
            return ast

        symbol = ast.value[0].value
        if symbol == "def!":
            evaluated = eval(ast.value[2], env)
            env.set(ast.value[1].value, evaluated)
            return evaluated

        if symbol == "let*":
            new_env = Env(env)
            params = ast.value[1].value

            i = 0
            while i < len(params):
                new_env.set(params[i].value, eval(params[i + 1], new_env))
                i += 2
            ast = ast.value[2]
            env = new_env
            continue

        if symbol == "do":
            evaluated = None
            for i in ast.value[1:-1]:
                eval(i, env)
            ast = ast.value[len(ast.value) -1]
            continue

        if symbol == "if":
            evaluated = None
            cond = eval(ast.value[1], env)
            if cond.type != "nil" and (cond.type != "bool" or cond.value == True):
                ast = ast.value[2]
            elif len(ast.value) > 3:
                ast = ast.value[3]
            else: 
                ast = Val("nil", [])
            continue

        if symbol == "fn*":
            def func(*exprs_t):
                new_env = Env(env)
                params = ast.value[1].value
                exprs = list(exprs_t)
                i = 0
                while i < len(params):
                    if params[i].value == "&":
                        new_env.set(params[i + 1].value, Val("list", exprs[i:]))
                        break
                    new_env.set(params[i].value, exprs[i])
                    i += 1

                return eval(ast.value[2], new_env)

            return Val("custom_fn", {
                "fn": func,
                "ast": ast.value[2],
                "params": ast.value[1].value,
                "env": env
            })

        new_ast = eval_ast(ast, env)

        fn = new_ast.value[0]
        if fn.type == 'custom_fn':
            exprs = new_ast.value[1:]
            ast = fn.value["ast"]
            params = fn.value["params"]
            i = 0
            new_env = Env(fn.value["env"])
            while i < len(params):
                if params[i].value == "&":
                    new_env.set(params[i + 1].value, Val("list", exprs[i:]))
                    break
                new_env.set(params[i].value, exprs[i])
                i += 1
            env = new_env
            continue

        return fn.value(*new_ast.value[1:])
Ejemplo n.º 25
0
def println_fn(*args):
    print(" ".join(map(lambda a: pr_str(a, False), list(args))))
    return Val("nil", [])
Ejemplo n.º 26
0
Archivo: env.py Proyecto: Axnyff/mal
 def get(self, key):
     if key in self.data:
         return self.data[key]
     if self.outer != None:
         return self.outer.get(key)
     raise Exception(Val("string", "'" + key + "' not found"))
Ejemplo n.º 27
0
def eval(ast, env):
    while True:
        ast = macroexpand(ast, env)
        if ast.type != "list":
            return eval_ast(ast, env)
        if len(ast.value) == 0:
            return ast

        symbol = ast.value[0].value

        if symbol == "try*":
            if (len(ast.value) <= 2):
                return eval(ast.value[1], env)
            try:
                return eval(ast.value[1], env)
            except Exception as e:
                error = Val("string", str(e))
                if isinstance(e.args[0], Val):
                    error = e.args[0]
                new_env = Env(env)

                new_env.set(ast.value[2].value[1].value, error)
                return eval(ast.value[2].value[2], new_env)

        if symbol == "macroexpand":
            return macroexpand(ast.value[1], env)

        if symbol == "quote":
            return ast.value[1]

        if symbol == "quasiquote":
            ast = quasiquote(ast.value[1])
            continue

        if symbol == "def!":
            evaluated = eval(ast.value[2], env)
            env.set(ast.value[1].value, evaluated)
            return evaluated

        if symbol == "defmacro!":
            evaluated = Val("macro", eval(ast.value[2], env).value)
            env.set(ast.value[1].value, evaluated)
            return evaluated

        if symbol == "let*":
            new_env = Env(env)
            params = ast.value[1].value

            i = 0
            while i < len(params):
                new_env.set(params[i].value, eval(params[i + 1], new_env))
                i += 2
            ast = ast.value[2]
            env = new_env
            continue

        if symbol == "do":
            for i in ast.value[1:-1]:
                eval(i, env)
            ast = ast.value[len(ast.value) - 1]
            continue

        if symbol == "if":
            cond = eval(ast.value[1], env)
            if cond.type != "nil" and (cond.type != "bool"
                                       or cond.value == True):
                ast = ast.value[2]
            elif len(ast.value) > 3:
                ast = ast.value[3]
            else:
                ast = Val("nil", [])
            continue

        if symbol == "fn*":

            def func(*exprs_t):
                new_env = Env(env)
                params = ast.value[1].value
                exprs = list(exprs_t)
                i = 0
                while i < len(params):
                    if params[i].value == "&":
                        new_env.set(params[i + 1].value,
                                    Val("list", exprs[i:]))
                        break
                    new_env.set(params[i].value, exprs[i])
                    i += 1

                return eval(ast.value[2], new_env)

            return Val(
                "custom_fn", {
                    "fn": func,
                    "ast": ast.value[2],
                    "params": ast.value[1].value,
                    "env": env,
                })

        new_ast = eval_ast(ast, env)

        fn = new_ast.value[0]
        if fn.type == 'custom_fn':
            exprs = new_ast.value[1:]
            ast = fn.value["ast"]
            params = fn.value["params"]
            i = 0
            new_env = Env(fn.value["env"])
            while i < len(params):
                if params[i].value == "&":
                    new_env.set(params[i + 1].value, Val("list", exprs[i:]))
                    break
                new_env.set(params[i].value, exprs[i])
                i += 1
            env = new_env
            continue

        return fn.value(*new_ast.value[1:])