示例#1
0
        static MalVal EVAL(MalVal orig_ast, Env env) {
            MalVal a0, a1, a2, res;
            MalList el;

            while (true) {

            //Console.WriteLine("EVAL: " + printer._pr_str(orig_ast, true));
            if (!orig_ast.list_Q()) {
                return eval_ast(orig_ast, env);
            }

            // apply list
            MalVal expanded = macroexpand(orig_ast, env);
            if (!expanded.list_Q()) {
                return eval_ast(expanded, env);
            } 
            MalList ast = (MalList) expanded;

            if (ast.size() == 0) { return ast; }
            a0 = ast[0];

            String a0sym = a0 is MalSymbol ? ((MalSymbol)a0).getName()
                                           : "__<*fn*>__";

            switch (a0sym) {
            case "def!":
                a1 = ast[1];
                a2 = ast[2];
                res = EVAL(a2, env);
                env.set((MalSymbol)a1, res);
                return res;
            case "let*":
                a1 = ast[1];
                a2 = ast[2];
                MalSymbol key;
                MalVal val;
                Env let_env = new Env(env);
                for(int i=0; i<((MalList)a1).size(); i+=2) {
                    key = (MalSymbol)((MalList)a1)[i];
                    val = ((MalList)a1)[i+1];
                    let_env.set(key, EVAL(val, let_env));
                }
                orig_ast = a2;
                env = let_env;
                break;
            case "quote":
                return ast[1];
            case "quasiquote":
                orig_ast = quasiquote(ast[1]);
                break;
            case "defmacro!":
                a1 = ast[1];
                a2 = ast[2];
                res = EVAL(a2, env);
                ((MalFunc)res).setMacro();
                env.set(((MalSymbol)a1), res);
                return res;
            case "macroexpand":
                a1 = ast[1];
                return macroexpand(a1, env);
            case "try*":
                try {
                    return EVAL(ast[1], env);
                } catch (Exception e) {
                    if (ast.size() > 2) {
                        MalVal exc;
                        a2 = ast[2];
                        MalVal a20 = ((MalList)a2)[0];
                        if (((MalSymbol)a20).getName() == "catch*") {
                            if (e is Mal.types.MalException) {
                                exc = ((Mal.types.MalException)e).getValue();
                            } else {
                                exc = new MalString(e.StackTrace);
                            }
                            return EVAL(((MalList)a2)[2],
                                        new Env(env, ((MalList)a2).slice(1,2),
                                                new MalList(exc)));
                        }
                    }
                    throw e;
                }
            case "do":
                eval_ast(ast.slice(1, ast.size()-1), env);
                orig_ast = ast[ast.size()-1];
                break;
            case "if":
                a1 = ast[1];
                MalVal cond = EVAL(a1, env);
                if (cond == Mal.types.Nil || cond == Mal.types.False) {
                    // eval false slot form
                    if (ast.size() > 3) {
                        orig_ast = ast[3];
                    } else {
                        return Mal.types.Nil;
                    }
                } else {
                    // eval true slot form
                    orig_ast = ast[2];
                }
                break;
            case "fn*":
                MalList a1f = (MalList)ast[1];
                MalVal a2f = ast[2];
                Env cur_env = env;
                return new MalFunc(a2f, env, a1f,
                    args => EVAL(a2f, new Env(cur_env, a1f, args)) );
            default:
                el = (MalList)eval_ast(ast, env);
                var f = (MalFunc)el[0];
                MalVal fnast = f.getAst();
                if (fnast != null) {
                    orig_ast = fnast;
                    env = f.genEnv(el.rest());
                } else {
                    return f.apply(el.rest());
                }
                break;
            }

            }
        }
