Browse files

playing with a new parser strategy.

  • Loading branch information...
1 parent 02e1b01 commit 2789c347f6207e25398e5bc6d754ecfa31dec54e @ccgus committed Jun 29, 2009
Showing with 197 additions and 158 deletions.
  1. +5 −20 src/JSTPreprocessor.h
  2. +115 −138 src/JSTPreprocessor.m
  3. +4 −0 src/JSTalk.m
  4. +73 −0 tests/preprocess.jstalk
View
25 src/JSTPreprocessor.h
@@ -19,34 +19,19 @@
-
-
-@interface JSTPObjcCall : NSObject {
+@interface JSTPSymbolGroup : NSObject {
+ unichar _openSymbol;
NSMutableArray *_args;
-
- JSTPObjcCall *_parent;
-
- NSString *_target;
- NSString *_lastString;
- NSMutableString *_selector;
- NSMutableString *_currentArgument;
-
- NSUInteger _parentCount;
+ JSTPSymbolGroup *_parent;
}
@property (retain) NSMutableArray *args;
-@property (retain) NSMutableString *selector;
-@property (retain) NSString *target;
-@property (retain) NSString *lastString;
-@property (retain) NSMutableString *currentArgument;
-@property (assign) JSTPObjcCall *parent;
+@property (retain) JSTPSymbolGroup *parent;
-- (void) addSymbol:(id)whatever;
+- (void) addSymbol:(id)aSymbol;
@end
-
-
View
253 src/JSTPreprocessor.m
@@ -49,76 +49,64 @@ + (NSString*) preprocessForObjCStrings:(NSString*)sourceString {
return buffer;
}
++ (BOOL) isOpenSymbol:(NSString*)tag {
+ return [tag isEqualToString:@"["] || [tag isEqualToString:@"("];
+}
+
++ (BOOL) isCloseSymbol:(NSString*)tag {
+ return [tag isEqualToString:@"]"] || [tag isEqualToString:@")"];
+}
+
+ (NSString*) preprocessForObjCMessagesToJS:(NSString*)sourceString {
NSMutableString *buffer = [NSMutableString string];
TDTokenizer *tokenizer = [TDTokenizer tokenizerWithString:sourceString];
tokenizer.whitespaceState.reportsWhitespaceTokens = YES;
- tokenizer.commentState.reportsCommentTokens = NO;
+ tokenizer.commentState.reportsCommentTokens = YES;
TDToken *eof = [TDToken EOFToken];
TDToken *tok = nil;
- BOOL lastWasWord = NO;
- NSUInteger bracketCount = 0;
- JSTPObjcCall *currentObjcCall = 0x00;
+
+ JSTPSymbolGroup *currentGroup = 0x00;
while ((tok = [tokenizer nextToken]) != eof) {
- if (tok.isSymbol && !lastWasWord && [tok.stringValue isEqualToString:@"["]) {
+ //debug(@"tok: '%@' %d", [tok description], tok.word);
+
+ if ([tok isSymbol] && [self isOpenSymbol:[tok stringValue]]) {
- tokenizer.whitespaceState.reportsWhitespaceTokens = NO;
+ JSTPSymbolGroup *nextGroup = [[[JSTPSymbolGroup alloc] init] autorelease];
- if (!bracketCount) {
- currentObjcCall = [[[JSTPObjcCall alloc] init] autorelease];
- }
- else {
- JSTPObjcCall *newobjc = [[[JSTPObjcCall alloc] init] autorelease];
-
- newobjc.parent = currentObjcCall;
-
- currentObjcCall = newobjc;
- }
-
- bracketCount++;
+ nextGroup.parent = currentGroup;
+ currentGroup = nextGroup;
+
}
- else if (bracketCount && tok.isSymbol && [tok.stringValue isEqualToString:@"]"]) {
-
- bracketCount--;
+ else if (tok.isSymbol && [self isCloseSymbol:tok.stringValue]) {
- if (!bracketCount) {
- // we're done!
-
- tokenizer.whitespaceState.reportsWhitespaceTokens = YES;
-
- }
-
- JSTPObjcCall *parent = currentObjcCall.parent;
-
- if (!parent) {
- [buffer appendString:[currentObjcCall description]];
+ if (currentGroup.parent) {
+ [currentGroup.parent addSymbol:currentGroup];
}
else {
- [parent addSymbol:currentObjcCall];
+ [buffer appendString:[currentGroup description]];
}
- currentObjcCall = parent;
+ currentGroup = currentGroup.parent;
+ continue;
}
- else if (bracketCount) {
- [currentObjcCall addSymbol:[tok stringValue]];
+
+ if (currentGroup) {
+ [currentGroup addSymbol:tok];
}
else {
[buffer appendString:[tok stringValue]];
}
-
- lastWasWord = tok.isWord;
}
return buffer;
}
-
+ (NSString*) preprocessCode:(NSString*)sourceString {
sourceString = [self preprocessForObjCStrings:sourceString];
@@ -131,164 +119,153 @@ + (NSString*) preprocessCode:(NSString*)sourceString {
-
-@implementation JSTPObjcCall
+@implementation JSTPSymbolGroup
@synthesize args=_args;
-@synthesize selector=_selector;
-@synthesize target=_target;
-@synthesize lastString=_lastString;
-@synthesize currentArgument=_currentArgument;
@synthesize parent=_parent;
- (id) init {
self = [super init];
if (self != nil) {
- self.currentArgument = [NSMutableString string];
+ _args = [[NSMutableArray array] retain];
}
+
return self;
}
- (void)dealloc {
[_args release];
- [_selector release];
- [_target release];
- [_lastString release];
- [_currentArgument release];
+ [_parent release];
[super dealloc];
}
-
- (void) addSymbol:(id)aSymbol {
- //debug(@"aSymbol: %@ (%@)", aSymbol, NSStringFromClass([aSymbol class]));
-
- // the first bit is always the target.
- if (!_target) {
- self.target = aSymbol;
- return;
+ if (!_openSymbol && [aSymbol isKindOfClass:[TDToken class]]) {
+ _openSymbol = [[aSymbol stringValue] characterAtIndex:0];
}
-
- // the second bit is the first part of the selector.
- if (!_selector) {
- self.selector = [NSMutableString stringWithString:aSymbol];
- return;
+ else {
+ [_args addObject:aSymbol];
}
+}
+
+- (NSString*) description {
- // be lazy about creating this guy
- if (!_args) {
- self.args = [NSMutableArray array];
- }
+ NSUInteger argsCount = [_args count];
- if ([aSymbol isKindOfClass:[JSTPObjcCall class]]) {
-
- if ([_lastString length]) {
- //debug(@"adding %@ to current args", _lastString);
- [_currentArgument appendString:_lastString];
- [_args addObject:_currentArgument];
- self.lastString = 0x00;
- }
-
- [_args addObject:[aSymbol description]];
-
- self.currentArgument = [NSMutableString string];
-
- return;
+ if (_openSymbol == '(') {
+ return [NSString stringWithFormat:@"(%@)", [_args componentsJoinedByString:@""]];
}
- if ([aSymbol isEqualToString:@","]) {
-
- if ([_lastString length]) {
- [_currentArgument appendString:_lastString];
- [_args addObject:_currentArgument];
- self.lastString = 0x00;
- }
-
- self.currentArgument = [NSMutableString string];
-
- return;
+ if (_openSymbol != '[') {
+ return [NSString stringWithFormat:@"Bad JSTPSymbolGroup! %@", _args];
}
+ BOOL firstArgIsWord = [_args count] && ([[_args objectAtIndex:0] isKindOfClass:[TDToken class]] && [[_args objectAtIndex:0] isWord]);
+ BOOL firstArgIsSymbolGroup = [_args count] && [[_args objectAtIndex:0] isKindOfClass:[JSTPSymbolGroup class]];
- // sanity check.
- if (![aSymbol isKindOfClass:[NSString class]]) {
- // what in the heck...
- NSBeep();
- return;
+ // objc messages start with a word. So, if it isn't- then let's just fling things back the way they were.
+ if (!firstArgIsWord && !firstArgIsSymbolGroup) {
+ return [NSString stringWithFormat:@"[%@]", [_args componentsJoinedByString:@""]];
}
- // yay, it's part of our selector! maybe? what about "foo ? bar : xyz" ? Yea, gotta fix that.
- if ([aSymbol isEqualToString:@":"]) {
+
+ NSMutableString *selector = [NSMutableString string];
+ NSMutableArray *currentArgs = [NSMutableArray array];
+ NSMutableArray *methodArgs = [NSMutableArray array];
+ NSString *target = [_args objectAtIndex:0];
+ NSString *lastWord = 0x00;
+ BOOL hadSymbolAsArg = NO;
+ NSUInteger idx = 1;
+
+ while (idx < argsCount) {
- if ([_lastString length]) {
- [self.selector appendString:_lastString];
- self.lastString = 0x00;
- }
+ id currentPassedArg = [_args objectAtIndex:idx++];
+
+ TDToken *currentToken = [currentPassedArg isKindOfClass:[TDToken class]] ? currentPassedArg : 0x00;
- [self.selector appendString:aSymbol];
+ if ([currentToken isWhitespace]) {
+ continue;
+ }
- if ([_currentArgument length]) {
- [_args addObject:_currentArgument];
+ if (!hadSymbolAsArg && [currentToken isSymbol]) {
+ hadSymbolAsArg = YES;
}
- self.currentArgument = [NSMutableString string];
+ NSString *value = currentToken ? [currentToken stringValue] : [currentPassedArg description];
- return;
+ if ([@":" isEqualToString:value]) {
+
+ [currentArgs removeLastObject];
+
+ if ([currentArgs count]) {
+ [methodArgs addObject:[currentArgs componentsJoinedByString:@" "]];
+ [currentArgs removeAllObjects];
+ }
+
+ [selector appendString:lastWord];
+ [selector appendString:value];
+ }
+ else {
+ [currentArgs addObject:[value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
+ }
+
+ lastWord = value;
}
+ if ([currentArgs count]) {
+ [methodArgs addObject:[currentArgs componentsJoinedByString:@""]];
+ }
- if (_lastString) {
- [_currentArgument appendString:_lastString];
+ if (![selector length] && !hadSymbolAsArg && ([methodArgs count] == 1)) {
+ [selector appendString:[methodArgs lastObject]];
+ [methodArgs removeAllObjects];
}
- self.lastString = aSymbol;
-}
-
-- (NSString*) description {
-
- if (![_selector length]) {
- // ... whoops, was it an array call?
- return [NSString stringWithFormat:@"[%@]", _target];
+ if (![selector length] && [methodArgs count] == 1) {
+ return [NSString stringWithFormat:@"[%@%@]", target, [methodArgs lastObject]];
}
- if ([_lastString length]) {
- [_currentArgument appendString:_lastString];
- self.lastString = 0x00;
+ if (![methodArgs count] && ![selector length]) {
+ return [NSString stringWithFormat:@"[%@]", target];
}
- if ([_currentArgument length]) {
- [_args addObject:_currentArgument];
- self.currentArgument = 0x00;
+ if (![selector length] && lastWord) {
+ [selector appendString:lastWord];
+ [methodArgs removeLastObject];
}
- NSMutableString *ret = [NSMutableString string];
+ BOOL useMsgSend = NO;
- NSString *method = [self.selector stringByReplacingOccurrencesOfString:@":" withString:@"_"];
+ if (useMsgSend) {
+ NSMutableString *ret = [NSMutableString stringWithFormat:@"jstalk_msgsend(%@, '%@'", target, selector];
+
+ if ([methodArgs count]) {
+ [ret appendString:@", "];
+ [ret appendString:[methodArgs componentsJoinedByString:@", "]];
+ }
+
+ [ret appendString:@")"];
+
+ return ret;
+ }
- [ret appendFormat:@"%@.%@(", _target, method];
+ [selector replaceOccurrencesOfString:@":" withString:@"_" options:0 range:NSMakeRange(0, [selector length])];
- for (id foo in _args) {
- [ret appendFormat:@"%@, ", [foo description]];
- }
+ NSMutableString *ret = [NSMutableString stringWithFormat:@"%@.%@(", target, selector];
- // get rid of the last comma
- if ([_args count]) {
- [ret deleteCharactersInRange:NSMakeRange([ret length] - 2 , 2)];
+ if ([methodArgs count]) {
+ [ret appendString:[methodArgs componentsJoinedByString:@", "]];
}
-
[ret appendString:@")"];
return ret;
+
}
-
@end
-
-
-
-
View
4 src/JSTalk.m
@@ -212,6 +212,10 @@ - (void) print:(NSString*)s {
[_printController print:s];
}
else {
+ if (![s isKindOfClass:[NSString class]]) {
+ s = [s description];
+ }
+
printf("%s\n", [s UTF8String]);
}
}
View
73 tests/preprocess.jstalk
@@ -0,0 +1,73 @@
+var count = 1;
+var tests = new Array();
+
+var process = function (a, b) {
+
+ //print("running test " + count);
+
+ a = [JSTPreprocessor preprocessCode:a];
+
+ if (a != b) {
+ NSBeep();
+ print("Failure for test " + count);
+ print(a + "\nshould be equal to:\n" + b);
+ return false;
+ }
+
+ print("Success for test " + count);
+
+ count++;
+
+ return true;
+}
+
+var addTest = function (a, b) {
+ tests.push(new Array(a, b));
+}
+
+print("Staring preprocessing tests.")
+
+addTest('print([4 - 5, b]);',
+ 'print([4 - 5, b]);');
+
+addTest('print([a, b]);',
+ 'print([a,b]);');
+
+addTest('[db executeUpdate:"insert into foo values (?, ?, ?)",\n 1, // comment!\n @"Hello",\n [NSDate date]];',
+ 'db.executeUpdate_("insert into foo values (?, ?, ?)",1,NSString.stringWithString_("Hello"),NSDate.date());');
+
+addTest('[db executeUpdate:"insert into foo values (?, ?)", 1, "Hello"];',
+ 'db.executeUpdate_("insert into foo values (?, ?)",1,"Hello");');
+
+addTest('var acorn = [JSTalk application:"Acorn"];',
+ 'var acorn = JSTalk.application_("Acorn");');
+
+addTest('print([]);',
+ 'print([]);');
+
+addTest('[fo doSomething:" a " + [b fun] + " c " in:nil];',
+ 'fo.doSomething_in_(" a " + b.fun() + " c ", nil);');
+
+addTest('[NSFullUserName() lowercaseString];',
+ 'NSFullUserName().lowercaseString();');
+
+
+
+var stopOnFirstFail = false;
+var shouldContinue = true;
+var len = tests.length;
+var idx = 0;
+while (shouldContinue && idx < len) {
+ var a = tests[idx][0];
+ var b = tests[idx][1];
+
+ shouldContinue = process(a, b);
+
+ shouldContinue = stopOnFirstFail ? shouldContinue : true;
+
+ idx++;
+}
+
+print("Done");
+
+// what about "foo ? bar : xyz" ? Yea, gotta fix that.

0 comments on commit 2789c34

Please sign in to comment.