1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using Mal;
using MalVal = Mal.types.MalVal;
using MalSymbol = Mal.types.MalSymbol;
using MalInt = Mal.types.MalInt;
using MalList = Mal.types.MalList;
using MalVector = Mal.types.MalVector;
using MalHashMap = Mal.types.MalHashMap;
using MalFunc = Mal.types.MalFunc;
using Env = Mal.env.Env;
namespace Mal {
class step3_env {
// read
static MalVal READ(string str) {
return reader.read_str(str);
}
// eval
static MalVal eval_ast(MalVal ast, Env env) {
if (ast is MalSymbol) {
return env.get((MalSymbol)ast);
} else if (ast is MalList) {
MalList old_lst = (MalList)ast;
MalList new_lst = ast.list_Q() ? new MalList()
: (MalList)new MalVector();
foreach (MalVal mv in old_lst.getValue()) {
new_lst.conj_BANG(EVAL(mv, env));
}
return new_lst;
} else if (ast is MalHashMap) {
var new_dict = new Dictionary<string, MalVal>();
foreach (var entry in ((MalHashMap)ast).getValue()) {
new_dict.Add(entry.Key, EVAL((MalVal)entry.Value, env));
}
return new MalHashMap(new_dict);
} else {
return ast;
}
}
static MalVal EVAL(MalVal orig_ast, Env env) {
MalVal a0, a1, a2, res;
MalList el;
//Console.WriteLine("EVAL: " + printer._pr_str(orig_ast, true));
if (!orig_ast.list_Q()) {
return eval_ast(orig_ast, env);
}
// apply list
MalList ast = (MalList)orig_ast;
if (ast.size() == 0) { return ast; }
a0 = ast[0];
if (!(a0 is MalSymbol)) {
throw new Mal.types.MalError("attempt to apply on non-symbol '"
+ Mal.printer._pr_str(a0,true) + "'");
}
switch (((MalSymbol)a0).getName()) {
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));
}
return EVAL(a2, let_env);
default:
el = (MalList)eval_ast(ast, env);
var f = (MalFunc)el[0];
return f.apply(el.rest());
}
}
// print
static string PRINT(MalVal exp) {
return printer._pr_str(exp, true);
}
// repl
static void Main(string[] args) {
var repl_env = new Mal.env.Env(null);
Func<string, MalVal> RE = (string str) => EVAL(READ(str), repl_env);
repl_env.set(new MalSymbol("+"), new MalFunc(
a => (MalInt)a[0] + (MalInt)a[1]) );
repl_env.set(new MalSymbol("-"), new MalFunc(
a => (MalInt)a[0] - (MalInt)a[1]) );
repl_env.set(new MalSymbol("*"), new MalFunc(
a => (MalInt)a[0] * (MalInt)a[1]) );
repl_env.set(new MalSymbol("/"), new MalFunc(
a => (MalInt)a[0] / (MalInt)a[1]) );
if (args.Length > 0 && args[0] == "--raw") {
Mal.readline.mode = Mal.readline.Mode.Raw;
}
// repl loop
while (true) {
string line;
try {
line = Mal.readline.Readline("user> ");
if (line == null) { break; }
if (line == "") { continue; }
} catch (IOException e) {
Console.WriteLine("IOException: " + e.Message);
break;
}
try {
Console.WriteLine(PRINT(RE(line)));
} catch (Mal.types.MalContinue) {
continue;
} catch (Exception e) {
Console.WriteLine("Error: " + e.Message);
Console.WriteLine(e.StackTrace);
continue;
}
}
}
}
}
|