Example #1
0
def quasiquote(ast):
    if not is_pair(ast):
        return types._list(types._symbol("quote"), ast)
    elif ast[0] == "unquote":
        return ast[1]
    elif is_pair(ast[0]) and ast[0][0] == "splice-unquote":
        return types._list(types._symbol("concat"), ast[0][1], quasiquote(ast[1:]))
    else:
        return types._list(types._symbol("cons"), quasiquote(ast[0]), quasiquote(ast[1:]))
Example #2
0
def quasiquote(ast):
    if not is_pair(ast):
        return types._list(types._symbol("quote"), ast)
    elif ast[0] == 'unquote':
        return ast[1]
    elif is_pair(ast[0]) and ast[0][0] == 'splice-unquote':
        return types._list(types._symbol("concat"), ast[0][1],
                           quasiquote(ast[1:]))
    else:
        return types._list(types._symbol("cons"), quasiquote(ast[0]),
                           quasiquote(ast[1:]))
Example #3
0
def quasiquote(ast):
    if types._list_Q(ast):
        if len(ast) == 2 and ast[0] == u'unquote':
            return ast[1]
        else:
            return qq_foldr(ast)
    elif types._hash_map_Q(ast) or types._symbol_Q(ast):
        return types._list(types._symbol(u'quote'), ast)
    elif types._vector_Q(ast):
        return types._list(types._symbol(u'vec'), qq_foldr(ast))
    else:
        return ast
Example #4
0
def quasiquote(ast):
    if not is_pair(ast):
        return _list(_symbol(u"quote"), ast)
    else:
        a0 = ast[0]
        if isinstance(a0, MalSym):
            if a0.value == u'unquote':
                return ast[1]
        if is_pair(a0) and isinstance(a0[0], MalSym):
            a00 = a0[0]
            if (isinstance(a00, MalSym) and a00.value == u'splice-unquote'):
                return _list(_symbol(u"concat"), a0[1], quasiquote(ast.rest()))
    return _list(_symbol(u"cons"), quasiquote(a0), quasiquote(ast.rest()))
Example #5
0
def quasiquote(ast):
    if types._list_Q(ast):
        if len(ast) == 2:
            fst = ast[0]
            if isinstance(fst, MalSym) and fst.value == u"unquote":
                return ast[1]
        return qq_foldr(ast.values)
    elif types._vector_Q(ast):
        return _list(_symbol(u"vec"), qq_foldr(ast.values))
    elif types._symbol_Q(ast) or types._hash_map_Q(ast):
        return _list(_symbol(u"quote"), ast)
    else:
        return ast
Example #6
0
def quasiquote(ast):
    if not is_pair(ast):
        return _list(_symbol(u"quote"), ast)
    else:
        a0 = ast[0]
        if isinstance(a0, MalSym):
            if a0.value == u'unquote':
                return ast[1]
        if is_pair(a0) and isinstance(a0[0], MalSym):
            a00 = a0[0]
            if (isinstance(a00, MalSym) and
                a00.value == u'splice-unquote'):
                return _list(_symbol(u"concat"),
                             a0[1],
                             quasiquote(ast.rest()))
    return _list(_symbol(u"cons"),
                quasiquote(a0),
                quasiquote(ast.rest()))
Example #7
0
def eval_ast(ast, env):
    if types._symbol_Q(ast):
        return env.get(ast)
    elif types._list_Q(ast):
        return types._list(*map(lambda a: EVAL(a, env), ast))
    elif types._vector_Q(ast):
        return types._vector(*map(lambda a: EVAL(a, env), ast))
    elif types._hash_map_Q(ast):
        return types.Hash_Map((k, EVAL(v, env)) for k, v in ast.items())
    else:
        return ast  # primitive value, return unchanged
