Commit | Line | Data |
---|---|---|
57350ed7 JM |
1 | #import <Foundation/Foundation.h> |
2 | ||
3 | #import "mal_readline.h" | |
4 | #import "types.h" | |
5 | #import "reader.h" | |
6 | #import "printer.h" | |
7 | ||
8 | // read | |
9 | NSObject *READ(NSString *str) { | |
10 | return read_str(str); | |
11 | } | |
12 | ||
13 | // eval | |
14 | ||
15 | // forward declaration | |
16 | NSObject *EVAL(NSObject *ast, NSDictionary *env); | |
17 | ||
18 | NSObject *eval_ast(NSObject *ast, NSDictionary *env) { | |
19 | if ([ast isMemberOfClass:[MalSymbol class]]) { | |
20 | if ([env objectForKey:ast]) { | |
21 | return env[ast]; | |
22 | } else { | |
23 | @throw [NSString stringWithFormat:@"'%@' not found", ast]; | |
24 | } | |
25 | } else if ([ast isKindOfClass:[NSArray class]]) { | |
26 | NSMutableArray *newLst = [NSMutableArray array]; | |
27 | for (NSObject * x in (NSArray *)ast) { | |
28 | [newLst addObject:EVAL(x, env)]; | |
29 | } | |
30 | if ([ast isKindOfClass:[MalVector class]]) { | |
31 | return [MalVector fromArray:newLst]; | |
32 | } else { | |
33 | return newLst; | |
34 | } | |
35 | } else if ([ast isKindOfClass:[NSDictionary class]]) { | |
36 | NSMutableDictionary *newDict = [NSMutableDictionary dictionary]; | |
37 | for (NSString * k in (NSDictionary *)ast) { | |
38 | newDict[k] = EVAL(((NSDictionary *)ast)[k], env); | |
39 | } | |
40 | return newDict; | |
41 | } else { | |
42 | return ast; | |
43 | } | |
44 | } | |
45 | ||
46 | NSObject *EVAL(NSObject *ast, NSDictionary *env) { | |
47 | //NSLog(@"EVAL: %@", ast); | |
48 | if (!list_Q(ast)) { | |
49 | return eval_ast(ast, env); | |
50 | } | |
51 | ||
203e9599 JM |
52 | // apply list |
53 | if ([(NSArray *)ast count] == 0) { | |
54 | return ast; | |
55 | } | |
57350ed7 JM |
56 | NSArray * el = (NSArray *) eval_ast(ast, env); |
57 | NSObject * (^ f)(NSArray *) = el[0]; | |
7cae6e6f | 58 | NSArray * args = _rest(el); |
57350ed7 JM |
59 | return f(args); |
60 | } | |
61 | ||
62 | ||
63 | NSString *PRINT(NSObject *exp) { | |
64 | return _pr_str(exp, true); | |
65 | } | |
66 | ||
67 | // REPL | |
68 | NSString *REP(NSString *line, NSDictionary *env) { | |
69 | return PRINT(EVAL(READ(line), env)); | |
70 | } | |
71 | ||
7cae6e6f | 72 | int main () { |
57350ed7 JM |
73 | NSDictionary * repl_env = @{ |
74 | @"+": ^(NSArray *args){ | |
75 | return [NSNumber numberWithInt:[args[0] intValue] + [args[1] intValue]]; | |
76 | }, | |
77 | @"-": ^(NSArray *args){ | |
78 | return [NSNumber numberWithInt:[args[0] intValue] - [args[1] intValue]]; | |
79 | }, | |
80 | @"*": ^(NSArray *args){ | |
81 | return [NSNumber numberWithInt:[args[0] intValue] * [args[1] intValue]]; | |
82 | }, | |
83 | @"/": ^(NSArray *args){ | |
84 | return [NSNumber numberWithInt:[args[0] intValue] / [args[1] intValue]]; | |
85 | }, | |
86 | }; | |
87 | ||
7cae6e6f JM |
88 | // Create an autorelease pool to manage the memory into the program |
89 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
90 | // If using automatic reference counting (ARC), use @autoreleasepool instead: | |
91 | // @autoreleasepool { | |
92 | ||
57350ed7 JM |
93 | while (true) { |
94 | char *rawline = _readline("user> "); | |
95 | if (!rawline) { break; } | |
96 | NSString *line = [NSString stringWithUTF8String:rawline]; | |
97 | if ([line length] == 0) { continue; } | |
98 | @try { | |
99 | printf("%s\n", [[REP(line, repl_env) description] UTF8String]); | |
100 | } @catch(NSString *e) { | |
101 | printf("Error: %s\n", [e UTF8String]); | |
7cae6e6f JM |
102 | } @catch(NSException *e) { |
103 | if ([[e name] isEqualTo:@"ReaderContinue"]) { continue; } | |
104 | printf("Exception: %s\n", [[e reason] UTF8String]); | |
57350ed7 JM |
105 | } |
106 | } | |
107 | ||
108 | [pool drain]; | |
109 | ||
110 | // } | |
111 | } |