Implement step 7
[jackhill/mal.git] / objc / step4_if_fn_do.m
1 #import <Foundation/Foundation.h>
2
3 #import "mal_readline.h"
4 #import "types.h"
5 #import "reader.h"
6 #import "printer.h"
7 #import "env.h"
8 #import "malfunc.h"
9 #import "core.h"
10
11 // read
12 NSObject *READ(NSString *str) {
13 return read_str(str);
14 }
15
16 // eval
17 NSObject *eval_ast(NSObject *ast, Env *env) {
18 if ([ast isMemberOfClass:[MalSymbol class]]) {
19 return [env get:(MalSymbol *)ast];
20 } else if ([ast isKindOfClass:[NSArray class]]) {
21 NSMutableArray *newLst = [NSMutableArray array];
22 for (NSObject * x in (NSArray *)ast) {
23 [newLst addObject:EVAL(x, env)];
24 }
25 if ([ast isKindOfClass:[MalVector class]]) {
26 return [MalVector fromArray:newLst];
27 } else {
28 return newLst;
29 }
30 } else if ([ast isKindOfClass:[NSDictionary class]]) {
31 NSMutableDictionary *newDict = [NSMutableDictionary dictionary];
32 for (NSString * k in (NSDictionary *)ast) {
33 newDict[k] = EVAL(((NSDictionary *)ast)[k], env);
34 }
35 return newDict;
36 } else {
37 return ast;
38 }
39 }
40
41 NSObject *EVAL(NSObject *ast, Env *env) {
42 //NSLog(@"EVAL: %@ (%@)", _pr_str(ast, true), env);
43 if (!list_Q(ast)) {
44 return eval_ast(ast, env);
45 }
46
47 NSArray * alst = (NSArray *)ast;
48 id a0 = alst[0];
49 NSString * a0sym = [a0 isKindOfClass:[MalSymbol class]] ? (NSString *)a0
50 : @"__<*fn*>__";
51
52 if ([a0sym isEqualTo:@"def!"]) {
53 return [env set:((MalSymbol *)alst[1]) val:EVAL(alst[2], env)];
54 } else if ([(NSString *)a0 isEqualTo:@"let*"]) {
55 Env *let_env = [Env fromOuter:env];
56 NSArray * binds = (NSArray *)alst[1];
57 for (int i=0; i < [binds count]; i+=2) {
58 [let_env set:binds[i] val:EVAL(binds[i+1], let_env)];
59 }
60 return EVAL(alst[2], let_env);
61 } else if ([a0sym isEqualTo:@"do"]) {
62 NSArray * el = (NSArray *)eval_ast(_rest(alst), env);
63 return [el lastObject];
64 } else if ([a0sym isEqualTo:@"if"]) {
65 NSObject * cond = EVAL(alst[1], env);
66 if ([cond isKindOfClass:[NSNull class]] ||
67 [cond isKindOfClass:[MalFalse class]]) {
68 if ([alst count] > 3) {
69 return EVAL(alst[3], env);
70 } else {
71 return [NSNull alloc];
72 }
73 } else {
74 return EVAL(alst[2], env);
75 }
76 } else if ([a0sym isEqualTo:@"fn*"]) {
77 return [[MalFunc alloc] init:alst[2] env:env params:alst[1]];
78 } else {
79 NSArray * el = (NSArray *) eval_ast(ast, env);
80 NSArray * args = @[];
81 if ([el count] > 1) {
82 args = _rest(el);
83 }
84 return apply(el[0], args);
85 /*
86 if ([el[0] isKindOfClass:[MalFunc class]]) {
87 MalFunc * mf = el[0];
88 return [mf apply:args];
89 } else {
90 NSObject * (^ f)(NSArray *) = el[0];
91 return f(args);
92 }
93 */
94 }
95 }
96
97 // print
98 NSString *PRINT(NSObject *exp) {
99 return _pr_str(exp, true);
100 }
101
102 // REPL
103 NSString *REP(NSString *line, Env *env) {
104 return PRINT(EVAL(READ(line), env));
105 }
106
107 int main () {
108 Env * repl_env = [[Env alloc] init];
109
110 // Create an autorelease pool to manage the memory into the program
111 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
112 // If using automatic reference counting (ARC), use @autoreleasepool instead:
113 // @autoreleasepool {
114
115 // core.m: defined using Objective-C
116 NSDictionary * core_ns = [Core ns];
117 for (NSString* key in core_ns) {
118 [repl_env set:(MalSymbol *)key val:[core_ns objectForKey:key]];
119 }
120
121 // core.mal: defined using the language itself
122 REP(@"(def! not (fn* (a) (if a false true)))", repl_env);
123
124 while (true) {
125 char *rawline = _readline("user> ");
126 if (!rawline) { break; }
127 NSString *line = [NSString stringWithUTF8String:rawline];
128 if ([line length] == 0) { continue; }
129 @try {
130 printf("%s\n", [[REP(line, repl_env) description] UTF8String]);
131 } @catch(NSString *e) {
132 printf("Error: %s\n", [e UTF8String]);
133 } @catch(NSException *e) {
134 if ([[e name] isEqualTo:@"ReaderContinue"]) { continue; }
135 printf("Exception: %s\n", [[e reason] UTF8String]);
136 }
137 }
138
139 [pool drain];
140
141 // }
142 }