Example #8
0
def eval_ast(ast, env):
    if types._symbol_Q(ast):
        try:
            return env[ast]
        except:
            raise Exception("'" + ast + "' not found")
    elif types._list_Q(ast):
        return types._list(*map(lambda a: EVAL(a, env), ast))
    elif types._vector_Q(ast):
        return types._vector(*map(lambda a: EVAL(a, env), ast))
    elif types._hash_map_Q(ast):
        return types.Hash_Map((k, EVAL(v, env)) for k, v in ast.items())
    else:
        return ast  # primitive value, return unchanged
Example #9
0
def eval_ast(ast, env):
    if types._symbol_Q(ast):
        return env.get(ast)
    elif types._list_Q(ast):
        return types._list(*map(lambda a: EVAL(a, env), ast))
    elif types._vector_Q(ast):
        return types._vector(*map(lambda a: EVAL(a, env), ast))
    elif types._hash_map_Q(ast):
        keyvals = []
        for k in ast.keys():
            keyvals.append(EVAL(k, env))
            keyvals.append(EVAL(ast[k], env))
        return types._hash_map(*keyvals)
    else:
        return ast  # primitive value, return unchanged
Example #10
0
def eval_ast(ast, env):
    if types._symbol_Q(ast):
        return env.get(ast)
    elif types._list_Q(ast):
        return types._list(*map(lambda a: EVAL(a, env), ast))
    elif types._vector_Q(ast):
        return types._vector(*map(lambda a: EVAL(a, env), ast))
    elif types._hash_map_Q(ast):
        keyvals = []
        for k in ast.keys():
            keyvals.append(EVAL(k, env))
            keyvals.append(EVAL(ast[k], env))
        return types._hash_map(*keyvals)
    else:
        return ast  # primitive value, return unchanged
Example #11
0
def eval_ast(ast, env):
    if types._symbol_Q(ast):
        try:
            return env[ast]
        except:
            raise Exception("'" + ast + "' not found")
    elif types._list_Q(ast):
        return types._list(*map(lambda a: EVAL(a, env), ast))
    elif types._vector_Q(ast):
        return types._vector(*map(lambda a: EVAL(a, env), ast))
    elif types._hash_map_Q(ast):
        keyvals = []
        for k in ast.keys():
            keyvals.append(EVAL(k, env))
            keyvals.append(EVAL(ast[k], env))
        return types._hash_map(*keyvals)
    else:
        return ast  # primitive value, return unchanged
Example #12
0
File: reader.py Project: vo0doO/mal
def read_form(reader):
    token = reader.peek()
    # reader macros/transforms
    if token[0] == ";":
        reader.next()
        return None
    elif token == "'":
        reader.next()
        return _list(_symbol("quote"), read_form(reader))
    elif token == "`":
        reader.next()
        return _list(_symbol("quasiquote"), read_form(reader))
    elif token == "~":
        reader.next()
        return _list(_symbol("unquote"), read_form(reader))
    elif token == "~@":
        reader.next()
        return _list(_symbol("splice-unquote"), read_form(reader))
    elif token == "^":
        reader.next()
        meta = read_form(reader)
        return _list(_symbol("with-meta"), read_form(reader), meta)
    elif token == "@":
        reader.next()
        return _list(_symbol("deref"), read_form(reader))

    # list
    elif token == ")":
        raise Exception("unexpected ')'")
    elif token == "(":
        return read_list(reader)

    # vector
    elif token == "]":
        raise Exception("unexpected ']'")
    elif token == "[":
        return read_vector(reader)

    # hash-map
    elif token == "}":
        raise Exception("unexpected '}'")
    elif token == "{":
        return read_hash_map(reader)

    # atom
    else:
        return read_atom(reader)