示例#2
0
        static MalVal EVAL(MalVal orig_ast, Env env)
        {
            MalVal  a0, a1, a2, res;
            MalList el;

            while (true)
            {
                //Console.WriteLine("EVAL: " + printer._pr_str(orig_ast, true));
                if (!orig_ast.list_Q())
                {
                    return(eval_ast(orig_ast, env));
                }

                // apply list
                MalVal expanded = macroexpand(orig_ast, env);
                if (!expanded.list_Q())
                {
                    return(eval_ast(expanded, env));
                }
                MalList ast = (MalList)expanded;

                if (ast.size() == 0)
                {
                    return(ast);
                }
                a0 = ast[0];

                String a0sym = a0 is MalSymbol ? ((MalSymbol)a0).getName()
                                           : "__<*fn*>__";

                switch (a0sym)
                {
                case "def!":
                    a1  = ast[1];
                    a2  = ast[2];
                    res = EVAL(a2, env);
                    env.set((MalSymbol)a1, res);
                    return(res);

                case "let*":
                    a1 = ast[1];
                    a2 = ast[2];
                    MalSymbol key;
                    MalVal    val;
                    Env       let_env = new Env(env);
                    for (int i = 0; i < ((MalList)a1).size(); i += 2)
                    {
                        key = (MalSymbol)((MalList)a1)[i];
                        val = ((MalList)a1)[i + 1];
                        let_env.set(key, EVAL(val, let_env));
                    }
                    orig_ast = a2;
                    env      = let_env;
                    break;

                case "quote":
                    return(ast[1]);

                case "quasiquote":
                    orig_ast = quasiquote(ast[1]);
                    break;

                case "defmacro!":
                    a1  = ast[1];
                    a2  = ast[2];
                    res = EVAL(a2, env);
                    ((MalFunc)res).setMacro();
                    env.set(((MalSymbol)a1), res);
                    return(res);

                case "macroexpand":
                    a1 = ast[1];
                    return(macroexpand(a1, env));

                case "try*":
                    try {
                        return(EVAL(ast[1], env));
                    } catch (Exception e) {
                        if (ast.size() > 2)
                        {
                            MalVal exc;
                            a2 = ast[2];
                            MalVal a20 = ((MalList)a2)[0];
                            if (((MalSymbol)a20).getName() == "catch*")
                            {
                                if (e is Mal.types.MalException)
                                {
                                    exc = ((Mal.types.MalException)e).getValue();
                                }
                                else
                                {
                                    exc = new MalString(e.Message);
                                }
                                return(EVAL(((MalList)a2)[2],
                                            new Env(env, ((MalList)a2).slice(1, 2),
                                                    new MalList(exc))));
                            }
                        }
                        throw e;
                    }

                case "do":
                    eval_ast(ast.slice(1, ast.size() - 1), env);
                    orig_ast = ast[ast.size() - 1];
                    break;

                case "if":
                    a1 = ast[1];
                    MalVal cond = EVAL(a1, env);
                    if (cond == Mal.types.Nil || cond == Mal.types.False)
                    {
                        // eval false slot form
                        if (ast.size() > 3)
                        {
                            orig_ast = ast[3];
                        }
                        else
                        {
                            return(Mal.types.Nil);
                        }
                    }
                    else
                    {
                        // eval true slot form
                        orig_ast = ast[2];
                    }
                    break;

                case "fn*":
                    MalList a1f     = (MalList)ast[1];
                    MalVal  a2f     = ast[2];
                    Env     cur_env = env;
                    return(new MalFunc(a2f, env, a1f,
                                       args => EVAL(a2f, new Env(cur_env, a1f, args))));

                default:
                    el = (MalList)eval_ast(ast, env);
                    var    f     = (MalFunc)el[0];
                    MalVal fnast = f.getAst();
                    if (fnast != null)
                    {
                        orig_ast = fnast;
                        env      = f.genEnv(el.rest());
                    }
                    else
                    {
                        return(f.apply(el.rest()));
                    }
                    break;
                }
            }
        }
