diff --git a/src/classes/GRMustacheTemplateParser.m b/src/classes/GRMustacheTemplateParser.m index ac4f165f..283b4092 100644 --- a/src/classes/GRMustacheTemplateParser.m +++ b/src/classes/GRMustacheTemplateParser.m @@ -242,9 +242,8 @@ - (GRMustacheInvocation *)invocationWithToken:(GRMustacheToken *)token error:(NS { NSString *content = token.content; NSUInteger length = content.length; - BOOL acceptDotIdentifier = YES; BOOL acceptIdentifier = YES; - BOOL acceptSeparator = NO; + BOOL acceptSeparator = YES; NSMutableArray *keys = [NSMutableArray array]; unichar c; NSUInteger identifierStart = 0; @@ -252,15 +251,15 @@ - (GRMustacheInvocation *)invocationWithToken:(GRMustacheToken *)token error:(NS c = [content characterAtIndex:i]; switch (c) { case '.': - if (acceptDotIdentifier) { - [keys addObject:[content substringWithRange:NSMakeRange(identifierStart, i+1-identifierStart)]]; - acceptDotIdentifier = NO; - acceptIdentifier = NO; - acceptSeparator = NO; - } else if (acceptSeparator) { - [keys addObject:[content substringWithRange:NSMakeRange(identifierStart, i-identifierStart)]]; + if (acceptSeparator) { + if (i==0) { + // leading dot: "." or ".foo…" + [keys addObject:@"."]; + } else { + // dot in the middle: "foo.bar…" + [keys addObject:[content substringWithRange:NSMakeRange(identifierStart, i-identifierStart)]]; + } identifierStart = i + 1; - acceptDotIdentifier = NO; acceptIdentifier = YES; acceptSeparator = NO; } else { @@ -273,7 +272,6 @@ - (GRMustacheInvocation *)invocationWithToken:(GRMustacheToken *)token error:(NS default: if (acceptIdentifier) { - acceptDotIdentifier = NO; acceptIdentifier = YES; acceptSeparator = YES; } else { @@ -287,7 +285,8 @@ - (GRMustacheInvocation *)invocationWithToken:(GRMustacheToken *)token error:(NS } if (acceptSeparator) { [keys addObject:[content substringWithRange:NSMakeRange(identifierStart, length - identifierStart)]]; - } else if (acceptIdentifier) { + } else if (acceptIdentifier && length > 1) { + // dot at the end: "…foo." if (outError != NULL) { *outError = [self parseErrorAtToken:token description:[NSString stringWithFormat:@"Invalid identifier: %@", content]]; } diff --git a/src/tests/Public/v3.0/GRMustacheParsingErrorsTest.m b/src/tests/Public/v3.0/GRMustacheParsingErrorsTest.m index 48f4fc51..84c23041 100644 --- a/src/tests/Public/v3.0/GRMustacheParsingErrorsTest.m +++ b/src/tests/Public/v3.0/GRMustacheParsingErrorsTest.m @@ -62,12 +62,6 @@ - (void)testParsingReportsEmptyVariableTag - (void)testParsingReportsBadlyFormattedVariableTag { NSError *error; - - // ".a" could mean anchored access to "self.a". - // But it doesn't mean anything, actually. - STAssertNil([GRMustacheTemplate templateFromString:@"{{.a}}" error:&error], nil); - STAssertEquals(error.code, (NSInteger)GRMustacheErrorCodeParseError, nil); - STAssertNil([GRMustacheTemplate templateFromString:@"{{a.}}" error:&error], nil); STAssertEquals(error.code, (NSInteger)GRMustacheErrorCodeParseError, nil); STAssertNil([GRMustacheTemplate templateFromString:@"{{..}}" error:&error], nil); diff --git a/src/tests/Public/v3.0/GRMustacheSuites/compound_keys.json b/src/tests/Public/v3.0/GRMustacheSuites/compound_keys.json index a781ba5e..7ca76242 100644 --- a/src/tests/Public/v3.0/GRMustacheSuites/compound_keys.json +++ b/src/tests/Public/v3.0/GRMustacheSuites/compound_keys.json @@ -29,6 +29,48 @@ "data": { "person": { } }, "template": "{{person.name}}", "expected": "" + }, + { + "name": "key lookup is anchored", + "data": { "b": "b", "a": { } }, + "template": "-{{#a}}{{b}}{{/a}}-{{a.b}}-", + "expected": "-b--" + }, + { + "name": "key lookup is anchored", + "data": { "c": "c", "b": { "c" : "cb" } }, + "template": "-{{a.b.c}}-", + "expected": "--" + }, + { + "name": "key lookup is anchored", + "data": { "c": "c", "b": { "c" : "cb" }, "a": { } }, + "template": "-{{a.b.c}}-", + "expected": "--" + }, + { + "name": "key lookup is anchored", + "data": { "c": "c", "b": { "c" : "cb" }, "a": { "b": { } } }, + "template": "-{{a.b.c}}-", + "expected": "--" + }, + { + "name": "key lookup is anchored", + "data": { "c": "c", "b": { "c" : "cb" }, "a": { "b": { "c": "ca" } } }, + "template": "-{{a.b.c}}-", + "expected": "-ca-" + }, + { + "name": "key lookup is anchored", + "data": { "b": "b", "a": { } }, + "template": "-{{#a}}{{b}}{{/a}}-{{#a}}{{.b}}{{/a}}-{{a.b}}-", + "expected": "-b---" + }, + { + "name": "key lookup is anchored", + "data": { "b": "b", "a": { "b": "ba"} }, + "template": "-{{#a}}{{b}}{{/a}}-{{#a}}{{.b}}{{/a}}-{{a.b}}-", + "expected": "-ba-ba-ba-" } ] }