Example #13
0
def read_form(reader):
    token = reader.peek()
    # reader macros/transforms
    if token[0] == ';':
        reader.next()
        return None
    elif token == '\'':
        reader.next()
        return _list(MalSym(u'quote'), read_form(reader))
    elif token == '`':
        reader.next()
        return _list(MalSym(u'quasiquote'), read_form(reader))
    elif token == '~':
        reader.next()
        return _list(MalSym(u'unquote'), read_form(reader))
    elif token == '~@':
        reader.next()
        return _list(MalSym(u'splice-unquote'), read_form(reader))
    elif token == '^':
        reader.next()
        meta = read_form(reader)
        return _list(MalSym(u'with-meta'), read_form(reader), meta)
    elif token == '@':
        reader.next()
        return _list(MalSym(u'deref'), read_form(reader))

    # list
    elif token == ')':
        types.throw_str("unexpected ')'")
    elif token == '(':
        return read_list(reader)

        # vector
    elif token == ']':
        types.throw_str("unexpected ']'")
    elif token == '[':
        return read_vector(reader)

        # hash-map
    elif token == '}':
        types.throw_str("unexpected '}'")
    elif token == '{':
        return read_hash_map(reader)

        # atom
    else:
        return read_atom(reader)
Example #14
0
def read_form(reader):
    token = reader.peek()
    # reader macros/transforms
    if token[0] == ';':
        reader.next()
        return None
    elif token == '\'':
        reader.next()
        return _list(MalSym(u'quote'), read_form(reader))
    elif token == '`':
        reader.next()
        return _list(MalSym(u'quasiquote'), read_form(reader))
    elif token == '~':
        reader.next()
        return _list(MalSym(u'unquote'), read_form(reader))
    elif token == '~@':
        reader.next()
        return _list(MalSym(u'splice-unquote'), read_form(reader))
    elif token == '^':
        reader.next()
        meta = read_form(reader)
        return _list(MalSym(u'with-meta'), read_form(reader), meta)
    elif token == '@':
        reader.next()
        return _list(MalSym(u'deref'), read_form(reader))

    # list
    elif token == ')': types.throw_str("unexpected ')'")
    elif token == '(': return read_list(reader)

    # vector
    elif token == ']': types.throw_str("unexpected ']'");
    elif token == '[': return read_vector(reader);

    # hash-map
    elif token == '}': types.throw_str("unexpected '}'");
    elif token == '{': return read_hash_map(reader);

    # atom
    else:              return read_atom(reader);
Example #15
0
def qq_foldr(seq):
    return functools.reduce(qq_loop, reversed(seq), types._list())
Example #16
0
def qq_loop(acc, elt):
    if types._list_Q(elt) and len(elt) == 2 and elt[0] == u'splice-unquote':
        return types._list(types._symbol(u'concat'), elt[1], acc)
    else:
        return types._list(types._symbol(u'cons'), quasiquote(elt), acc)
Example #17
0
    return printer._pr_str(exp)


# repl
repl_env = Env()


def REP(str):
    return PRINT(EVAL(READ(str), repl_env))


# core.py: defined using python
for k, v in core.ns.items():
    repl_env.set(types._symbol(k), v)
repl_env.set(types._symbol('eval'), lambda ast: EVAL(ast, repl_env))
repl_env.set(types._symbol('*ARGV*'), types._list(*sys.argv[2:]))

# core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))"
    )
REP("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))"
    )

if len(sys.argv) >= 2:
    REP('(load-file "' + sys.argv[1] + '")')
    sys.exit(0)

# repl loop
while True:
    try:
