2016-08-06 18:42:56 +03:00
|
|
|
// @import readline.ck
|
2016-04-30 21:12:07 +03:00
|
|
|
// @import types/MalObject.ck
|
2016-08-06 01:34:18 +03:00
|
|
|
// @import types/mal/MalAtom.ck
|
2024-08-29 01:44:37 +03:00
|
|
|
// @import types/mal/MalString.ck
|
2016-08-06 01:34:18 +03:00
|
|
|
// @import types/mal/MalError.ck
|
|
|
|
// @import types/mal/MalNil.ck
|
|
|
|
// @import types/mal/MalFalse.ck
|
|
|
|
// @import types/mal/MalTrue.ck
|
|
|
|
// @import types/mal/MalInt.ck
|
|
|
|
// @import types/mal/MalSymbol.ck
|
|
|
|
// @import types/mal/MalKeyword.ck
|
|
|
|
// @import types/mal/MalList.ck
|
|
|
|
// @import types/mal/MalVector.ck
|
|
|
|
// @import types/mal/MalHashMap.ck
|
2016-04-30 21:12:07 +03:00
|
|
|
// @import util/*.ck
|
|
|
|
// @import reader.ck
|
|
|
|
// @import printer.ck
|
2016-07-30 01:50:12 +03:00
|
|
|
// @import env.ck
|
2017-10-10 19:29:36 +03:00
|
|
|
// @import func.ck
|
2016-05-12 21:04:22 +03:00
|
|
|
// @import types/MalSubr.ck
|
|
|
|
// @import types/subr/*.ck
|
2016-04-30 21:12:07 +03:00
|
|
|
|
|
|
|
fun MalObject READ(string input)
|
|
|
|
{
|
|
|
|
return Reader.read_str(input);
|
|
|
|
}
|
|
|
|
|
|
|
|
fun MalObject EVAL(MalObject m, Env env)
|
|
|
|
{
|
2024-08-29 00:27:01 +03:00
|
|
|
env.find("DEBUG-EVAL") @=> MalObject debugEval;
|
|
|
|
if( debugEval != null && (debugEval.type != "false" &&
|
|
|
|
debugEval.type != "nil" ) )
|
|
|
|
{
|
|
|
|
Util.println("EVAL: " + Printer.pr_str(m, true));
|
|
|
|
}
|
|
|
|
|
2016-04-30 21:12:07 +03:00
|
|
|
if( m.type == "list" )
|
|
|
|
{
|
2024-08-28 23:12:06 +03:00
|
|
|
if( m.objects.size() == 0 )
|
2016-04-30 21:12:07 +03:00
|
|
|
{
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
2024-08-28 23:12:06 +03:00
|
|
|
m.malObjectValues() @=> MalObject ast[];
|
|
|
|
ast[0].stringValue => string a0;
|
2016-04-30 21:12:07 +03:00
|
|
|
|
|
|
|
if( a0 == "def!" )
|
|
|
|
{
|
2024-08-28 23:12:06 +03:00
|
|
|
ast[1].stringValue => string a1;
|
2016-04-30 21:12:07 +03:00
|
|
|
|
|
|
|
EVAL(ast[2], env) @=> MalObject value;
|
|
|
|
if( value.type == "error" )
|
|
|
|
{
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
env.set(a1, value);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
else if( a0 == "let*" )
|
|
|
|
{
|
|
|
|
Env.create(env) @=> Env let_env;
|
2024-08-28 23:12:06 +03:00
|
|
|
ast[1].malObjectValues() @=> MalObject bindings[];
|
2016-04-30 21:12:07 +03:00
|
|
|
|
|
|
|
for( 0 => int i; i < bindings.size(); 2 +=> i)
|
|
|
|
{
|
2024-08-28 23:12:06 +03:00
|
|
|
bindings[i].stringValue => string symbol;
|
2016-04-30 21:12:07 +03:00
|
|
|
EVAL(bindings[i+1], let_env) @=> MalObject value;
|
|
|
|
|
|
|
|
if( value.type == "error" )
|
|
|
|
{
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
let_env.set(symbol, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return EVAL(ast[2], let_env);
|
|
|
|
}
|
|
|
|
|
|
|
|
eval_ast(m, env) @=> MalObject result;
|
|
|
|
if( result.type == "error" )
|
|
|
|
{
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-08-28 23:12:06 +03:00
|
|
|
result.malObjectValues() @=> MalObject values[];
|
2016-04-30 21:12:07 +03:00
|
|
|
values[0]$MalSubr @=> MalSubr subr;
|
|
|
|
MalObject.slice(values, 1) @=> MalObject args[];
|
|
|
|
|
|
|
|
return subr.call(args);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eval_ast(m, env) @=> MalObject result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fun MalObject eval_ast(MalObject m, Env env)
|
|
|
|
{
|
|
|
|
m.type => string type;
|
|
|
|
|
|
|
|
if( type == "symbol" )
|
|
|
|
{
|
2024-08-28 23:12:06 +03:00
|
|
|
return env.get(m.stringValue);
|
2016-04-30 21:12:07 +03:00
|
|
|
}
|
|
|
|
else if( type == "list" || type == "vector" || type == "hashmap" )
|
|
|
|
{
|
2024-08-28 23:12:06 +03:00
|
|
|
m.malObjectValues() @=> MalObject values[];
|
2016-04-30 21:12:07 +03:00
|
|
|
MalObject results[values.size()];
|
|
|
|
|
|
|
|
if( type != "hashmap" )
|
|
|
|
{
|
|
|
|
for( 0 => int i; i < values.size(); i++ )
|
|
|
|
{
|
|
|
|
EVAL(values[i], env) @=> MalObject result;
|
|
|
|
|
|
|
|
if( result.type == "error" )
|
|
|
|
{
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
result @=> results[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for( 0 => int i; i < values.size(); i++ )
|
|
|
|
{
|
|
|
|
if( i % 2 == 0 )
|
|
|
|
{
|
|
|
|
values[i] @=> results[i];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
EVAL(values[i], env) @=> results[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( type == "list" )
|
|
|
|
{
|
|
|
|
return MalList.create(results);
|
|
|
|
}
|
|
|
|
else if( type == "vector" )
|
|
|
|
{
|
|
|
|
return MalVector.create(results);
|
|
|
|
}
|
|
|
|
else if( type == "hashmap" )
|
|
|
|
{
|
|
|
|
return MalHashMap.create(results);
|
|
|
|
}
|
2024-08-28 20:49:59 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
Util.panic("Programmer error (exhaustive match)");
|
|
|
|
return null;
|
|
|
|
}
|
2016-04-30 21:12:07 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fun string PRINT(MalObject m)
|
|
|
|
{
|
|
|
|
return Printer.pr_str(m, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
Env.create(null) @=> Env repl_env;
|
|
|
|
repl_env.set("+", new MalAdd);
|
|
|
|
repl_env.set("-", new MalSub);
|
|
|
|
repl_env.set("*", new MalMul);
|
|
|
|
repl_env.set("/", new MalDiv);
|
|
|
|
|
2016-08-06 01:34:18 +03:00
|
|
|
fun string errorMessage(MalObject m)
|
|
|
|
{
|
2024-08-29 01:44:37 +03:00
|
|
|
return "exception: " + String.repr(m.malObjectValue().stringValue);
|
2016-08-06 01:34:18 +03:00
|
|
|
}
|
|
|
|
|
2016-04-30 21:12:07 +03:00
|
|
|
fun string rep(string input)
|
|
|
|
{
|
|
|
|
READ(input) @=> MalObject m;
|
|
|
|
|
|
|
|
if( m.type == "error" )
|
|
|
|
{
|
2016-08-06 01:34:18 +03:00
|
|
|
return errorMessage(m);
|
2016-04-30 21:12:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
EVAL(m, repl_env) @=> MalObject result;
|
|
|
|
if( result.type == "error" )
|
|
|
|
{
|
2016-08-06 01:34:18 +03:00
|
|
|
return errorMessage(result);
|
2016-04-30 21:12:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return PRINT(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
fun void main()
|
|
|
|
{
|
2016-08-06 18:42:56 +03:00
|
|
|
int done;
|
2016-04-30 21:12:07 +03:00
|
|
|
|
2016-08-06 18:42:56 +03:00
|
|
|
while( !done )
|
2016-04-30 21:12:07 +03:00
|
|
|
{
|
2016-08-06 18:42:56 +03:00
|
|
|
Readline.readline("user> ") => string input;
|
2016-04-30 21:12:07 +03:00
|
|
|
|
2016-08-06 18:42:56 +03:00
|
|
|
if( input != null )
|
2016-04-30 21:12:07 +03:00
|
|
|
{
|
2016-08-06 18:42:56 +03:00
|
|
|
rep(input) => string output;
|
|
|
|
|
2024-08-29 01:44:37 +03:00
|
|
|
if( output == "exception: \"empty input\"" )
|
2016-08-06 18:42:56 +03:00
|
|
|
{
|
|
|
|
// proceed immediately with prompt
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Util.println(output);
|
|
|
|
}
|
2016-04-30 21:12:07 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-08-06 18:42:56 +03:00
|
|
|
true => done;
|
2016-04-30 21:12:07 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
main();
|