Просмотр исходного кода

Improve behavior of TBKeyPathTokenizer

Tanner Bennett лет назад: 6
Родитель
Сommit
43c15356d9

+ 21 - 7
Classes/GlobalStateExplorers/RuntimeBrowser/TBKeyPathTokenizer.m

@@ -84,7 +84,7 @@ static NSCharacterSet *methodAllowed     = nil;
 
 
 + (TBToken *)scanToken:(NSScanner *)scanner allowed:(NSCharacterSet *)allowedChars first:(NSCharacterSet *)first {
 + (TBToken *)scanToken:(NSScanner *)scanner allowed:(NSCharacterSet *)allowedChars first:(NSCharacterSet *)first {
     if (scanner.isAtEnd) {
     if (scanner.isAtEnd) {
-        if ([scanner.string hasSuffix:@"."]) {
+        if ([scanner.string hasSuffix:@"."] && ![scanner.string hasSuffix:@"\\."]) {
             return [TBToken string:nil options:TBWildcardOptionsAny];
             return [TBToken string:nil options:TBWildcardOptionsAny];
         }
         }
         return nil;
         return nil;
@@ -99,12 +99,10 @@ static NSCharacterSet *methodAllowed     = nil;
     }
     }
 
 
     if ([scanner scanString:@"*." intoString:nil]) {
     if ([scanner scanString:@"*." intoString:nil]) {
-        options = TBWildcardOptionsAny;
         return [TBToken string:nil options:TBWildcardOptionsAny];
         return [TBToken string:nil options:TBWildcardOptionsAny];
     } else if ([scanner scanString:@"*" intoString:nil]) {
     } else if ([scanner scanString:@"*" intoString:nil]) {
         if (scanner.isAtEnd) {
         if (scanner.isAtEnd) {
-            options = TBWildcardOptionsAny;
-            return [TBToken string:nil options:TBWildcardOptionsAny];
+            return [TBToken any];
         }
         }
         
         
         options |= TBWildcardOptionsPrefix;
         options |= TBWildcardOptionsPrefix;
@@ -115,23 +113,38 @@ static NSCharacterSet *methodAllowed     = nil;
     NSCharacterSet *disallowed = allowedChars.invertedSet;
     NSCharacterSet *disallowed = allowedChars.invertedSet;
     while (!stop && ![scanner scanString:@"." intoString:&tmp] && !scanner.isAtEnd) {
     while (!stop && ![scanner scanString:@"." intoString:&tmp] && !scanner.isAtEnd) {
         // Scan word chars
         // Scan word chars
+        // In this block, we have not scanned anything yet, except maybe leading '\' or '\.'
         if (!didScanFirstAllowed) {
         if (!didScanFirstAllowed) {
             if ([scanner scanCharactersFromSet:first intoString:&tmp]) {
             if ([scanner scanCharactersFromSet:first intoString:&tmp]) {
                 [token appendString:tmp];
                 [token appendString:tmp];
                 didScanFirstAllowed = YES;
                 didScanFirstAllowed = YES;
+            } else if ([scanner scanString:@"\\" intoString:nil]) {
+                if (options == TBWildcardOptionsPrefix && [scanner scanString:@"." intoString:nil]) {
+                    [token appendString:@"."];
+                } else if (scanner.isAtEnd && options == TBWildcardOptionsPrefix) {
+                    // Only allow standalone '\' if prefixed by '*'
+                    return [TBToken any];
+                } else {
+                    // Token starts with a number, period, or something else not allowed,
+                    // or token is a standalone '\' with no '*' prefix
+                    @throw NSInternalInconsistencyException;
+                }
             } else {
             } else {
-                // Token starts with a number or something else not allowed
+                // Token starts with a number, period, or something else not allowed
                 @throw NSInternalInconsistencyException;
                 @throw NSInternalInconsistencyException;
             }
             }
         } else if ([scanner scanCharactersFromSet:allowedChars intoString:&tmp]) {
         } else if ([scanner scanCharactersFromSet:allowedChars intoString:&tmp]) {
             [token appendString:tmp];
             [token appendString:tmp];
         }
         }
-        // Scan '\.'
+        // Scan '\.' or trailing '\'
         else if ([scanner scanString:@"\\" intoString:nil]) {
         else if ([scanner scanString:@"\\" intoString:nil]) {
             if ([scanner scanString:@"." intoString:nil]) {
             if ([scanner scanString:@"." intoString:nil]) {
                 [token appendString:@"."];
                 [token appendString:@"."];
+            } else if (scanner.isAtEnd) {
+                // Ignore forward slash not followed by period if at end
+                return [TBToken string:token options:options | TBWildcardOptionsSuffix];
             } else {
             } else {
-                // Invalid token, forward slash not followed by period
+                // Only periods can follow a forward slash
                 @throw NSInternalInconsistencyException;
                 @throw NSInternalInconsistencyException;
             }
             }
         }
         }
@@ -153,6 +166,7 @@ static NSCharacterSet *methodAllowed     = nil;
         }
         }
     }
     }
 
 
+    // Did we scan a trailing, un-escsaped '.'?
     if ([tmp isEqualToString:@"."]) {
     if ([tmp isEqualToString:@"."]) {
         didScanDelimiter = YES;
         didScanDelimiter = YES;
     }
     }

+ 1 - 1
Classes/GlobalStateExplorers/RuntimeBrowser/TBToken.m

@@ -19,7 +19,7 @@
     static TBToken *any = nil;
     static TBToken *any = nil;
     static dispatch_once_t onceToken;
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
     dispatch_once(&onceToken, ^{
-        any = [self string:@"" options:TBWildcardOptionsAny];
+        any = [self string:nil options:TBWildcardOptionsAny];
     });
     });
 
 
     return any;
     return any;