Example #18
0
def EVAL(ast, env):
    while True:
        #print("EVAL %s" % printer._pr_str(ast))
        if not types._list_Q(ast):
            return eval_ast(ast, env)
        if len(ast) == 0: return ast

        # apply list
        ast = macroexpand(ast, env)
        if not types._list_Q(ast):
            return eval_ast(ast, env)
        if len(ast) == 0: return ast
        a0 = ast[0]
        if isinstance(a0, MalSym):
            a0sym = a0.value
        else:
            a0sym = u"__<*fn*>__"

        if u"def!" == a0sym:
            a1, a2 = ast[1], ast[2]
            res = EVAL(a2, env)
            return env.set(a1, res)
        elif u"let*" == a0sym:
            a1, a2 = ast[1], ast[2]
            let_env = Env(env)
            for i in range(0, len(a1), 2):
                let_env.set(a1[i], EVAL(a1[i+1], let_env))
            ast = a2
            env = let_env # Continue loop (TCO)
        elif u"quote" == a0sym:
            return ast[1]
        elif u"quasiquote" == a0sym:
            ast = quasiquote(ast[1]) # Continue loop (TCO)
        elif u"defmacro!" == a0sym:
            func = EVAL(ast[2], env)
            func.ismacro = True
            return env.set(ast[1], func)
        elif u"macroexpand" == a0sym:
            return macroexpand(ast[1], env)
        elif u"try*" == a0sym:
            if len(ast) < 3:
                return EVAL(ast[1], env);
            a1, a2 = ast[1], ast[2]
            a20 = a2[0]
            if isinstance(a20, MalSym):
                if a20.value == u"catch*":
                    try:
                        return EVAL(a1, env);
                    except types.MalException as exc:
                        exc = exc.object
                        catch_env = Env(env, _list(a2[1]), _list(exc))
                        return EVAL(a2[2], catch_env)
                    except Exception as exc:
                        exc = MalStr(unicode("%s" % exc))
                        catch_env = Env(env, _list(a2[1]), _list(exc))
                        return EVAL(a2[2], catch_env)
            return EVAL(a1, env);
        elif u"do" == a0sym:
            if len(ast) == 0:
                return nil
            elif len(ast) > 1:
                eval_ast(ast.slice2(1, len(ast)-1), env)
            ast = ast[-1] # Continue loop (TCO)
        elif u"if" == a0sym:
            a1, a2 = ast[1], ast[2]
            cond = EVAL(a1, env)
            if cond is nil or cond is false:
                if len(ast) > 3: ast = ast[3] # Continue loop (TCO)
                else:            return nil
            else:
                ast = a2 # Continue loop (TCO)
        elif u"fn*" == a0sym:
            a1, a2 = ast[1], ast[2]
            return MalFunc(None, a2, env, a1, EVAL)
        else:
            el = eval_ast(ast, env)
            f = el.values[0]
            if isinstance(f, MalFunc):
                if f.ast:
                    ast = f.ast
                    env = f.gen_env(el.rest()) # Continue loop (TCO) 
                else:
                    return f.apply(el.rest())
            else:
                raise Exception("%s is not callable" % f)
Example #19
0
def qq_loop(elt, acc):
    if types._list_Q(elt) and len(elt) == 2:
        fst = elt[0]
        if isinstance(fst, MalSym) and fst.value == u"splice-unquote":
            return _list(_symbol(u"concat"), elt[1], acc)
    return _list(_symbol(u"cons"), quasiquote(elt), acc)