示例#3
0
        static MalVal EVAL(MalVal orig_ast, Env env)
        {
            MalVal a0, a1, a2, res;

            while (true)
            {
                MalVal dbgeval = env.get("DEBUG-EVAL");
                if (dbgeval != null && dbgeval != Mal.types.Nil &&
                    dbgeval != Mal.types.False)
                {
                    Console.WriteLine("EVAL: " + printer._pr_str(orig_ast, true));
                }
                if (orig_ast is MalSymbol)
                {
                    string key = ((MalSymbol)orig_ast).getName();
                    res = env.get(key);
                    if (res == null)
                    {
                        throw new Mal.types.MalException("'" + key + "' not found");
                    }
                    return(res);
                }
                else if (orig_ast is MalVector)
                {
                    MalVector old_lst = (MalVector)orig_ast;
                    MalVector new_lst = new MalVector();
                    foreach (MalVal mv in old_lst.getValue())
                    {
                        new_lst.conj_BANG(EVAL(mv, env));
                    }
                    return(new_lst);
                }
                else if (orig_ast is MalHashMap)
                {
                    var new_dict = new Dictionary <string, MalVal>();
                    foreach (var entry in ((MalHashMap)orig_ast).getValue())
                    {
                        new_dict.Add(entry.Key, EVAL((MalVal)entry.Value, env));
                    }
                    return(new MalHashMap(new_dict));
                }
                else if (!(orig_ast is MalList))
                {
                    return(orig_ast);
                }

                // apply list
                MalList ast = (MalList)orig_ast;

                if (ast.size() == 0)
                {
                    return(ast);
                }
                a0 = ast[0];

                String a0sym = a0 is MalSymbol ? ((MalSymbol)a0).getName()
                                           : "__<*fn*>__";

                switch (a0sym)
                {
                case "def!":
                    a1  = ast[1];
                    a2  = ast[2];
                    res = EVAL(a2, env);
                    env.set((MalSymbol)a1, res);
                    return(res);

                case "let*":
                    a1 = ast[1];
                    a2 = ast[2];
                    MalSymbol key;
                    MalVal    val;
                    Env       let_env = new Env(env);
                    for (int i = 0; i < ((MalList)a1).size(); i += 2)
                    {
                        key = (MalSymbol)((MalList)a1)[i];
                        val = ((MalList)a1)[i + 1];
                        let_env.set(key, EVAL(val, let_env));
                    }
                    orig_ast = a2;
                    env      = let_env;
                    break;

                case "quote":
                    return(ast[1]);

                case "quasiquote":
                    orig_ast = quasiquote(ast[1]);
                    break;

                case "defmacro!":
                    a1  = ast[1];
                    a2  = ast[2];
                    res = EVAL(a2, env);
                    res = res.copy();
                    ((MalFunc)res).setMacro();
                    env.set(((MalSymbol)a1), res);
                    return(res);

                case "try*":
                    try {
                        return(EVAL(ast[1], env));
                    } catch (Exception e) {
                        if (ast.size() > 2)
                        {
                            MalVal exc;
                            a2 = ast[2];
                            MalVal a20 = ((MalList)a2)[0];
                            if (((MalSymbol)a20).getName() == "catch*")
                            {
                                if (e is Mal.types.MalException)
                                {
                                    exc = ((Mal.types.MalException)e).getValue();
                                }
                                else
                                {
                                    exc = new MalString(e.Message);
                                }
                                return(EVAL(((MalList)a2)[2],
                                            new Env(env, ((MalList)a2).slice(1, 2),
                                                    new MalList(exc))));
                            }
                        }
                        throw e;
                    }

                case "do":
                    foreach (MalVal mv in ast.slice(1, ast.size() - 1).getValue())
                    {
                        EVAL(mv, env);
                    }
                    orig_ast = ast[ast.size() - 1];
                    break;

                case "if":
                    a1 = ast[1];
                    MalVal cond = EVAL(a1, env);
                    if (cond == Mal.types.Nil || cond == Mal.types.False)
                    {
                        // eval false slot form
                        if (ast.size() > 3)
                        {
                            orig_ast = ast[3];
                        }
                        else
                        {
                            return(Mal.types.Nil);
                        }
                    }
                    else
                    {
                        // eval true slot form
                        orig_ast = ast[2];
                    }
                    break;

                case "fn*":
                    MalList a1f     = (MalList)ast[1];
                    MalVal  a2f     = ast[2];
                    Env     cur_env = env;
                    return(new MalFunc(a2f, env, a1f,
                                       args => EVAL(a2f, new Env(cur_env, a1f, args))));

                default:
                    MalFunc f = (MalFunc)EVAL(ast[0], env);
                    if (f.isMacro())
                    {
                        orig_ast = f.apply(ast.rest());
                        break;
                    }
                    MalList arguments = new MalList();
                    foreach (MalVal mv in ast.rest().getValue())
                    {
                        arguments.conj_BANG(EVAL(mv, env));
                    }
                    MalVal fnast = f.getAst();
                    if (fnast != null)
                    {
                        orig_ast = fnast;
                        env      = f.genEnv(arguments);
                    }
                    else
                    {
                        return(f.apply(arguments));
                    }
                    break;
                }
            }
        }