From e02c197a86a9c177937a6df95a92ab05b009a479 Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Sat, 14 Jun 2008 19:38:29 +0200 Subject: Implement most of the Common Lisp reader. --- GNUmakefile | 6 +-- MLKCharacter.h | 32 ++++++++++++ MLKEndOfFileError.h | 32 ++++++++++++ MLKEndOfFileError.m | 35 +++++++++++++ MLKPackage.h | 53 +++++++++++++++++++ MLKReader.h | 30 +++++++++++ MLKReader.m | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++ MLKReaderError.h | 32 ++++++++++++ MLKReaderError.m | 35 +++++++++++++ MLKReadtable.h | 43 +++++++++++++++ 10 files changed, 443 insertions(+), 3 deletions(-) create mode 100644 MLKCharacter.h create mode 100644 MLKEndOfFileError.h create mode 100644 MLKEndOfFileError.m create mode 100644 MLKPackage.h create mode 100644 MLKReader.h create mode 100644 MLKReader.m create mode 100644 MLKReaderError.h create mode 100644 MLKReaderError.m create mode 100644 MLKReadtable.h diff --git a/GNUmakefile b/GNUmakefile index b2de3a9..9eb3844 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -18,9 +18,9 @@ include $(GNUSTEP_MAKEFILES)/common.make TOOL_NAME = etoilisp -etoilisp_OBJC_FILES = MLKCons.m MLKDynamicContext.m MLKEnvironment.m \ - MLKLinkedList.m MLKLispValue.m MLKSymbol.m \ - MLKThrowException.m \ +etoilisp_OBJC_FILES = MLKCons.m MLKDynamicContext.m MLKEndOfFileError.m \ + MLKEnvironment.m MLKLinkedList.m MLKLispValue.m \ + MLKReader.m MLKSymbol.m MLKThrowException.m \ MLKUndefinedVariableException.m BUNDLE_NAME = Test diff --git a/MLKCharacter.h b/MLKCharacter.h new file mode 100644 index 0000000..664803a --- /dev/null +++ b/MLKCharacter.h @@ -0,0 +1,32 @@ +/* -*- mode: objc; coding: utf-8 -*- */ +/* Étoilisp/Mulklisp, 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 "MLKLispValue.h" + +#import + + +@interface MLKCharacter : MLKLispValue +{ + unichar unichar; +} + +-(MLKCharacter*) initWithUnichar:(unichar)anUnichar; + ++(MLKCharacter*) characterWithUnichar:(unichar)anUnichar; +@end diff --git a/MLKEndOfFileError.h b/MLKEndOfFileError.h new file mode 100644 index 0000000..cb066c1 --- /dev/null +++ b/MLKEndOfFileError.h @@ -0,0 +1,32 @@ +/* -*- mode: objc; coding: utf-8 -*- */ +/* Étoilisp/Mulklisp, 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 + +@class MLKStream; + + +@interface MLKEndOfFileError : NSException +{ + MLKStream *stream; +} + +-(MLKEndOfFileError *) initWithStream:(MLKStream *)aStream; + +-(void) dealloc; +@end diff --git a/MLKEndOfFileError.m b/MLKEndOfFileError.m new file mode 100644 index 0000000..237c2b2 --- /dev/null +++ b/MLKEndOfFileError.m @@ -0,0 +1,35 @@ +/* -*- mode: objc; coding: utf-8 -*- */ +/* Étoilisp/Mulklisp, 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 "MLKEndOfFileError.h" + + +@implementation MLKEndOfFileError +-(MLKEndOfFileError *) initWithStream:(MLKStream *)aStream +{ + self = [super init]; + stream = aStream; + return self; +} + +-(void) dealloc +{ + RELEASE (stream); + [super dealloc]; +} +@end diff --git a/MLKPackage.h b/MLKPackage.h new file mode 100644 index 0000000..25834f1 --- /dev/null +++ b/MLKPackage.h @@ -0,0 +1,53 @@ +/* -*- mode: objc; coding: utf-8 -*- */ +/* Étoilisp/Mulklisp, 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 "MLKLispValue.h" + +@class MLKSymbol, NSMutableDictionary, NSMutableSet, NSSet, NSString; + + +@interface MLKPackage : MLKLispValue +{ + NSMutableDictionary *symbols; + NSMutableSet *exported_symbols; + NSMutableSet *shadowed_symbols; + NSMutableSet *nicknames; + NSString *name; +} + +-(MLKPackage *) initWithName:(NSString *)name + nicknames:(NSSet *)nicknames; + +-(void) usePackage:(MLKPackage *)aPackage; +-(void) import:(MLKSymbol *)aSymbol; +-(void) shadow:(MLKPackage *)aPackage; +-(void) unintern:(MLKSymbol *)aSymbol; +-(MLKSymbol *) intern:(NSString*)symbolName; +-(MLKSymbol *) findSymbol:(NSString*)symbolName; + +-(NSString *) name; +-(NSSet *) nicknames; +-(NSSet *) exportedSymbols; +-(NSSet *) shadowedSymbols; +-(NSSet *) allSymbols; + +// [clUser cons: @"Mulk", [clUser __intern: @"NIL"]] ought to do the +// Right Thing. +-(void) forwardInvocation:(NSInvocation *)anInvocation; +-(BOOL) respondsToSelector:(SEL)selector; +@end diff --git a/MLKReader.h b/MLKReader.h new file mode 100644 index 0000000..9e62e9d --- /dev/null +++ b/MLKReader.h @@ -0,0 +1,30 @@ +/* -*- mode: objc; coding: utf-8 -*- */ +/* Étoilisp/Mulklisp, 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 . + */ + +#include + +@class MLKStream; + + +@interface MLKReader : NSObject ++(id) readFromStream:(MLKStream *)stream + eofError:(BOOL)eofError + eofValue:(id)eofValue + recursive:(BOOL)recursive + preserveWhitespace:(BOOL)preserveWhitespace; +@end diff --git a/MLKReader.m b/MLKReader.m new file mode 100644 index 0000000..fba2ef2 --- /dev/null +++ b/MLKReader.m @@ -0,0 +1,148 @@ +/* -*- mode: objc; coding: utf-8 -*- */ +/* Étoilisp/Mulklisp, 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 "MLKReader.h" +#import "MLKCharacter.h" +#import "MLKReadtable.h" +#import "MLKEndOfFileError.h" +#import "MLKReaderError.h" +#import "MLKDynamicContext.h" +#import "MLKEnvironment.h" +#import "MLKPackage.h" + +#import +#import + + +@implementation MLKReader ++(id) readFromStream:(MLKStream *)stream + eofError:(BOOL)eofError + eofValue:(id)eofValue + recursive:(BOOL)recursive + preserveWhitespace:(BOOL)preserveWhitespace +{ + unichar ch; + NSMutableString *token; + MLKReadtable *readtable; + BOOL escaped; + + readtable = [[[MLKDynamicContext currentContext] environment] + valueForBinding:[[MLKPackage commonLisp] + intern:@"*READTABLE*"]]; + + start: + if ([stream isEOF]) + { + if (eofError) + [[[MLKEndOfFileError alloc] initWithStream:stream] raise]; + else + return eofValue; + } + + ch = [stream readChar]; + if ([readtable isWhitespaceCharacter:ch]) + goto start; + + if ([readtable isMacroCharacter:ch]) + { + NSArray *returnValues; + MLKClosure *macrofun = [readtable macroFunctionForCharacter:ch]; + NSArray *args = [NSArray arrayWithObjects: + stream, + [MLKCharacter characterWithUnichar:ch], + nil]; + if ([args count] != 2) + { + args = [NSMutableArray arrayWithCapacity:2]; + [((NSMutableArray*)args) addObject:stream]; + [((NSMutableArray*)args) addObject:[MLKCharacter + characterWithUnichar:ch]]; + } + returnValues = [macrofun applyToArray:args]; + if ([returnValues count]) + return [returnValues objectAtIndex:0]; + else + goto start; + } + + escaped = NO; + + if ([readtable isSingleEscapeCharacter:ch]) + { + if ([stream isEOF]) + [[[MLKEndOfFileError alloc] initWithStream:stream] raise]; + + token = [NSMutableString stringWithCapacity:8]; + [token appendFormat:@"%C", [stream readChar]]; + } + + if ([readtable isMultipleEscapeCharacter:ch]) + { + token = [NSMutableString stringWithCapacity:8]; + escaped = YES; + } + + if ([readtable isConstituentCharacter:ch]) + { + token = [NSMutableString stringWithCapacity:8]; + [token appendFormat:@"%C", [stream readChar]]; + } + + while (![stream isEOF]) + { + ch = [stream readChar]; + if ([readtable isConstituentCharacter:ch] || + [readtable isNonTerminatingMacroCharacter:ch] || + (escaped && [readtable isWhitespaceCharacter:ch])) + { + if (escaped) + [token appendFormat:@"%C", ch]; + else + [token appendFormat:@"%C", [readtable charWithReadtableCase:ch]]; + } + else if ([readtable isSingleEscapeCharacter:ch]) + { + if ([stream isEOF]) + [[[MLKEndOfFileError alloc] initWithStream:stream] raise]; + + token = [NSMutableString stringWithCapacity:8]; + [token appendFormat:@"%C", [stream readChar]]; + } + else if ([readtable isMultipleEscapeCharacter:ch]) + escaped = !escaped; + else if ([readtable isTerminatingMacroCharacter:ch]) + { + [stream unreadChar]; + break; + } + else if ([readtable isWhitespaceCharacter:ch]) + { + if (preserveWhitespace) + [stream unreadChar]; + break; + } + else if ([readtable isInvalidCharacter:ch]) + { + [[[MLKReaderError alloc] initWithStream:stream] raise]; + } + } + + // FIXME: Check the token for invalid syntax. + return token; +} +@end diff --git a/MLKReaderError.h b/MLKReaderError.h new file mode 100644 index 0000000..7c48911 --- /dev/null +++ b/MLKReaderError.h @@ -0,0 +1,32 @@ +/* -*- mode: objc; coding: utf-8 -*- */ +/* Étoilisp/Mulklisp, 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 + +@class MLKStream; + + +@interface MLKReaderError : NSException +{ + MLKStream *stream; +} + +-(MLKReaderError *) initWithStream:(id)aStream; + +-(void) dealloc; +@end diff --git a/MLKReaderError.m b/MLKReaderError.m new file mode 100644 index 0000000..ce23176 --- /dev/null +++ b/MLKReaderError.m @@ -0,0 +1,35 @@ +/* -*- mode: objc; coding: utf-8 -*- */ +/* Étoilisp/Mulklisp, 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 "MLKEndOfFileError.h" + + +@implementation MLKReaderError +-(MLKReaderError *) initWithStream:(MLKStream *)aStream +{ + self = [super init]; + stream = aStream; + return self; +} + +-(void) dealloc +{ + RELEASE (stream); + [super dealloc]; +} +@end diff --git a/MLKReadtable.h b/MLKReadtable.h new file mode 100644 index 0000000..ed08d84 --- /dev/null +++ b/MLKReadtable.h @@ -0,0 +1,43 @@ +/* -*- mode: objc; coding: utf-8 -*- */ +/* Étoilisp/Mulklisp, 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 "MLKLispValue.h" + +@class NSMutableDictionary; + + +enum MLKReadtableCase +{ + MLKReadtableCase_UPCASE, + MLKReadtableCase_DOWNCASE, + MLKReadtableCase_INVERT, + MLKReadtableCase_PRESERVE +}; + + +@interface MLKReadtable : MLKLispValue +{ + NSMutableDictionary *_syntaxTable; + NSMutableDictionary *_readerMacros; + //MLKClosure *_caseConverter; + enum MLKReadtableCase _case; +} + +-(MLKReadtable *) init; +-(MLKReadtable *) copy; +@end -- cgit v1.2.3