Esempio n. 1
0
function MAL_EVAL($ast, $env)
{
    while (true) {
        #echo "MAL_EVAL: " . _pr_str($ast) . "\n";
        if (!_list_Q($ast)) {
            return eval_ast($ast, $env);
        }
        // apply list
        $ast = macroexpand($ast, $env);
        if (!_list_Q($ast)) {
            return eval_ast($ast, $env);
        }
        if ($ast->count() === 0) {
            return $ast;
        }
        $a0 = $ast[0];
        $a0v = _symbol_Q($a0) ? $a0->value : $a0;
        switch ($a0v) {
            case "def!":
                $res = MAL_EVAL($ast[2], $env);
                return $env->set($ast[1], $res);
            case "let*":
                $a1 = $ast[1];
                $let_env = new Env($env);
                for ($i = 0; $i < count($a1); $i += 2) {
                    $let_env->set($a1[$i], MAL_EVAL($a1[$i + 1], $let_env));
                }
                $ast = $ast[2];
                $env = $let_env;
                break;
                // Continue loop (TCO)
            // Continue loop (TCO)
            case "quote":
                return $ast[1];
            case "quasiquote":
                $ast = quasiquote($ast[1]);
                break;
                // Continue loop (TCO)
            // Continue loop (TCO)
            case "defmacro!":
                $func = MAL_EVAL($ast[2], $env);
                $func->ismacro = true;
                return $env->set($ast[1], $func);
            case "macroexpand":
                return macroexpand($ast[1], $env);
            case "php*":
                $res = eval($ast[1]);
                switch (gettype($res)) {
                    case "array":
                        if ($res !== array_values($res)) {
                            $new_res = _hash_map();
                            $new_res->exchangeArray($res);
                            return $new_res;
                        } else {
                            return call_user_func_array('_list', $res);
                        }
                    default:
                        return $res;
                }
            case "try*":
                $a1 = $ast[1];
                $a2 = $ast[2];
                if ($a2[0]->value === "catch*") {
                    try {
                        return MAL_EVAL($a1, $env);
                    } catch (Error $e) {
                        $catch_env = new Env($env, array($a2[1]), array($e->obj));
                        return MAL_EVAL($a2[2], $catch_env);
                    } catch (Exception $e) {
                        $catch_env = new Env($env, array($a2[1]), array($e->getMessage()));
                        return MAL_EVAL($a2[2], $catch_env);
                    }
                } else {
                    return MAL_EVAL($a1, $env);
                }
            case "do":
                eval_ast($ast->slice(1, -1), $env);
                $ast = $ast[count($ast) - 1];
                break;
                // Continue loop (TCO)
            // Continue loop (TCO)
            case "if":
                $cond = MAL_EVAL($ast[1], $env);
                if ($cond === NULL || $cond === false) {
                    if (count($ast) === 4) {
                        $ast = $ast[3];
                    } else {
                        $ast = NULL;
                    }
                } else {
                    $ast = $ast[2];
                }
                break;
                // Continue loop (TCO)
            // Continue loop (TCO)
            case "fn*":
                return _function('MAL_EVAL', 'native', $ast[2], $env, $ast[1]);
            default:
                $el = eval_ast($ast, $env);
                $f = $el[0];
                $args = array_slice($el->getArrayCopy(), 1);
                if ($f->type === 'native') {
                    $ast = $f->ast;
                    $env = $f->gen_env($args);
                    // Continue loop (TCO)
                } else {
                    return $f->apply($args);
                }
        }
    }
}
Esempio n. 2
0
function MAL_EVAL($ast, $env)
{
    while (true) {
        #echo "MAL_EVAL: " . _pr_str($ast) . "\n";
        if (!_list_Q($ast)) {
            return eval_ast($ast, $env);
        }
        // apply list
        $ast = macroexpand($ast, $env);
        if (!_list_Q($ast)) {
            return eval_ast($ast, $env);
        }
        if ($ast->count() === 0) {
            return $ast;
        }
        $a0 = $ast[0];
        $a0v = _symbol_Q($a0) ? $a0->value : $a0;
        switch ($a0v) {
            case "def!":
                $res = MAL_EVAL($ast[2], $env);
                return $env->set($ast[1], $res);
            case "let*":
                $a1 = $ast[1];
                $let_env = new Env($env);
                for ($i = 0; $i < count($a1); $i += 2) {
                    $let_env->set($a1[$i], MAL_EVAL($a1[$i + 1], $let_env));
                }
                $ast = $ast[2];
                $env = $let_env;
                break;
                // Continue loop (TCO)
            // Continue loop (TCO)
            case "quote":
                return $ast[1];
            case "quasiquote":
                $ast = quasiquote($ast[1]);
                break;
                // Continue loop (TCO)
            // Continue loop (TCO)
            case "defmacro!":
                $func = MAL_EVAL($ast[2], $env);
                $func->ismacro = true;
                return $env->set($ast[1], $func);
            case "macroexpand":
                return macroexpand($ast[1], $env);
            case "do":
                eval_ast($ast->slice(1, -1), $env);
                $ast = $ast[count($ast) - 1];
                break;
                // Continue loop (TCO)
            // Continue loop (TCO)
            case "if":
                $cond = MAL_EVAL($ast[1], $env);
                if ($cond === NULL || $cond === false) {
                    if (count($ast) === 4) {
                        $ast = $ast[3];
                    } else {
                        $ast = NULL;
                    }
                } else {
                    $ast = $ast[2];
                }
                break;
                // Continue loop (TCO)
            // Continue loop (TCO)
            case "fn*":
                return _function('MAL_EVAL', 'native', $ast[2], $env, $ast[1]);
            default:
                $el = eval_ast($ast, $env);
                $f = $el[0];
                $args = array_slice($el->getArrayCopy(), 1);
                if ($f->type === 'native') {
                    $ast = $f->ast;
                    $env = $f->gen_env($args);
                    // Continue loop (TCO)
                } else {
                    return $f->apply($args);
                }
        }
    }
}
Esempio n. 3
0
}
// print
function MAL_PRINT($exp)
{
    return _pr_str($exp, True);
}
// repl
$repl_env = new Env(NULL);
function rep($str)
{
    global $repl_env;
    return MAL_PRINT(MAL_EVAL(READ($str), $repl_env));
}
// core.php: defined using PHP
foreach ($core_ns as $k => $v) {
    $repl_env->set(_symbol($k), _function($v));
}
// core.mal: defined using the language itself
rep("(def! not (fn* (a) (if a false true)))");
// repl loop
do {
    try {
        $line = mal_readline("user> ");
        if ($line === NULL) {
            break;
        }
        if ($line !== "") {
            print rep($line) . "\n";
        }
    } catch (BlankException $e) {
        continue;