/* -*- mode: objc; coding: utf-8 -*- */ /* Toilet Lisp, a Common Lisp subset for the Étoilé runtime. * Copyright (C) 2008 Matthias Andreas Benkard. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #import "MLKBinaryStreamCharacterStream.h" #import "MLKBinding.h" #import "MLKCharacter.h" #import "MLKCompiledClosure.h" #import "MLKCons.h" #import "MLKDynamicContext.h" #import "MLKInterpretedClosure.h" #import "MLKInterpreter.h" #import "MLKLLVMCompiler.h" #import "MLKNumber.h" #import "MLKPackage.h" #import "MLKRoot.h" #import "MLKStreamStream.h" #import "MLKSymbol.h" #import "MLKInteger.h" #import "MLKSingleFloat.h" #import "MLKDoubleFloat.h" #import "NSObject-MLKPrinting.h" #import "globals.h" #import "runtime-compatibility.h" #import "util.h" #import #import #import #import #import #import #import #import #import #include static NSMethodSignature *signature; static MLKPackage *sys; static MLKPackage *cl; static NSMutableDictionary *lisp_c_name_map; static id truify (BOOL value) { return (value ? (id) [cl intern:@"T"] : nil); } id toilet_car (id *_data, id *_multireturn, id cons, id _marker) { return [cons car]; } id toilet_cdr (id *_data, id *_multireturn, id cons, id _marker) { return [cons cdr]; } id toilet_rplaca (id *_data, id *_multireturn, id cons, id value, id _marker) { [cons setCar:value]; return cons; } id toilet_rplacd (id *_data, id *_multireturn, id cons, id value, id _marker) { [cons setCdr:value]; return cons; } id toilet_cons (id *_data, id *_multireturn, id car, id cdr, id _marker) { return [MLKCons cons:car with:cdr]; } id toilet_load (id *_data, id *_multireturn, NSString *fileName, id _marker) { BOOL success; int l, i; NSInputStream *input = [NSInputStream inputStreamWithFileAtPath:fileName]; MLKBinaryStream *filestream = LAUTORELEASE ([[MLKStreamStream alloc] initWithInputStream:input]); MLKCharacterStream *stream = LAUTORELEASE ([[MLKBinaryStreamCharacterStream alloc] initWithBinaryStream:filestream]); MLKDynamicContext *oldContext = [MLKDynamicContext currentContext]; int level = MLKIntWithInteger ([oldContext valueForSymbol:[sys intern:@"*LOAD-LEVEL*"]]); MLKDynamicContext *ctx; l = [fileName length]; MLKCharacterStream *ostream = [[MLKDynamicContext currentContext] valueForSymbol:[cl intern:@"*STANDARD-OUTPUT*"]]; [ostream writeString:@";\n; "]; for (i = 0; i < 68 - 2*level; i++) [ostream writeChar:'_']; [ostream writeString:@"\n; /"]; for (i = 0; i < 30 - l/2 - level; i++) [ostream writeChar:'-']; [ostream writeString:[NSString stringWithFormat:@" LOAD: %s ", [fileName UTF8String]]]; for (i = 0; i < 30 - (l+1)/2 - level; i++) [ostream writeChar:'-']; [ostream writeString:@"\n; |\n"]; //NSLog (@"%d", [input hasBytesAvailable]); [input open]; //NSLog (@"%d", [input hasBytesAvailable]); ctx = [[MLKDynamicContext alloc] initWithParent:oldContext variables:nil handlers:nil restarts:nil catchTags:nil activeHandlerEnvironment:nil]; [ctx addValue:MLKIntegerWithInt(level + 1) forSymbol:[sys intern:@"*LOAD-LEVEL*"]]; [ctx pushContext]; @try { success = [MLKInterpreter load:stream verbose:YES print:YES]; } @finally { [MLKDynamicContext popContext]; LRELEASE (ctx); [input close]; } [ostream writeString:@"; \\"]; for (i = 0; i < 68 - 2*level; i++) [ostream writeChar:'_']; [ostream writeString:@"\n; \n"]; return truify (success); } id toilet_require (id *_data, id *_multireturn, id moduleName, id _marker) { NSLog(@"require..."); NSBundle *toiletKit = [NSBundle bundleForClass:[MLKRoot class]]; NSString *path = [[toiletKit resourcePath] stringByAppendingPathComponent:stringify(moduleName)]; return toilet_load (NULL, _multireturn, path, MLKEndOfArgumentsMarker); } id toilet_eq (id *_data, id *_multireturn, id x, id y, id _marker) { return truify (x == y); } id toilet_fixnum_eq (id *_data, id *_multireturn, id x, id y, id _marker) { #ifdef NO_FIXNUMS return truify ([x isEqual:y]); #else return truify (x == y); #endif } id toilet_symbolp (id *_data, id *_multireturn, id arg0, id _marker) { return truify (MLKInstanceP(arg0) && (!arg0 || [arg0 isKindOfClass:[MLKSymbol class]])); } id toilet_listp (id *_data, id *_multireturn, id arg0, id _marker) { return truify (MLKInstanceP(arg0) && (!arg0 || [arg0 isKindOfClass:[MLKCons class]])); } id toilet_consp (id *_data, id *_multireturn, id arg0, id _marker) { return truify (MLKInstanceP(arg0) && [arg0 isKindOfClass:[MLKCons class]]); } id toilet_atom (id *_data, id *_multireturn, id arg0, id _marker) { return truify (!MLKInstanceP(arg0) || ![arg0 isKindOfClass:[MLKCons class]]); } id toilet_null (id *_data, id *_multireturn, id arg0, id _marker) { return truify (!arg0); } id toilet_fixnump (id *_data, id *_multireturn, id arg0, id _marker) { return truify (MLKFixnumP(arg0)); } id toilet_add (id *_data, id *_multireturn, MLKNumber *x, MLKNumber *y, id _marker) { return [nullify(x) add:nullify(y)]; } id toilet_subtract (id *_data, id *_multireturn, MLKNumber *x, MLKNumber *y, id _marker) { return [nullify(x) subtract:nullify(y)]; } id toilet_multiply (id *_data, id *_multireturn, MLKNumber *x, MLKNumber *y, id _marker) { return [nullify(x) multiplyWith:nullify(y)]; } id toilet_divide (id *_data, id *_multireturn, MLKNumber *x, MLKNumber *y, id _marker) { return [nullify(x) divideBy:nullify(y)]; } id toilet_add_fixnums (id *_data, id *_multireturn, id x, id y, id _marker) { return MLKAddFixnums (x, y); } id toilet_subtract_fixnums (id *_data, id *_multireturn, id x, id y, id _marker) { return MLKSubtractFixnums (x, y); } id toilet_idivide_fixnums (id *_data, id *_multireturn, id x, id y, id _marker) { return MLKIDivideFixnums (x, y); } id toilet_multiply_fixnums (id *_data, id *_multireturn, id x, id y, id _marker) { return MLKMultiplyFixnums (x, y); } id toilet_list (id *_data, id *_multireturn, ...) { id arg; va_list ap; id cons, tail; cons = nil; tail = nil; va_start (ap, _multireturn); while ((arg = va_arg(ap, id)) != MLKEndOfArgumentsMarker) { //NSLog (@"list: Adding stuff (%%p = %p).", arg); //NSLog (@"list: Stuff: %p = %@", arg, nullify(arg)); if (!tail) { cons = tail = [MLKCons cons:arg with:nil]; } else { [tail setCdr:[MLKCons cons:arg with:nil]]; tail = [tail cdr]; } } va_end (ap); //NSLog (@"list: Done. Result: %p", cons); //NSLog (@"list: %p = %@", cons, cons); return cons; } #define VA_NEXT(AP, ARG, DEFAULT) \ ((ARG == MLKEndOfArgumentsMarker) \ ? (id)DEFAULT \ : (id)({ id __tmp = ARG; ARG = va_arg(AP, id); __tmp; })) id toilet_macroexpand_1 (id *_data, id *_multireturn, id form, id arg, ...) { va_list ap; va_start (ap, arg); MLKLexicalContext *context = VA_NEXT (ap, arg, nil); id macrofun = nil; va_end (ap); if ([form isKindOfClass:[MLKCons class]] && (![form car] || [[form car] isKindOfClass:[MLKSymbol class]]) && [context symbolNamesMacro:[form car]]) { macrofun = [context macroForSymbol:[form car]]; } else if ([form isKindOfClass:[MLKSymbol class]] && [context symbolNamesSymbolMacro:form]) { macrofun = [context symbolMacroForSymbol:[form car]]; } if (macrofun) { form = denullify ([[macrofun applyToArray: [NSArray arrayWithObjects: form, context, nil]] objectAtIndex:0]); } return form; } id toilet_shadow_ (id *_data, id *_multireturn, id symbols, id arg, ...) { va_list ap; va_start (ap, arg); id package = VA_NEXT (ap, arg, [[MLKDynamicContext currentContext] valueForSymbol: [[MLKPackage findPackage:@"COMMON-LISP"] intern:@"*PACKAGE*"]]); va_end (ap); if (![symbols isKindOfClass:[MLKCons class]]) symbols = [MLKCons cons:symbols with:nil]; do { [package shadow:stringify([symbols car])]; } while ((symbols = [symbols cdr])); return [cl intern:@"T"]; } id toilet_export (id *_data, id *_multireturn, id symbols, id arg, ...) { va_list ap; va_start (ap, arg); id package = VA_NEXT (ap, arg, [[MLKDynamicContext currentContext] valueForSymbol: [[MLKPackage findPackage:@"COMMON-LISP"] intern:@"*PACKAGE*"]]); va_end (ap); if (![symbols isKindOfClass:[MLKCons class]]) symbols = [MLKCons cons:symbols with:nil]; do { [package export:[symbols car]]; } while ((symbols = [symbols cdr])); return [cl intern:@"T"]; } id toilet_unexport (id *_data, id *_multireturn, id symbols, id arg, ...) { va_list ap; va_start (ap, arg); id package = VA_NEXT (ap, arg, [[MLKDynamicContext currentContext] valueForSymbol: [[MLKPackage findPackage:@"COMMON-LISP"] intern:@"*PACKAGE*"]]); va_end (ap); if (![symbols isKindOfClass:[MLKCons class]]) symbols = [MLKCons cons:symbols with:nil]; do { [package unexport:[symbols car]]; } while ((symbols = [symbols cdr])); return [cl intern:@"T"]; } id toilet_find_package (id *_data, id *_multireturn, id name, id _marker) { MLKPackage *package = [MLKPackage findPackage:stringify(name)]; if (package) { return package; } else { [NSException raise:@"MLKNoSuchPackageError" format:@"The package %@ does not exist", MLKPrintToString(name)]; return nil; } } id toilet_string (id *_data, id *_multireturn, id x, id _marker) { return stringify (x); } id toilet_gensym (id *_data, id *_multireturn, id arg, ...) { va_list ap; va_start (ap, arg); id x = VA_NEXT (ap, arg, @"G"); va_end (ap); NSString *prefix; NSString *suffix; MLKBinding *gensymCounter = [[MLKDynamicContext currentContext] bindingForSymbol: [[MLKPackage findPackage:@"COMMON-LISP"] intern:@"*GENSYM-COUNTER*"]]; if ([x isKindOfClass:[NSString class]]) { prefix = x; suffix = MLKPrintToString([gensymCounter value]); [gensymCounter setValue:[(MLKInteger*)[gensymCounter value] add:[MLKInteger integerWithInt:1]]]; } else if ([x isKindOfClass:[MLKInteger class]]) { // x must be an integer. prefix = @"G"; suffix = MLKPrintToString(x); } else { [NSException raise:@"MLKTypeError" format:@"%@ is not of type (OR INTEGER STRING).", x]; return nil; } return [MLKSymbol symbolWithName: [NSString stringWithFormat:@"%@%@", prefix, suffix] package:nil]; } id toilet_make_symbol (id *_data, id *_multireturn, id name, id _marker) { return [MLKSymbol symbolWithName:name package:nil]; } id toilet_intern (id *_data, id *_multireturn, id name, id arg, ...) { va_list ap; va_start (ap, arg); id package = VA_NEXT (ap, arg, [[MLKDynamicContext currentContext] valueForSymbol: [[MLKPackage findPackage:@"COMMON-LISP"] intern:@"*PACKAGE*"]]); va_end (ap); return [package intern:name]; } id toilet_import (id *_data, id *_multireturn, id symbol, id arg, ...) { va_list ap; va_start (ap, arg); id package = VA_NEXT (ap, arg, [[MLKDynamicContext currentContext] valueForSymbol: [[MLKPackage findPackage:@"COMMON-LISP"] intern:@"*PACKAGE*"]]); va_end (ap); [package import:symbol]; return [cl intern:@"T"]; } id toilet_objc_class_of (id *_data, id *_multireturn, id x, id _marker) { return [x class]; } id toilet_objc_subclassp (id *_data, id *_multireturn, id x, id y, id _marker) { return truify ([x isSubclassOfClass:y]); } id toilet_find_objc_class (id *_data, id *_multireturn, id x, id _marker) { return NSClassFromString (x); } id toilet_ns_log (id *_data, id *_multireturn, id x, id _marker) { NSString *description = MLKPrintToString(x); NSLog (@"%@", description); return x; } id toilet_symbol_name (id *_data, id *_multireturn, id symbol, id _marker) { return (symbol ? (id)[symbol name] : (id)@"NIL"); } id toilet_primitive_type_of (id *_data, id *_multireturn, id object, id _marker) { if (!object) { return [cl intern:@"NULL"]; } else if (MLKFixnumP (object)) { return [cl intern:@"FIXNUM"]; } else if ([object isKindOfClass:[MLKSymbol class]]) { return [cl intern:@"SYMBOL"]; } else if ([object isKindOfClass:[MLKCons class]]) { return [cl intern:@"CONS"]; } else if ([object isKindOfClass:[MLKDoubleFloat class]]) { return [cl intern:@"DOUBLE-FLOAT"]; } else if ([object isKindOfClass:[MLKSingleFloat class]]) { return [cl intern:@"SINGLE-FLOAT"]; } else if ([object isKindOfClass:[MLKInteger class]]) { return [cl intern:@"INTEGER"]; } else if ([object isKindOfClass:[MLKCharacter class]]) //FIXME: STANDARD-CHAR { return [cl intern:@"BASE-CHAR"]; } else if ([object isKindOfClass:[MLKInterpretedClosure class]]) { return [cl intern:@"FUNCTION"]; } else if ([object isKindOfClass:[MLKLexicalContext class]]) { return [sys intern:@"LEXICAL-CONTEXT"]; } else if ([object isKindOfClass:[MLKBinding class]]) { return [sys intern:@"BINDING"]; } else if ([object isKindOfClass:[MLKPackage class]]) { return [cl intern:@"PACKAGE"]; } else if ([object isKindOfClass:[MLKBinaryStream class]]) { return [cl intern:@"BINARY-STREAM"]; } else if ([object isKindOfClass:[MLKCharacterStream class]]) { return [cl intern:@"CHARACTER-STREAM"]; } else if ([object isKindOfClass:[NSException class]]) { return [sys intern:@"EXCEPTION"]; } else if ([object isKindOfClass:[NSArray class]]) { return [cl intern:@"ARRAY"]; } else { return [cl intern:@"T"]; } } id toilet_send_by_name (id *_data, id *_multireturn, id object, NSString *methodName, id arg, ...) { NSInvocation *invocation; SEL selector; NSMethodSignature *signature; int i; MLKForeignType returnType; va_list ap; if (MLKFixnumP (object)) object = [MLKInteger integerWithFixnum:object]; selector = NSSelectorFromString (methodName); if (!selector) { [NSException raise:@"MLKNoSuchSelectorError" format:@"Could not find a selector named %@", methodName]; } signature = [object methodSignatureForSelector:selector]; if (!signature) { [NSException raise:@"MLKDoesNotUnderstandError" format:@"%@ does not respond to selector %@", object, methodName]; } invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setSelector:selector]; [invocation setTarget:object]; i = 2; va_start (ap, arg); while (arg != MLKEndOfArgumentsMarker) { const char *objctype = [signature getArgumentTypeAtIndex:i]; MLKForeignType type = MLKForeignTypeWithObjectiveCType (objctype); ffi_type *ffi_argtype = MLKFFITypeWithForeignType (type); void *argbuf = alloca (ffi_argtype->size); if (type == MLKT_INVALID) [NSException raise:@"MLKInvalidArgumentError" format:@"Don't know how to coerce %@ into type \"%s\".", arg, objctype]; MLKSetForeignValueWithLispValue (argbuf, arg, type); [invocation setArgument:argbuf atIndex:i]; arg = va_arg (ap, id); i++; } va_end (ap); [invocation invoke]; returnType = MLKForeignTypeWithObjectiveCType ([signature methodReturnType]); if (returnType == MLKT_INVALID) { [NSException raise:@"MLKInvalidReturnTypeError" format:@"Cannot handle an Objective-C return type of \"%@\" \ as provided by method %@ of object %s", methodName, object, [signature methodReturnType]]; return nil; } else if (returnType == MLKT_VOID) { return nil; } else { ffi_type *ffi_rettype = MLKFFITypeWithForeignType (returnType); void *returnValue = alloca (ffi_rettype->size); [invocation getReturnValue:returnValue]; return MLKLispValueWithForeignValue (returnValue, returnType); } } id toilet_declarations_and_doc_and_forms (id *_data, id *_multireturn, id bodyAndDecls, id _marker) { id decls, doc, forms; MLKSplitDeclarationsDocAndForms (&decls, &doc, &forms, bodyAndDecls, YES); return [MLKCons cons:decls with:[MLKCons cons:doc with:[MLKCons cons:forms with:nil]]]; } id toilet_declarations_and_forms (id *_data, id *_multireturn, id bodyAndDecls, id _marker) { id decls, doc, forms; MLKSplitDeclarationsDocAndForms (&decls, &doc, &forms, bodyAndDecls, NO); return [MLKCons cons:decls with:[MLKCons cons:forms with:nil]]; } id toilet_compile (id *_data, id *_multireturn, id object, id _marker) { if (!MLKDefaultCompiler) [NSException raise:@"MLKNotImplementedException" format:@"It seems as though there is no compiler here."]; //NSLog (@"Compiling lambda form."); id thing = [MLKDefaultCompiler compile:object inContext:[MLKLexicalContext globalContext]]; //NSLog (@"Compilation done."); //NSLog (@"Compiled: %@", thing); return thing; } id toilet_fset (id *_data, id *_multireturn, id symbol, id value, id _marker) { [[MLKLexicalContext globalContext] addFunction:symbol]; [[MLKLexicalEnvironment globalEnvironment] addFunction:value forSymbol:symbol]; return value; } id toilet_set (id *_data, id *_multireturn, id symbol, id value, id _marker) { MLKDynamicContext *dynamicContext = [MLKDynamicContext currentContext]; if ([dynamicContext bindingForSymbol:symbol]) [dynamicContext setValue:value forSymbol:symbol]; else [[MLKDynamicContext globalContext] addValue:value forSymbol:symbol]; return value; } id toilet_macroset (id *_data, id *_multireturn, id symbol, id value, id _marker) { [[MLKLexicalContext globalContext] addMacro:value forSymbol:symbol]; return value; } id toilet_apply (id *_data, id *_multireturn, id function, id arglist, id _marker) { // FIXME: Multiple values. if (!function || [function isKindOfClass:[MLKSymbol class]]) { function = [[MLKLexicalEnvironment globalEnvironment] functionForSymbol:function]; } NSArray *values = [function applyToArray:(arglist ? (id)[arglist array] : (id)[NSArray array])]; return ([values count] > 0 ? denullify([values objectAtIndex:0]) : nil); } id toilet_eval (id *_data, id *_multireturn, id evaluand, id _marker) { // FIXME: Multiple values. NSArray *values = [MLKInterpreter eval:evaluand inLexicalContext: [MLKLexicalContext globalContext] withEnvironment: [MLKLexicalEnvironment globalEnvironment]]; return ([values count] > 0 ? denullify([values objectAtIndex:0]) : nil); } static void register_cl (NSString *name, NSString *c_name, id (*function)()) { MLKCompiledClosure *closure = [MLKCompiledClosure closureWithCode:function data:NULL length:0]; [[MLKLexicalContext globalContext] addFunction:[cl intern:name]]; [[MLKLexicalEnvironment globalEnvironment] addFunction:closure forSymbol:[cl intern:name]]; [lisp_c_name_map setObject:c_name forKey:[cl intern:name]]; } static void register_sys (NSString *name, NSString *c_name, id (*function)()) { MLKCompiledClosure *closure = [MLKCompiledClosure closureWithCode:function data:NULL length:0]; [[MLKLexicalContext globalContext] addFunction:[sys intern:name]]; [[MLKLexicalEnvironment globalEnvironment] addFunction:closure forSymbol:[sys intern:name]]; [lisp_c_name_map setObject:c_name forKey:[sys intern:name]]; } const char *toilet_built_in_function_name(id lisp_name) { NSString *name = [lisp_c_name_map objectForKey:lisp_name]; if (name) { return [name UTF8String]; } else { return NULL; } } @implementation MLKRoot +(void) initialize { lisp_c_name_map = [[NSMutableDictionary alloc] init]; signature = LRETAIN ([self methodSignatureForSelector:@selector(car:)]); sys = [MLKPackage findPackage:@"TOILET-SYSTEM"]; cl = [MLKPackage findPackage:@"COMMON-LISP"]; // NOTE TO SELF: PREFIX NAMES WITH TOILET_ AND UN-STATIC-IZE THEM SO THAT // LLVM MAY FIND AND INVOKE THEM! register_sys (@"CAR", @"toilet_car", toilet_car); register_sys (@"CDR", @"toilet_cdr", toilet_cdr); register_sys (@"RPLACA", @"toilet_rplaca", toilet_rplaca); register_sys (@"RPLACD", @"toilet_rplacd", toilet_rplacd); register_sys (@"CONS", @"toilet_cons", toilet_cons); register_sys (@"LOAD", @"toilet_load", toilet_load); register_sys (@"REQUIRE", @"toilet_require", toilet_require); register_sys (@"EQ", @"toilet_eq", toilet_eq); register_sys (@"FIXNUM-EQ", @"toilet_fixnum_eq", toilet_fixnum_eq); register_sys (@"SYMBOLP", @"toilet_symbolp", toilet_symbolp); register_sys (@"LISTP", @"toilet_listp", toilet_listp); register_sys (@"CONSP", @"toilet_consp", toilet_consp); register_sys (@"ATOM", @"toilet_atom", toilet_atom); register_sys (@"NULL", @"toilet_null", toilet_null); register_sys (@"FIXNUMP", @"toilet_fixnump", toilet_fixnump); register_sys (@"ADD", @"toilet_add", toilet_add); register_sys (@"SUBTRACT", @"toilet_subtract", toilet_subtract); register_sys (@"MULTIPLY", @"toilet_multiply", toilet_multiply); register_sys (@"DIVIDE", @"toilet_divide", toilet_divide); register_sys (@"ADD-FIXNUMS", @"toilet_add_fixnums", toilet_add_fixnums); register_sys (@"SUBTRACT-FIXNUMS", @"toilet_subtract_fixnums", toilet_subtract_fixnums); register_sys (@"MULTIPLY-FIXNUMS", @"toilet_multiply_fixnums", toilet_multiply_fixnums); register_sys (@"IDIVIDE-FIXNUMS", @"toilet_idivide_fixnums", toilet_idivide_fixnums); register_sys (@"LIST", @"toilet_list", (id (*)())toilet_list); register_sys (@"MACROEXPAND-1", @"macroexpand_1", (id (*)())toilet_macroexpand_1); register_sys (@"SHADOW", @"toilet_shadow_", (id (*)())toilet_shadow_); register_sys (@"EXPORT", @"toilet_export", (id (*)())toilet_export); register_sys (@"UNEXPORT", @"toilet_unexport", (id (*)())toilet_unexport); register_sys (@"FIND-PACKAGE", @"toilet_find_package", toilet_find_package); register_sys (@"STRING", @"toilet_string", toilet_string); register_sys (@"GENSYM", @"toilet_gensym", (id (*)())toilet_gensym); register_sys (@"MAKE-SYMBOL", @"toilet_make_symbol", toilet_make_symbol); register_sys (@"INTERN", @"toilet_intern", (id (*)())toilet_intern); register_sys (@"IMPORT", @"toilet_import", (id (*)())toilet_import); register_sys (@"OBJC-CLASS-OF", @"toilet_objc_class_of", toilet_objc_class_of); register_sys (@"OBJC-SUBCLASSP", @"toilet_objc_subclassp", toilet_objc_subclassp); register_sys (@"FIND-OBJC-CLASS", @"toilet_find_objc_class", toilet_find_objc_class); register_sys (@"NS-LOG", @"toilet_ns_log", toilet_ns_log); register_sys (@"SYMBOL-NAME", @"toilet_symbol_name", toilet_symbol_name); register_sys (@"PRIMITIVE-TYPE-OF", @"toilet_primitive_type_of", toilet_primitive_type_of); register_sys (@"SEND-BY-NAME", @"toilet_send_by_name", (id (*)())toilet_send_by_name); register_sys (@"DECLARATIONS-AND-DOC-AND-FORMS", @"toilet_declarations_and_doc_and_forms", toilet_declarations_and_doc_and_forms); register_sys (@"DECLARATIONS-AND-FORMS", @"toilet_declarations_and_forms", toilet_declarations_and_forms); register_sys (@"COMPILE", @"toilet_compile", toilet_compile); register_sys (@"%FSET", @"toilet_fset", toilet_fset); register_sys (@"SET", @"toilet_set", toilet_set); register_sys (@"%MACROSET", @"toilet_macroset", toilet_macroset); register_sys (@"APPLY", @"toilet_apply", toilet_apply); register_sys (@"EVAL", @"toilet_eval", toilet_eval); } +(void) registerBuiltins { // Do the real work in +initialize. } @end