| 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 | while (true) { |
| 43 | //NSLog(@"EVAL: %@ (%@)", _pr_str(ast, true), env); |
| 44 | if (!list_Q(ast)) { |
| 45 | return eval_ast(ast, env); |
| 46 | } |
| 47 | |
| 48 | // apply list |
| 49 | if ([(NSArray *)ast count] == 0) { |
| 50 | return ast; |
| 51 | } |
| 52 | NSArray * alst = (NSArray *)ast; |
| 53 | id a0 = alst[0]; |
| 54 | NSString * a0sym = [a0 isKindOfClass:[MalSymbol class]] ? (NSString *)a0 |
| 55 | : @"__<*fn*>__"; |
| 56 | |
| 57 | if ([a0sym isEqualTo:@"def!"]) { |
| 58 | return [env set:((MalSymbol *)alst[1]) val:EVAL(alst[2], env)]; |
| 59 | } else if ([(NSString *)a0 isEqualTo:@"let*"]) { |
| 60 | Env *let_env = [Env fromOuter:env]; |
| 61 | NSArray * binds = (NSArray *)alst[1]; |
| 62 | for (int i=0; i < [binds count]; i+=2) { |
| 63 | [let_env set:binds[i] val:EVAL(binds[i+1], let_env)]; |
| 64 | } |
| 65 | env = let_env; |
| 66 | ast = alst[2]; // TCO |
| 67 | } else if ([a0sym isEqualTo:@"do"]) { |
| 68 | NSRange r = NSMakeRange(1, [alst count] - 2); |
| 69 | eval_ast([alst subarrayWithRange:r], env); |
| 70 | ast = [alst lastObject]; // TCO |
| 71 | } else if ([a0sym isEqualTo:@"if"]) { |
| 72 | NSObject * cond = EVAL(alst[1], env); |
| 73 | if ([cond isKindOfClass:[NSNull class]] || |
| 74 | [cond isKindOfClass:[MalFalse class]]) { |
| 75 | if ([alst count] > 3) { |
| 76 | ast = alst[3]; // TCO |
| 77 | } else { |
| 78 | return [NSNull alloc]; |
| 79 | } |
| 80 | } else { |
| 81 | ast = alst[2]; // TCO |
| 82 | } |
| 83 | } else if ([a0sym isEqualTo:@"fn*"]) { |
| 84 | return [[MalFunc alloc] init:alst[2] env:env params:alst[1]]; |
| 85 | } else { |
| 86 | NSArray * el = (NSArray *) eval_ast(ast, env); |
| 87 | NSArray * args = @[]; |
| 88 | if ([el count] > 1) { |
| 89 | args = _rest(el); |
| 90 | } |
| 91 | if ([el[0] isKindOfClass:[MalFunc class]]) { |
| 92 | MalFunc * mf = el[0]; |
| 93 | env = [Env fromBindings:[mf env] binds:[mf params] exprs:args]; |
| 94 | ast = [mf ast]; // TCO |
| 95 | } else { |
| 96 | NSObject * (^ f)(NSArray *) = el[0]; |
| 97 | return f(args); |
| 98 | } |
| 99 | } |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | // print |
| 104 | NSString *PRINT(NSObject *exp) { |
| 105 | return _pr_str(exp, true); |
| 106 | } |
| 107 | |
| 108 | // REPL |
| 109 | NSString *REP(NSString *line, Env *env) { |
| 110 | return PRINT(EVAL(READ(line), env)); |
| 111 | } |
| 112 | |
| 113 | int main () { |
| 114 | Env * repl_env = [[Env alloc] init]; |
| 115 | |
| 116 | // Create an autorelease pool to manage the memory into the program |
| 117 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; |
| 118 | // If using automatic reference counting (ARC), use @autoreleasepool instead: |
| 119 | // @autoreleasepool { |
| 120 | |
| 121 | // core.m: defined using Objective-C |
| 122 | NSDictionary * core_ns = [Core ns]; |
| 123 | for (NSString* key in core_ns) { |
| 124 | [repl_env set:(MalSymbol *)key val:[core_ns objectForKey:key]]; |
| 125 | } |
| 126 | |
| 127 | // core.mal: defined using the language itself |
| 128 | REP(@"(def! not (fn* (a) (if a false true)))", repl_env); |
| 129 | |
| 130 | while (true) { |
| 131 | char *rawline = _readline("user> "); |
| 132 | if (!rawline) { break; } |
| 133 | NSString *line = [NSString stringWithUTF8String:rawline]; |
| 134 | if ([line length] == 0) { continue; } |
| 135 | @try { |
| 136 | printf("%s\n", [[REP(line, repl_env) description] UTF8String]); |
| 137 | } @catch(NSString *e) { |
| 138 | printf("Error: %s\n", [e UTF8String]); |
| 139 | } @catch(NSObject *e) { |
| 140 | NSObject * exc = e; |
| 141 | printf("Exception: %s\n", [_pr_str(exc, true) UTF8String]); |
| 142 | } @catch(NSException *e) { |
| 143 | if ([[e name] isEqualTo:@"ReaderContinue"]) { continue; } |
| 144 | printf("Exception: %s\n", [[e reason] UTF8String]); |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | [pool drain]; |
| 149 | |
| 150 | // } |
| 151 | } |