gensym: hide the counter in an environment, define inc in stepA.
[jackhill/mal.git] / dart / step2_eval.dart
CommitLineData
3934e3f8
HT
1import 'dart:io';
2
3import 'printer.dart' as printer;
4import 'reader.dart' as reader;
5import 'types.dart';
6
7final 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
14MalType READ(String x) => reader.read_str(x);
15
16class NotFoundException implements Exception {
17 /// The name of the symbol that was not found.
18 final String value;
19
20 NotFoundException(this.value);
21}
22
23eval_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
45EVAL(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
60String PRINT(MalType x) => printer.pr_str(x);
61
62String rep(String x) {
dd7a4f55 63 return PRINT(EVAL(READ(x), replEnv));
3934e3f8
HT
64}
65
66const prompt = 'user> ';
67main() {
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}