| OLD | NEW |
| 1 # Copyright 2012 Benjamin Kalman | 1 # Copyright 2012 Benjamin Kalman |
| 2 # | 2 # |
| 3 # Licensed under the Apache License, Version 2.0 (the "License"); | 3 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 # you may not use this file except in compliance with the License. | 4 # you may not use this file except in compliance with the License. |
| 5 # You may obtain a copy of the License at | 5 # You may obtain a copy of the License at |
| 6 # | 6 # |
| 7 # http://www.apache.org/licenses/LICENSE-2.0 | 7 # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 # | 8 # |
| 9 # Unless required by applicable law or agreed to in writing, software | 9 # Unless required by applicable law or agreed to in writing, software |
| 10 # distributed under the License is distributed on an "AS IS" BASIS, | 10 # distributed under the License is distributed on an "AS IS" BASIS, |
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 self.text.Append(text) | 268 self.text.Append(text) |
| 269 | 269 |
| 270 def GetResult(self): | 270 def GetResult(self): |
| 271 return RenderResult(self.text.ToString(), self._errors); | 271 return RenderResult(self.text.ToString(), self._errors); |
| 272 | 272 |
| 273 class _Identifier(object): | 273 class _Identifier(object): |
| 274 '''An identifier of the form 'foo', 'foo.bar.baz', 'foo-bar.baz', etc. | 274 '''An identifier of the form 'foo', 'foo.bar.baz', 'foo-bar.baz', etc. |
| 275 ''' | 275 ''' |
| 276 _VALID_ID_MATCHER = re.compile(r'^[a-zA-Z0-9@_/-]+$') | 276 _VALID_ID_MATCHER = re.compile(r'^[a-zA-Z0-9@_/-]+$') |
| 277 | 277 |
| 278 def __init__(self, name, line, column): | 278 def __init__(self, name, line, column, title=None): |
| 279 self.name = name | 279 self.name = name |
| 280 self.line = line | 280 self.line = line |
| 281 self.column = column | 281 self.column = column |
| 282 self._title = title |
| 282 if name == '': | 283 if name == '': |
| 283 raise ParseException('Empty identifier %s' % self.GetDescription()) | 284 raise ParseException('Empty identifier %s' % self.GetDescription()) |
| 284 for part in name.split('.'): | 285 for part in name.split('.'): |
| 285 if not _Identifier._VALID_ID_MATCHER.match(part): | 286 if not _Identifier._VALID_ID_MATCHER.match(part): |
| 286 raise ParseException('Invalid identifier %s' % self.GetDescription()) | 287 raise ParseException('Invalid identifier %s' % self.GetDescription()) |
| 287 | 288 |
| 288 def GetDescription(self): | 289 def GetDescription(self): |
| 289 return '\'%s\' at line %s column %s' % (self.name, self.line, self.column) | 290 desc = '\'%s\' at line %s column %s' % (self.name, self.line, self.column) |
| 291 if self._title is not None: |
| 292 desc = '%s: %s' % (self._title, desc) |
| 293 return desc |
| 290 | 294 |
| 291 def CreateResolutionErrorMessage(self, name, stack=None): | 295 def CreateResolutionErrorMessage(self, name, stack=None): |
| 292 message = _StringBuilder() | 296 message = _StringBuilder() |
| 293 message.Append('Failed to resolve %s in %s\n' % (self.GetDescription(), | 297 message.Append('Failed to resolve %s in %s\n' % (self.GetDescription(), |
| 294 name)) | 298 name)) |
| 295 if stack is not None: | 299 if stack is not None: |
| 296 for entry in reversed(stack.entries): | 300 for entry in reversed(stack.entries): |
| 297 message.Append(' included as %s in %s\n' % (entry.id_.GetDescription(), | 301 message.Append(' included as %s in %s\n' % (entry.id_.GetDescription(), |
| 298 entry.name)) | 302 entry.name)) |
| 299 return message.ToString().strip() | 303 return message.ToString().strip() |
| (...skipping 733 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1033 line, column = tokens.next_line, (tokens.next_column + 1) | 1037 line, column = tokens.next_line, (tokens.next_column + 1) |
| 1034 name = tokens.AdvanceToNextWhitespace() | 1038 name = tokens.AdvanceToNextWhitespace() |
| 1035 clazz = _UnescapedVariableNode | 1039 clazz = _UnescapedVariableNode |
| 1036 if name.startswith('*'): | 1040 if name.startswith('*'): |
| 1037 clazz = _JsonNode | 1041 clazz = _JsonNode |
| 1038 elif name.startswith('+'): | 1042 elif name.startswith('+'): |
| 1039 clazz = _PartialNode.Inline | 1043 clazz = _PartialNode.Inline |
| 1040 if clazz is not _UnescapedVariableNode: | 1044 if clazz is not _UnescapedVariableNode: |
| 1041 name = name[1:] | 1045 name = name[1:] |
| 1042 column += 1 | 1046 column += 1 |
| 1043 inline_node = clazz(_Identifier(name, line, column)) | 1047 inline_node = clazz(_Identifier(name, line, column, title=self._name)) |
| 1044 if isinstance(inline_node, _PartialNode): | 1048 if isinstance(inline_node, _PartialNode): |
| 1045 inline_node.SetArguments(self._ParsePartialNodeArgs(tokens)) | 1049 inline_node.SetArguments(self._ParsePartialNodeArgs(tokens)) |
| 1046 if bind_to is not None: | 1050 if bind_to is not None: |
| 1047 inline_node.PassThroughArgument(bind_to) | 1051 inline_node.PassThroughArgument(bind_to) |
| 1048 tokens.SkipWhitespace() | 1052 tokens.SkipWhitespace() |
| 1049 tokens.AdvanceOver(_Token.INLINE_END_SECTION) | 1053 tokens.AdvanceOver(_Token.INLINE_END_SECTION) |
| 1050 return [next_token.clazz(bind_to, id_, inline_node)] | 1054 return [next_token.clazz(bind_to, id_, inline_node)] |
| 1051 # Block syntax. | 1055 # Block syntax. |
| 1052 tokens.AdvanceOver(_Token.CLOSE_MUSTACHE) | 1056 tokens.AdvanceOver(_Token.CLOSE_MUSTACHE) |
| 1053 section = self._ParseSection(tokens) | 1057 section = self._ParseSection(tokens) |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1115 args[key] = {inner_id: inner_args} | 1119 args[key] = {inner_id: inner_args} |
| 1116 else: | 1120 else: |
| 1117 args[key] = self._NextIdentifier(tokens) | 1121 args[key] = self._NextIdentifier(tokens) |
| 1118 return args or None | 1122 return args or None |
| 1119 | 1123 |
| 1120 def _NextIdentifier(self, tokens): | 1124 def _NextIdentifier(self, tokens): |
| 1121 tokens.SkipWhitespace() | 1125 tokens.SkipWhitespace() |
| 1122 column_start = tokens.next_column + 1 | 1126 column_start = tokens.next_column + 1 |
| 1123 id_ = _Identifier(tokens.AdvanceOverNextString(excluded=' \n\r\t:()'), | 1127 id_ = _Identifier(tokens.AdvanceOverNextString(excluded=' \n\r\t:()'), |
| 1124 tokens.next_line, | 1128 tokens.next_line, |
| 1125 column_start) | 1129 column_start, |
| 1130 title=self._name) |
| 1126 tokens.SkipWhitespace() | 1131 tokens.SkipWhitespace() |
| 1127 return id_ | 1132 return id_ |
| 1128 | 1133 |
| 1129 def Render(self, *user_contexts): | 1134 def Render(self, *user_contexts): |
| 1130 '''Renders this template given a variable number of contexts to read out | 1135 '''Renders this template given a variable number of contexts to read out |
| 1131 values from (such as those appearing in {{foo}}). | 1136 values from (such as those appearing in {{foo}}). |
| 1132 ''' | 1137 ''' |
| 1133 internal_context = _InternalContext() | 1138 internal_context = _InternalContext() |
| 1134 contexts = list(user_contexts) | 1139 contexts = list(user_contexts) |
| 1135 contexts.append({ | 1140 contexts.append({ |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1149 return self.source == other.source and self._name == other._name | 1154 return self.source == other.source and self._name == other._name |
| 1150 | 1155 |
| 1151 def __ne__(self, other): | 1156 def __ne__(self, other): |
| 1152 return not (self == other) | 1157 return not (self == other) |
| 1153 | 1158 |
| 1154 def __repr__(self): | 1159 def __repr__(self): |
| 1155 return str('%s(%s)' % (type(self).__name__, self._top_node)) | 1160 return str('%s(%s)' % (type(self).__name__, self._top_node)) |
| 1156 | 1161 |
| 1157 def __str__(self): | 1162 def __str__(self): |
| 1158 return repr(self) | 1163 return repr(self) |
| OLD | NEW |