Example #20
0
def EVAL(ast, env):
    while True:
        #print("EVAL %s" % printer._pr_str(ast))
        if not types._list_Q(ast):
            return eval_ast(ast, env)
        if len(ast) == 0: return ast

        # apply list
        ast = macroexpand(ast, env)
        if not types._list_Q(ast):
            return eval_ast(ast, env)
        if len(ast) == 0: return ast
        a0 = ast[0]
        if isinstance(a0, MalSym):
            a0sym = a0.value
        else:
            a0sym = u"__<*fn*>__"

        if u"def!" == a0sym:
            a1, a2 = ast[1], ast[2]
            res = EVAL(a2, env)
            return env.set(a1, res)
        elif u"let*" == a0sym:
            a1, a2 = ast[1], ast[2]
            let_env = Env(env)
            for i in range(0, len(a1), 2):
                let_env.set(a1[i], EVAL(a1[i + 1], let_env))
            ast = a2
            env = let_env  # Continue loop (TCO)
        elif u"quote" == a0sym:
            return ast[1]
        elif u"quasiquote" == a0sym:
            ast = quasiquote(ast[1])  # Continue loop (TCO)
        elif u"defmacro!" == a0sym:
            func = EVAL(ast[2], env)
            func.ismacro = True
            return env.set(ast[1], func)
        elif u"macroexpand" == a0sym:
            return macroexpand(ast[1], env)
        elif u"try*" == a0sym:
            if len(ast) < 3:
                return EVAL(ast[1], env)
            a1, a2 = ast[1], ast[2]
            a20 = a2[0]
            if isinstance(a20, MalSym):
                if a20.value == u"catch*":
                    try:
                        return EVAL(a1, env)
                    except types.MalException as exc:
                        exc = exc.object
                        catch_env = Env(env, _list(a2[1]), _list(exc))
                        return EVAL(a2[2], catch_env)
                    except Exception as exc:
                        exc = MalStr(unicode("%s" % exc))
                        catch_env = Env(env, _list(a2[1]), _list(exc))
                        return EVAL(a2[2], catch_env)
            return EVAL(a1, env)
        elif u"do" == a0sym:
            if len(ast) == 0:
                return nil
            elif len(ast) > 1:
                eval_ast(ast.slice2(1, len(ast) - 1), env)
            ast = ast[-1]  # Continue loop (TCO)
        elif u"if" == a0sym:
            a1, a2 = ast[1], ast[2]
            cond = EVAL(a1, env)
            if cond is nil or cond is false:
                if len(ast) > 3: ast = ast[3]  # Continue loop (TCO)
                else: return nil
            else:
                ast = a2  # Continue loop (TCO)
        elif u"fn*" == a0sym:
            a1, a2 = ast[1], ast[2]
            return MalFunc(None, a2, env, a1, EVAL)
        else:
            el = eval_ast(ast, env)
            f = el.values[0]
            if isinstance(f, MalFunc):
                if f.ast:
                    ast = f.ast
                    env = f.gen_env(el.rest())  # Continue loop (TCO)
                else:
                    return f.apply(el.rest())
            else:
                raise Exception("%s is not callable" % f)
Example #21
0
File: core.py Project: BlinkD/mal
def keys(hm): return types._list(*hm.keys())

def vals(hm): return types._list(*hm.values())
Example #22
0
def vals(hm): return types._list(*hm.values())


# Sequence functions
def coll_Q(coll): return sequential_Q(coll) or hash_map_Q(coll)
Example #23
0
def keys(hm): return types._list(*hm.keys())

def vals(hm): return types._list(*hm.values())
Example #24
0
            else:
                return f(*el[1:])

# print
def PRINT(exp):
    return printer._pr_str(exp)

# repl
repl_env = Env()
def REP(str):
    return PRINT(EVAL(READ(str), repl_env))

# core.py: defined using python
for k, v in core.ns.items(): repl_env.set(k, v)
repl_env.set('eval', lambda ast: EVAL(ast, repl_env))
repl_env.set('*ARGV*', types._list(*sys.argv[2:]))

# core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
REP("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))")
REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))")

if len(sys.argv) >= 2:
    REP('(load-file "' + sys.argv[1] + '")')
    sys.exit(0)

# repl loop
while True:
    try:
        line = mal_readline.readline("user> ")
