1
1
mirror of https://github.com/kanaka/mal.git synced 2024-09-19 17:47:53 +03:00
mal/impls/d/step2_eval.d
Joel Martin 8a19f60386 Move implementations into impls/ dir
- Reorder README to have implementation list after "learning tool"
  bullet.

- This also moves tests/ and libs/ into impls. It would be preferrable
  to have these directories at the top level.  However, this causes
  difficulties with the wasm implementations which need pre-open
  directories and have trouble with paths starting with "../../". So
  in lieu of that, symlink those directories to the top-level.

- Move the run_argv_test.sh script into the tests directory for
  general hygiene.
2020-02-10 23:50:16 -06:00

133 lines
2.9 KiB
D

import std.algorithm;
import std.array;
import std.stdio;
import std.string;
import readline;
import reader;
import printer;
import types;
alias Env = MalType[string];
MalType READ(string str)
{
return read_str(str);
}
MalType eval_ast(MalType ast, Env env)
{
if (auto sym = cast(MalSymbol)ast)
{
auto v = (sym.name in env);
if (v is null) throw new Exception("'" ~ sym.name ~ "' not found");
return *v;
}
else if (auto lst = cast(MalList)ast)
{
auto el = array(lst.elements.map!(e => EVAL(e, env)));
return new MalList(el);
}
else if (auto lst = cast(MalVector)ast)
{
auto el = array(lst.elements.map!(e => EVAL(e, env)));
return new MalVector(el);
}
else if (auto hm = cast(MalHashmap)ast)
{
typeof(hm.data) new_data;
foreach (string k, MalType v; hm.data)
{
new_data[k] = EVAL(v, env);
}
return new MalHashmap(new_data);
}
else
{
return ast;
}
}
MalType EVAL(MalType ast, Env env)
{
if (typeid(ast) != typeid(MalList))
{
return eval_ast(ast, env);
}
if ((cast(MalList) ast).elements.length == 0)
{
return ast;
}
auto el = verify_cast!MalList(eval_ast(ast, env));
auto fobj = verify_cast!MalBuiltinFunc(el.elements[0]);
auto args = el.elements[1..$];
return fobj.fn(args);
}
string PRINT(MalType ast)
{
return pr_str(ast);
}
string rep(string str, Env env)
{
return PRINT(EVAL(READ(str), env));
}
static MalType mal_add(MalType[] a ...)
{
verify_args_count(a, 2);
MalInteger i0 = verify_cast!MalInteger(a[0]);
MalInteger i1 = verify_cast!MalInteger(a[1]);
return new MalInteger(i0.val + i1.val);
}
static MalType mal_sub(MalType[] a ...)
{
verify_args_count(a, 2);
MalInteger i0 = verify_cast!MalInteger(a[0]);
MalInteger i1 = verify_cast!MalInteger(a[1]);
return new MalInteger(i0.val - i1.val);
}
static MalType mal_mul(MalType[] a ...)
{
verify_args_count(a, 2);
MalInteger i0 = verify_cast!MalInteger(a[0]);
MalInteger i1 = verify_cast!MalInteger(a[1]);
return new MalInteger(i0.val * i1.val);
}
static MalType mal_div(MalType[] a ...)
{
verify_args_count(a, 2);
MalInteger i0 = verify_cast!MalInteger(a[0]);
MalInteger i1 = verify_cast!MalInteger(a[1]);
return new MalInteger(i0.val / i1.val);
}
void main()
{
Env repl_env;
repl_env["+"] = new MalBuiltinFunc(&mal_add, "+");
repl_env["-"] = new MalBuiltinFunc(&mal_sub, "-");
repl_env["*"] = new MalBuiltinFunc(&mal_mul, "*");
repl_env["/"] = new MalBuiltinFunc(&mal_div, "/");
for (;;)
{
string line = _readline("user> ");
if (line is null) break;
if (line.length == 0) continue;
try
{
writeln(rep(line, repl_env));
}
catch (Exception e)
{
writeln("Error: ", e.msg);
}
}
writeln("");
}