Commit | Line | Data |
---|---|---|
b0293c15 JM |
1 | using System; |
2 | using System.IO; | |
3 | using System.Collections; | |
4 | using System.Collections.Generic; | |
5 | using Mal; | |
6 | using MalVal = Mal.types.MalVal; | |
86b689f3 | 7 | using MalString = Mal.types.MalString; |
b0293c15 JM |
8 | using MalSymbol = Mal.types.MalSymbol; |
9 | using MalInteger = Mal.types.MalInteger; | |
10 | using MalList = Mal.types.MalList; | |
11 | using MalVector = Mal.types.MalVector; | |
12 | using MalHashMap = Mal.types.MalHashMap; | |
13 | using MalFunction = Mal.types.MalFunction; | |
14 | using Env = Mal.env.Env; | |
15 | ||
16 | namespace Mal { | |
8cb5cda4 | 17 | class step6_file { |
b0293c15 JM |
18 | // read |
19 | static MalVal READ(string str) { | |
20 | return reader.read_str(str); | |
21 | } | |
22 | ||
23 | // eval | |
24 | static MalVal eval_ast(MalVal ast, Env env) { | |
25 | if (ast is MalSymbol) { | |
26 | MalSymbol sym = (MalSymbol)ast; | |
27 | return env.get(sym.getName()); | |
28 | } else if (ast is MalList) { | |
29 | MalList old_lst = (MalList)ast; | |
30 | MalList new_lst = ast.list_Q() ? new MalList() | |
31 | : (MalList)new MalVector(); | |
32 | foreach (MalVal mv in old_lst.getValue()) { | |
33 | new_lst.conj_BANG(EVAL(mv, env)); | |
34 | } | |
35 | return new_lst; | |
36 | } else if (ast is MalHashMap) { | |
37 | var new_dict = new Dictionary<string, MalVal>(); | |
38 | foreach (var entry in ((MalHashMap)ast).getValue()) { | |
39 | new_dict.Add(entry.Key, EVAL((MalVal)entry.Value, env)); | |
40 | } | |
41 | return new MalHashMap(new_dict); | |
42 | } else { | |
43 | return ast; | |
44 | } | |
45 | } | |
46 | ||
47 | ||
48 | static MalVal EVAL(MalVal orig_ast, Env env) { | |
49 | MalVal a0, a1, a2, res; | |
50 | MalList el; | |
51 | ||
52 | while (true) { | |
53 | ||
54 | //System.out.println("EVAL: " + printer._pr_str(orig_ast, true)); | |
55 | if (!orig_ast.list_Q()) { | |
56 | return eval_ast(orig_ast, env); | |
57 | } | |
58 | ||
59 | // apply list | |
60 | MalList ast = (MalList)orig_ast; | |
61 | if (ast.size() == 0) { return ast; } | |
8cb5cda4 | 62 | a0 = ast[0]; |
b0293c15 JM |
63 | |
64 | String a0sym = a0 is MalSymbol ? ((MalSymbol)a0).getName() | |
65 | : "__<*fn*>__"; | |
66 | ||
67 | switch (a0sym) { | |
68 | case "def!": | |
8cb5cda4 JM |
69 | a1 = ast[1]; |
70 | a2 = ast[2]; | |
b0293c15 JM |
71 | res = EVAL(a2, env); |
72 | env.set(((MalSymbol)a1).getName(), res); | |
73 | return res; | |
74 | case "let*": | |
8cb5cda4 JM |
75 | a1 = ast[1]; |
76 | a2 = ast[2]; | |
b0293c15 JM |
77 | MalSymbol key; |
78 | MalVal val; | |
79 | Env let_env = new Env(env); | |
80 | for(int i=0; i<((MalList)a1).size(); i+=2) { | |
8cb5cda4 JM |
81 | key = (MalSymbol)((MalList)a1)[i]; |
82 | val = ((MalList)a1)[i+1]; | |
b0293c15 JM |
83 | let_env.set(key.getName(), EVAL(val, let_env)); |
84 | } | |
6301e0b6 JM |
85 | orig_ast = a2; |
86 | env = let_env; | |
87 | break; | |
b0293c15 JM |
88 | case "do": |
89 | eval_ast(ast.slice(1, ast.size()-1), env); | |
8cb5cda4 | 90 | orig_ast = ast[ast.size()-1]; |
b0293c15 JM |
91 | break; |
92 | case "if": | |
8cb5cda4 | 93 | a1 = ast[1]; |
b0293c15 JM |
94 | MalVal cond = EVAL(a1, env); |
95 | if (cond == Mal.types.Nil || cond == Mal.types.False) { | |
96 | // eval false slot form | |
97 | if (ast.size() > 3) { | |
98 | orig_ast = ast[3]; | |
99 | } else { | |
100 | return Mal.types.Nil; | |
101 | } | |
102 | } else { | |
103 | // eval true slot form | |
104 | orig_ast = ast[2]; | |
105 | } | |
106 | break; | |
107 | case "fn*": | |
8cb5cda4 JM |
108 | MalList a1f = (MalList)ast[1]; |
109 | MalVal a2f = ast[2]; | |
b0293c15 JM |
110 | Env cur_env = env; |
111 | return new MalFunction(a2f, env, a1f, | |
112 | args => EVAL(a2f, new Env(cur_env, a1f, args)) ); | |
113 | default: | |
114 | el = (MalList)eval_ast(ast, env); | |
8cb5cda4 | 115 | var f = (MalFunction)el[0]; |
b0293c15 JM |
116 | MalVal fnast = f.getAst(); |
117 | if (fnast != null) { | |
118 | orig_ast = fnast; | |
119 | env = f.genEnv(el.rest()); | |
120 | } else { | |
121 | return f.apply(el.rest()); | |
122 | } | |
123 | break; | |
124 | } | |
125 | ||
126 | } | |
127 | } | |
128 | ||
129 | ||
130 | static string PRINT(MalVal exp) { | |
131 | return printer._pr_str(exp, true); | |
132 | } | |
133 | ||
86b689f3 | 134 | // repl |
b0293c15 JM |
135 | static MalVal RE(Env env, string str) { |
136 | return EVAL(READ(str), env); | |
137 | } | |
b0293c15 JM |
138 | |
139 | static void Main(string[] args) { | |
140 | string prompt = "user> "; | |
141 | ||
8cb5cda4 JM |
142 | // core.cs: defined using C# |
143 | var repl_env = new env.Env(null); | |
144 | foreach (var entry in core.ns) { | |
145 | repl_env.set(entry.Key, entry.Value); | |
b0293c15 | 146 | } |
8cb5cda4 | 147 | repl_env.set("eval", new MalFunction(a => EVAL(a[0], repl_env))); |
86b689f3 JM |
148 | MalList _argv = new MalList(); |
149 | for (int i=1; i < args.Length; i++) { | |
150 | _argv.conj_BANG(new MalString(args[i])); | |
151 | } | |
152 | repl_env.set("*ARGV*", _argv); | |
b0293c15 | 153 | |
8cb5cda4 | 154 | // core.mal: defined using the language itself |
b0293c15 JM |
155 | RE(repl_env, "(def! not (fn* (a) (if a false true)))"); |
156 | RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"); | |
157 | ||
158 | int fileIdx = 0; | |
159 | if (args.Length > 0 && args[0] == "--raw") { | |
160 | Mal.readline.mode = Mal.readline.Mode.Raw; | |
161 | fileIdx = 1; | |
162 | } | |
163 | if (args.Length > fileIdx) { | |
86b689f3 | 164 | RE(repl_env, "(load-file \"" + args[fileIdx] + "\")"); |
b0293c15 JM |
165 | return; |
166 | } | |
86b689f3 JM |
167 | |
168 | // repl loop | |
b0293c15 JM |
169 | while (true) { |
170 | string line; | |
171 | try { | |
172 | line = Mal.readline.Readline(prompt); | |
173 | if (line == null) { break; } | |
174 | } catch (IOException e) { | |
175 | Console.WriteLine("IOException: " + e.Message); | |
176 | break; | |
177 | } | |
178 | try { | |
179 | Console.WriteLine(PRINT(RE(repl_env, line))); | |
180 | } catch (Mal.types.MalContinue) { | |
181 | continue; | |
b0293c15 JM |
182 | } catch (Exception e) { |
183 | Console.WriteLine("Error: " + e.Message); | |
8cb5cda4 | 184 | Console.WriteLine(e.StackTrace); |
b0293c15 JM |
185 | continue; |
186 | } | |
187 | } | |
188 | } | |
189 | } | |
190 | } |