Example #25
0
def EVAL(ast, env):
    while True:
        #print("EVAL %s" % printer._pr_str(ast))
        if types._symbol_Q(ast):
            assert isinstance(ast, MalSym)
            return env.get(ast)
        elif types._vector_Q(ast):
            res = []
            for a in ast.values:
                res.append(EVAL(a, env))
            return MalVector(res)
        elif types._hash_map_Q(ast):
            new_dct = {}
            for k in ast.dct.keys():
                new_dct[k] = EVAL(ast.dct[k], env)
            return MalHashMap(new_dct)
        elif not types._list_Q(ast):
            return ast  # primitive value, return unchanged
        else:
            # apply list
            if len(ast) == 0: return ast
            a0 = ast[0]
            if isinstance(a0, MalSym):
                a0sym = a0.value
            else:
                a0sym = u"__<*fn*>__"

            if u"def!" == a0sym:
                a1, a2 = ast[1], ast[2]
                res = EVAL(a2, env)
                return env.set(a1, res)
            elif u"let*" == a0sym:
                a1, a2 = ast[1], ast[2]
                let_env = Env(env)
                for i in range(0, len(a1), 2):
                    let_env.set(a1[i], EVAL(a1[i + 1], let_env))
                ast = a2
                env = let_env  # Continue loop (TCO)
            elif u"quote" == a0sym:
                return ast[1]
            elif u"quasiquote" == a0sym:
                ast = quasiquote(ast[1])  # Continue loop (TCO)
            elif u"defmacro!" == a0sym:
                func = EVAL(ast[2], env)
                func.ismacro = True
                return env.set(ast[1], func)
            elif u"try*" == a0sym:
                if len(ast) < 3:
                    return EVAL(ast[1], env)
                a1, a2 = ast[1], ast[2]
                a20 = a2[0]
                if isinstance(a20, MalSym):
                    if a20.value == u"catch*":
                        try:
                            return EVAL(a1, env)
                        except types.MalException as exc:
                            exc = exc.object
                            catch_env = Env(env, _list(a2[1]), _list(exc))
                            return EVAL(a2[2], catch_env)
                        except Exception as exc:
                            exc = MalStr(unicode("%s" % exc))
                            catch_env = Env(env, _list(a2[1]), _list(exc))
                            return EVAL(a2[2], catch_env)
                return EVAL(a1, env)
            elif u"do" == a0sym:
                if len(ast) == 0:
                    return nil
                for i in range(1, len(ast) - 1):
                    EVAL(ast[i], env)
                ast = ast[-1]  # Continue loop (TCO)
            elif u"if" == a0sym:
                a1, a2 = ast[1], ast[2]
                cond = EVAL(a1, env)
                if cond is nil or cond is false:
                    if len(ast) > 3: ast = ast[3]  # Continue loop (TCO)
                    else: return nil
                else:
                    ast = a2  # Continue loop (TCO)
            elif u"fn*" == a0sym:
                a1, a2 = ast[1], ast[2]
                return MalFunc(None, a2, env, a1, EVAL)
            else:
                f = EVAL(a0, env)
                args = ast.rest()
                if f.ismacro:
                    ast = f.apply(ast.rest())  # Continue loop (TCO)
                else:
                    res = []
                    for a in args.values:
                        res.append(EVAL(a, env))
                    el = MalList(res)
                    if isinstance(f, MalFunc):
                        if f.ast:
                            ast = f.ast
                            env = f.gen_env(el)  # Continue loop (TCO)
                        else:
                            return f.apply(el)
                    else:
                        raise Exception("%s is not callable" % f)
Example #26
0
def keys(hm):
    return types._list(*hm.keys())
Example #27
0
File: core.py Project: BlinkD/mal
def vals(hm): return types._list(*hm.values())


# Sequence functions
def coll_Q(coll): return sequential_Q(coll) or hash_map_Q(coll)
Example #28
0
            else:
                return f(*el[1:])

# print
def PRINT(exp):
    return printer._pr_str(exp)

# repl
repl_env = Env()
def REP(str):
    return PRINT(EVAL(READ(str), repl_env))

# core.py: defined using python
for k, v in core.ns.items(): repl_env.set(types._symbol(k), v)
repl_env.set(types._symbol('eval'), lambda ast: EVAL(ast, repl_env))
repl_env.set(types._symbol('*ARGV*'), types._list(*sys.argv[2:]))

# core.mal: defined using the language itself
REP("(def! *host-language* \"python\")")
REP("(def! not (fn* (a) (if a false true)))")
REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
REP("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))")
REP("(def! *gensym-counter* (atom 0))")
REP("(def! gensym (fn* [] (symbol (str \"G__\" (swap! *gensym-counter* (fn* [x] (+ 1 x)))))))")
REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) (let* (condvar (gensym)) `(let* (~condvar ~(first xs)) (if ~condvar ~condvar (or ~@(rest xs)))))))))")

if len(sys.argv) >= 2:
    REP('(load-file "' + sys.argv[1] + '")')
    sys.exit(0)

# repl loop
Example #29
0
def qq_foldr(seq):
    acc = _list()
    for elt in reversed(seq):
        acc = qq_loop(elt, acc)
    return acc