0001 // The MIT License 0002 // 0003 // Copyright (c) 2015 Gwendal Roué 0004 // 0005 // Permission is hereby granted, free of charge, to any person obtaining a copy 0006 // of this software and associated documentation files (the "Software"), to deal 0007 // in the Software without restriction, including without limitation the rights 0008 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 0009 // copies of the Software, and to permit persons to whom the Software is 0010 // furnished to do so, subject to the following conditions: 0011 // 0012 // The above copyright notice and this permission notice shall be included in 0013 // all copies or substantial portions of the Software. 0014 // 0015 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0016 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 0017 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 0018 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 0019 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 0020 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 0021 // THE SOFTWARE. 0022 0023 final class ExpressionParser{ 0024 0025 func parse
TemplateCompiler.swift:121 let expression = try ExpressionParser().parse(content, empty: &empty)TemplateCompiler.swift:138 let expression = try ExpressionParser().parse(content, empty: &empty)TemplateCompiler.swift:155 let expression = try ExpressionParser().parse(content, empty: &empty)TemplateCompiler.swift:172 let expression = try ExpressionParser().parse(content, empty: &empty)TemplateCompiler.swift:203 expression = try ExpressionParser().parse(content, empty: &empty)TemplateCompiler.swift:233 expression = try ExpressionParser().parse(content, empty: &empty)Context.swift:202 let parser = ExpressionParser()(string: String, inout empty outEmpty: Bool) throws -> Expression { 0026 enum State { 0027 // error 0028 case Error(String) 0029 0030 // Any expression can start 0031 case WaitingForAnyExpression 0032 0033 // Expression has started with a dot 0034 case LeadingDot 0035 0036 // Expression has started with an identifier 0037 case Identifier(identifierStart: String.Index) 0038 0039 // Parsing a scoping identifier 0040 case ScopingIdentifier(identifierStart: String.Index, baseExpression: Expression) 0041 0042 // Waiting for a scoping identifier 0043 case WaitingForScopingIdentifier(baseExpression: Expression) 0044 0045 // Parsed an expression 0046 case DoneExpression(expression: Expression) 0047 0048 // Parsed white space after an expression 0049 case DoneExpressionPlusWhiteSpace(expression: Expression) 0050 } 0051 0052 var state: State = .WaitingForAnyExpression 0053 var filterExpressionStack: [Expression] = [] 0054 0055 var i = string.startIndex 0056 let end = string.endIndex 0057 stringLoop: while i < end { 0058 let c = string[i] 0059 0060 switch state { 0061 case .Error: 0062 break stringLoop 0063 0064 case .WaitingForAnyExpression: 0065 switch c { 0066 case " ", "\r", "\n", "\r\n", "\t": 0067 break 0068 case ".": 0069 state = .LeadingDot 0070 case "(", ")", ",", "{", "}", "&", "$", "#", "^", "/", "<", ">": 0071 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0072 default: 0073 state = .Identifier(identifierStart: i) 0074 } 0075 0076 case .LeadingDot: 0077 switch c { 0078 case " ", "\r", "\n", "\r\n", "\t": 0079 state = .DoneExpressionPlusWhiteSpace(expression: Expression.ImplicitIterator) 0080 case ".": 0081 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0082 case "(": 0083 filterExpressionStack.append(Expression.ImplicitIterator) 0084 state = .WaitingForAnyExpression 0085 case ")": 0086 if let filterExpression = filterExpressionStack.last { 0087 filterExpressionStack.removeLast() 0088 let expression = Expression.Filter(filterExpression: filterExpression, argumentExpression: Expression.ImplicitIterator, partialApplication: false) 0089 state = .DoneExpression(expression: expression) 0090 } else { 0091 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0092 } 0093 case ",": 0094 if let filterExpression = filterExpressionStack.last { 0095 filterExpressionStack.removeLast() 0096 filterExpressionStack.append(Expression.Filter(filterExpression: filterExpression, argumentExpression: Expression.ImplicitIterator, partialApplication: true)) 0097 state = .WaitingForAnyExpression 0098 } else { 0099 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0100 } 0101 case "{", "}", "&", "$", "#", "^", "/", "<", ">": 0102 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0103 default: 0104 state = .ScopingIdentifier(identifierStart: i, baseExpression: Expression.ImplicitIterator) 0105 } 0106 0107 case .Identifier(identifierStart: let identifierStart): 0108 switch c { 0109 case " ", "\r", "\n", "\r\n", "\t": 0110 let identifier = string.substringWithRange(identifierStart..<i) 0111 state = .DoneExpressionPlusWhiteSpace(expression: Expression.Identifier(identifier: identifier)) 0112 case ".": 0113 let identifier = string.substringWithRange(identifierStart..<i) 0114 state = .WaitingForScopingIdentifier(baseExpression: Expression.Identifier(identifier: identifier)) 0115 case "(": 0116 let identifier = string.substringWithRange(identifierStart..<i) 0117 filterExpressionStack.append(Expression.Identifier(identifier: identifier)) 0118 state = .WaitingForAnyExpression 0119 case ")": 0120 if let filterExpression = filterExpressionStack.last { 0121 filterExpressionStack.removeLast() 0122 let identifier = string.substringWithRange(identifierStart..<i) 0123 let expression = Expression.Filter(filterExpression: filterExpression, argumentExpression: Expression.Identifier(identifier: identifier), partialApplication: false) 0124 state = .DoneExpression(expression: expression) 0125 } else { 0126 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0127 } 0128 case ",": 0129 if let filterExpression = filterExpressionStack.last { 0130 filterExpressionStack.removeLast() 0131 let identifier = string.substringWithRange(identifierStart..<i) 0132 filterExpressionStack.append(Expression.Filter(filterExpression: filterExpression, argumentExpression: Expression.Identifier(identifier: identifier), partialApplication: true)) 0133 state = .WaitingForAnyExpression 0134 } else { 0135 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0136 } 0137 default: 0138 break 0139 } 0140 0141 case .ScopingIdentifier(identifierStart: let identifierStart, baseExpression: let baseExpression): 0142 switch c { 0143 case " ", "\r", "\n", "\r\n", "\t": 0144 let identifier = string.substringWithRange(identifierStart..<i) 0145 let scopedExpression = Expression.Scoped(baseExpression: baseExpression, identifier: identifier) 0146 state = .DoneExpressionPlusWhiteSpace(expression: scopedExpression) 0147 case ".": 0148 let identifier = string.substringWithRange(identifierStart..<i) 0149 let scopedExpression = Expression.Scoped(baseExpression: baseExpression, identifier: identifier) 0150 state = .WaitingForScopingIdentifier(baseExpression: scopedExpression) 0151 case "(": 0152 let identifier = string.substringWithRange(identifierStart..<i) 0153 let scopedExpression = Expression.Scoped(baseExpression: baseExpression, identifier: identifier) 0154 filterExpressionStack.append(scopedExpression) 0155 state = .WaitingForAnyExpression 0156 case ")": 0157 if let filterExpression = filterExpressionStack.last { 0158 filterExpressionStack.removeLast() 0159 let identifier = string.substringWithRange(identifierStart..<i) 0160 let scopedExpression = Expression.Scoped(baseExpression: baseExpression, identifier: identifier) 0161 let expression = Expression.Filter(filterExpression: filterExpression, argumentExpression: scopedExpression, partialApplication: false) 0162 state = .DoneExpression(expression: expression) 0163 } else { 0164 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0165 } 0166 case ",": 0167 if let filterExpression = filterExpressionStack.last { 0168 filterExpressionStack.removeLast() 0169 let identifier = string.substringWithRange(identifierStart..<i) 0170 let scopedExpression = Expression.Scoped(baseExpression: baseExpression, identifier: identifier) 0171 filterExpressionStack.append(Expression.Filter(filterExpression: filterExpression, argumentExpression: scopedExpression, partialApplication: true)) 0172 state = .WaitingForAnyExpression 0173 } else { 0174 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0175 } 0176 default: 0177 break 0178 } 0179 0180 case .WaitingForScopingIdentifier(let baseExpression): 0181 switch c { 0182 case " ", "\r", "\n", "\r\n", "\t": 0183 state = .Error("Unexpected white space character at index \(string.startIndex.distanceTo(i))") 0184 case ".": 0185 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0186 case "(": 0187 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0188 case ")": 0189 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0190 case ",": 0191 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0192 case "{", "}", "&", "$", "#", "^", "/", "<", ">": 0193 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0194 default: 0195 state = .ScopingIdentifier(identifierStart: i, baseExpression: baseExpression) 0196 } 0197 0198 case .DoneExpression(let doneExpression): 0199 switch c { 0200 case " ", "\r", "\n", "\r\n", "\t": 0201 state = .DoneExpressionPlusWhiteSpace(expression: doneExpression) 0202 case ".": 0203 state = .WaitingForScopingIdentifier(baseExpression: doneExpression) 0204 case "(": 0205 filterExpressionStack.append(doneExpression) 0206 state = .WaitingForAnyExpression 0207 case ")": 0208 if let filterExpression = filterExpressionStack.last { 0209 filterExpressionStack.removeLast() 0210 let expression = Expression.Filter(filterExpression: filterExpression, argumentExpression: doneExpression, partialApplication: false) 0211 state = .DoneExpression(expression: expression) 0212 } else { 0213 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0214 } 0215 case ",": 0216 if let filterExpression = filterExpressionStack.last { 0217 filterExpressionStack.removeLast() 0218 filterExpressionStack.append(Expression.Filter(filterExpression: filterExpression, argumentExpression: doneExpression, partialApplication: true)) 0219 state = .WaitingForAnyExpression 0220 } else { 0221 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0222 } 0223 default: 0224 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0225 } 0226 0227 case .DoneExpressionPlusWhiteSpace(let doneExpression): 0228 switch c { 0229 case " ", "\r", "\n", "\r\n", "\t": 0230 break 0231 case ".": 0232 // Prevent "a .b" 0233 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0234 case "(": 0235 // Accept "a (b)" 0236 filterExpressionStack.append(doneExpression) 0237 state = .WaitingForAnyExpression 0238 case ")": 0239 // Accept "a(b )" 0240 if let filterExpression = filterExpressionStack.last { 0241 filterExpressionStack.removeLast() 0242 let expression = Expression.Filter(filterExpression: filterExpression, argumentExpression: doneExpression, partialApplication: false) 0243 state = .DoneExpression(expression: expression) 0244 } else { 0245 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0246 } 0247 case ",": 0248 // Accept "a(b ,c)" 0249 if let filterExpression = filterExpressionStack.last { 0250 filterExpressionStack.removeLast() 0251 filterExpressionStack.append(Expression.Filter(filterExpression: filterExpression, argumentExpression: doneExpression, partialApplication: true)) 0252 state = .WaitingForAnyExpression 0253 } else { 0254 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0255 } 0256 default: 0257 state = .Error("Unexpected character `\(c)` at index \(string.startIndex.distanceTo(i))") 0258 } 0259 } 0260 0261 i = i.successor() 0262 } 0263 0264 0265 // Parsing done 0266 0267 enum FinalState { 0268 case Error(String) 0269 case Empty 0270 case Valid(expression: Expression) 0271 } 0272 0273 let finalState: FinalState 0274 0275 switch state { 0276 case .WaitingForAnyExpression: 0277 if filterExpressionStack.isEmpty { 0278 finalState = .Empty 0279 } else { 0280 finalState = .Error("Missing `)` character at index \(string.startIndex.distanceTo(string.endIndex))") 0281 } 0282 0283 case .LeadingDot: 0284 if filterExpressionStack.isEmpty { 0285 finalState = .Valid(expression: Expression.ImplicitIterator) 0286 } else { 0287 finalState = .Error("Missing `)` character at index \(string.startIndex.distanceTo(string.endIndex))") 0288 } 0289 0290 case .Identifier(identifierStart: let identifierStart): 0291 if filterExpressionStack.isEmpty { 0292 let identifier = string.substringFromIndex(identifierStart) 0293 finalState = .Valid(expression: Expression.Identifier(identifier: identifier)) 0294 } else { 0295 finalState = .Error("Missing `)` character at index \(string.startIndex.distanceTo(string.endIndex))") 0296 } 0297 0298 case .ScopingIdentifier(identifierStart: let identifierStart, baseExpression: let baseExpression): 0299 if filterExpressionStack.isEmpty { 0300 let identifier = string.substringFromIndex(identifierStart) 0301 let scopedExpression = Expression.Scoped(baseExpression: baseExpression, identifier: identifier) 0302 finalState = .Valid(expression: scopedExpression) 0303 } else { 0304 finalState = .Error("Missing `)` character at index \(string.startIndex.distanceTo(string.endIndex))") 0305 } 0306 0307 case .WaitingForScopingIdentifier: 0308 finalState = .Error("Missing identifier at index \(string.startIndex.distanceTo(string.endIndex))") 0309 0310 case .DoneExpression(let doneExpression): 0311 if filterExpressionStack.isEmpty { 0312 finalState = .Valid(expression: doneExpression) 0313 } else { 0314 finalState = .Error("Missing `)` character at index \(string.startIndex.distanceTo(string.endIndex))") 0315 } 0316 0317 case .DoneExpressionPlusWhiteSpace(let doneExpression): 0318 if filterExpressionStack.isEmpty { 0319 finalState = .Valid(expression: doneExpression) 0320 } else { 0321 finalState = .Error("Missing `)` character at index \(string.startIndex.distanceTo(string.endIndex))") 0322 } 0323 0324 case .Error(let message): 0325 finalState = .Error(message) 0326 } 0327 0328 0329 // End 0330 0331 switch finalState { 0332 case .Empty: 0333 outEmpty = true 0334 throw MustacheError(kind: .ParseError, message: "Missing expression") 0335 0336 case .Error(let description): 0337 outEmpty = false 0338 throw MustacheError(kind: .ParseError, message: "Invalid expression `\(string)`: \(description)") 0339 0340 case .Valid(expression: let expression): 0341 return expression 0342 } 0343 } 0344 } 0345 0346 extension String { 0347 func substringWithRange
TemplateCompiler.swift:121 let expression = try ExpressionParser().parse(content, empty: &empty)TemplateCompiler.swift:138 let expression = try ExpressionParser().parse(content, empty: &empty)TemplateCompiler.swift:155 let expression = try ExpressionParser().parse(content, empty: &empty)TemplateCompiler.swift:172 let expression = try ExpressionParser().parse(content, empty: &empty)TemplateCompiler.swift:203 expression = try ExpressionParser().parse(content, empty: &empty)TemplateCompiler.swift:233 expression = try ExpressionParser().parse(content, empty: &empty)Context.swift:204 let expression = try parser.parse(string, empty: &empty)(range: Range<Index>) -> String { 0348 return self[range] 0349 } 0350 0351 func substringFromIndex
ExpressionParser.swift:110 let identifier = string.substringWithRange(identifierStart..<i)ExpressionParser.swift:113 let identifier = string.substringWithRange(identifierStart..<i)ExpressionParser.swift:116 let identifier = string.substringWithRange(identifierStart..<i)ExpressionParser.swift:122 let identifier = string.substringWithRange(identifierStart..<i)ExpressionParser.swift:131 let identifier = string.substringWithRange(identifierStart..<i)ExpressionParser.swift:144 let identifier = string.substringWithRange(identifierStart..<i)ExpressionParser.swift:148 let identifier = string.substringWithRange(identifierStart..<i)ExpressionParser.swift:152 let identifier = string.substringWithRange(identifierStart..<i)ExpressionParser.swift:159 let identifier = string.substringWithRange(identifierStart..<i)ExpressionParser.swift:169 let identifier = string.substringWithRange(identifierStart..<i)TemplateParser.swift:156 let content = templateString.substringWithRange(tagInitialIndex.successor()..<i)TemplateParser.swift:167 let content = templateString.substringWithRange(tagInitialIndex.successor()..<i)TemplateParser.swift:178 let content = templateString.substringWithRange(tagInitialIndex.successor()..<i)TemplateParser.swift:189 let content = templateString.substringWithRange(tagInitialIndex.successor()..<i)TemplateParser.swift:200 let content = templateString.substringWithRange(tagInitialIndex.successor()..<i)TemplateParser.swift:211 let content = templateString.substringWithRange(tagInitialIndex.successor()..<i)TemplateParser.swift:222 let content = templateString.substringWithRange(tagInitialIndex.successor()..<i)TemplateParser.swift:233 let content = templateString.substringWithRange(tagInitialIndex.successor()..<i)TemplateParser.swift:244 let content = templateString.substringWithRange(tagInitialIndex..<i)TemplateParser.swift:264 let content = templateString.substringWithRange(tagInitialIndex..<i)TemplateParser.swift:282 let content = templateString.substringWithRange(tagInitialIndex..<i)(index: Index) -> String { 0352 return self[index ..< endIndex] 0353 } 0354 }
ExpressionParser.swift:292 let identifier = string.substringFromIndex(identifierStart)ExpressionParser.swift:300 let identifier = string.substringFromIndex(identifierStart)TemplateParser.swift:59 let subs = templateString.substringFromIndex(index)