Commit | Line | Data |
---|---|---|
3934e3f8 HT |
1 | import 'dart:io'; |
2 | ||
3 | import 'printer.dart' as printer; | |
4 | import 'reader.dart' as reader; | |
5 | import 'types.dart'; | |
6 | ||
7 | final Map<MalSymbol, Function> replEnv = <MalSymbol, Function>{ | |
8 | new MalSymbol('+'): (MalInt a, MalInt b) => new MalInt(a.value + b.value), | |
9 | new MalSymbol('-'): (MalInt a, MalInt b) => new MalInt(a.value - b.value), | |
10 | new MalSymbol('*'): (MalInt a, MalInt b) => new MalInt(a.value * b.value), | |
11 | new MalSymbol('/'): (MalInt a, MalInt b) => new MalInt(a.value ~/ b.value), | |
12 | }; | |
13 | ||
14 | MalType READ(String x) => reader.read_str(x); | |
15 | ||
16 | class NotFoundException implements Exception { | |
17 | /// The name of the symbol that was not found. | |
18 | final String value; | |
19 | ||
20 | NotFoundException(this.value); | |
21 | } | |
22 | ||
23 | eval_ast(MalType ast, Map<MalSymbol, Function> env) { | |
24 | if (ast is MalSymbol) { | |
25 | var result = env[ast]; | |
26 | if (result == null) { | |
27 | throw new NotFoundException(ast.value); | |
28 | } | |
29 | return result; | |
30 | } else if (ast is MalList) { | |
31 | return new MalList(ast.elements.map((x) => EVAL(x, env)).toList()); | |
32 | } else if (ast is MalVector) { | |
33 | return new MalVector(ast.elements.map((x) => EVAL(x, env)).toList()); | |
34 | } else if (ast is MalHashMap) { | |
35 | var newMap = new Map.from(ast.value); | |
36 | for (var key in newMap.keys) { | |
37 | newMap[key] = EVAL(newMap[key], env); | |
38 | } | |
39 | return new MalHashMap(newMap); | |
40 | } else { | |
41 | return ast; | |
42 | } | |
43 | } | |
44 | ||
45 | EVAL(MalType ast, Map<MalSymbol, Function> env) { | |
46 | if (ast is! MalList) { | |
47 | return eval_ast(ast, env); | |
48 | } else { | |
49 | if ((ast as MalList).elements.isEmpty) { | |
50 | return ast; | |
51 | } else { | |
52 | var newAst = eval_ast(ast, env) as MalList; | |
53 | Function f = newAst.elements.first; | |
54 | var args = newAst.elements.sublist(1); | |
55 | return Function.apply(f, args); | |
56 | } | |
57 | } | |
58 | } | |
59 | ||
60 | String PRINT(MalType x) => printer.pr_str(x); | |
61 | ||
62 | String rep(String x) { | |
dd7a4f55 | 63 | return PRINT(EVAL(READ(x), replEnv)); |
3934e3f8 HT |
64 | } |
65 | ||
66 | const prompt = 'user> '; | |
67 | main() { | |
68 | while (true) { | |
69 | stdout.write(prompt); | |
70 | var input = stdin.readLineSync(); | |
71 | if (input == null) return; | |
72 | var output; | |
73 | try { | |
74 | output = rep(input); | |
dd7a4f55 JM |
75 | } on reader.ParseException catch (e) { |
76 | stdout.writeln("Error: '${e.message}'"); | |
77 | continue; | |
78 | } on NotFoundException catch (e) { | |
79 | stdout.writeln("Error: '${e.value}' not found"); | |
80 | continue; | |
3934e3f8 HT |
81 | } on reader.NoInputException { |
82 | continue; | |
83 | } | |
84 | stdout.writeln(output); | |
85 | } | |
86 | } |