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    /**
0024    A Context represents a state of the Mustache "context stack".
0025    
0026    The context stack grows and shrinks as the Mustache engine enters and leaves
0027    Mustache sections.
0028    
0029    The top of the context stack is called the "current context". It is the value
0030    rendered by the `{{.}}` tag:
0031    
0032        // Renders "Kitty, Pussy, Melba, "
0033        let template = try! Template(string: "{{#cats}}{{.}}, {{/cats}}")
0034        try! template.render(Box(["cats": ["Kitty", "Pussy", "Melba"]]))
0035    
0036    Key lookup starts with the current context and digs down the stack until if
0037    finds a value:
0038    
0039        // Renders "<child>, <parent>, "
0040        let template = try! Template(string: "{{#children}}<{{name}}>, {{/children}}")
0041        let data = [
0042          "name": "parent",
0043          "children": [
0044              ["name": "child"],
0045              [:]    // a child without a name
0046          ]
0047        ]
0048        try! template.render(Box(data))
0049    
0050    See also:
0051    
0052    - Configuration
0053    - TemplateRepository
0054    - RenderFunction
0055    */
0056    final public class Context
Configuration.swift:100
        baseContext = Context()
Configuration.swift:202
    public var baseContext: Context
Context.swift:75
        self.init(type: .Box(box: box, parent: Context()))
Context.swift:87
        self.init(type: .Root, registeredKeysContext: Context(Box(boxable: [key: box])))
Context.swift:102
    public func extendedContext(box: MustacheBox) -> Context {
Context.swift:103
        return Context(type: .Box(box: box, parent: self), registeredKeysContext: registeredKeysContext)
Context.swift:115
    public func contextWithRegisteredKey(key: String, box: MustacheBox) -> Context {
Context.swift:116
        let registeredKeysContext = (self.registeredKeysContext ?? Context()).extendedContext(Box(boxable: [key: box]))
Context.swift:117
        return Context(type: self.type, registeredKeysContext: registeredKeysContext)
Context.swift:215
        case Box(box: MustacheBox, parent: Context)
Context.swift:216
        case PartialOverride(partialOverride: TemplateASTNode.PartialOverride, parent: Context)
Context.swift:219
    private var registeredKeysContext: Context?
Context.swift:263
    private init(type: ContextType, registeredKeysContext: Context? = nil) {
Context.swift:268
    func extendedContext(partialOverride partialOverride: TemplateASTNode.PartialOverride) -> Context {
Context.swift:269
        return Context(type: .PartialOverride(partialOverride: partialOverride, parent: self), registeredKeysContext: registeredKeysContext)
Context.swift:273
extension Context: CustomDebugStringConvertible {
CoreFunctions.swift:753
    public var context: Context
ExpressionInvocation.swift:26
    func invokeWithContext(context: Context) throws -> MustacheBox {
ExpressionInvocation.swift:30
    private func evaluate(context context: Context, expression: Expression) throws -> MustacheBox {
RenderingEngine.swift:25
    init(templateAST: TemplateAST, context: Context) {
RenderingEngine.swift:41
    private let baseContext: Context
RenderingEngine.swift:44
    private func renderTemplateAST(templateAST: TemplateAST, inContext context: Context) throws {
RenderingEngine.swift:82
    private func renderNode(node: TemplateASTNode, inContext context: Context) throws {
RenderingEngine.swift:127
    private func renderTag(tag: LocatedTag, escapesHTML: Bool, inverted: Bool, expression: Expression, inContext context: Context) throws {
RenderingEngine.swift:209
    private func resolveBlock(block: TemplateASTNode.Block, inContext context: Context) -> TemplateASTNode.Block {
Template.swift:80
    public func render(context: Context) throws -> Rendering {
Template.swift:118
    public var baseContext: Context
Template.swift:207
    init(repository: TemplateRepository, templateAST: TemplateAST, baseContext: Context) {
SectionTag.swift:47
    func render(context: Context) throws -> Rendering {
Tag.swift:147
    func render(context: Context) throws -> Rendering
VariableTag.swift:46
    func render(context: Context) throws -> Rendering {
{ 0057 0058 // ========================================================================= 0059 // MARK: - Creating Contexts 0060 0061 /** 0062 Builds an empty Context. 0063 */ 0064 public convenience init
Configuration.swift:100
        baseContext = Context()
Context.swift:75
        self.init(type: .Box(box: box, parent: Context()))
Context.swift:116
        let registeredKeysContext = (self.registeredKeysContext ?? Context()).extendedContext(Box(boxable: [key: box]))
() { 0065 self.init(type: .Root) 0066 } 0067 0068 /** 0069 Builds a context that contains the provided box. 0070 0071 - parameter box: A box. 0072 - returns: A new context that contains *box*. 0073 */ 0074 public convenience init
Context.swift:87
        self.init(type: .Root, registeredKeysContext: Context(Box(boxable: [key: box])))
(_ box: MustacheBox) { 0075 self.init(type: .Box(box: box, parent: Context())) 0076 } 0077 0078 /** 0079 Builds a context with a registered key. Registered keys are looked up first 0080 when evaluating Mustache tags. 0081 0082 - parameter key: An identifier. 0083 - parameter box: A box. 0084 - returns: A new context with *box* registered for *key*. 0085 */ 0086 public convenience init(registeredKey key: String, box: MustacheBox) { 0087 self.init(type: .Root, registeredKeysContext: Context(Box(boxable: [key: box]))) 0088 } 0089 0090 0091 // ========================================================================= 0092 // MARK: - Deriving New Contexts 0093 0094 /** 0095 Returns a new context with the provided box pushed at the top of the context 0096 stack. 0097 0098 - parameter box: A box. 0099 - returns: A new context with *box* pushed at the top of the stack. 0100 */ 0101 @warn_unused_result(message="Context.extendedContext returns a new Context.") 0102 public func extendedContext
Configuration.swift:241
        baseContext = baseContext.extendedContext(box)
EachFilter.swift:55
                info.context = info.context.extendedContext(Box(boxable: position))
EachFilter.swift:87
                info.context = info.context.extendedContext(Box(boxable: position))
ZipFilter.swift:77
            var context = zippedBoxes.reduce(info.context) { (context, box) in context.extendedContext(box) }
Box.swift:186
                        return try info.tag.render(info.context.extendedContext(Box(boolValue: self)))
Box.swift:243
                        return try info.tag.render(info.context.extendedContext(Box(value: self)))
Box.swift:300
                        return try info.tag.render(info.context.extendedContext(Box(value: self)))
Box.swift:357
                        return try info.tag.render(info.context.extendedContext(Box(value: self)))
Box.swift:938
                    return try info.tag.render(info.context.extendedContext(self.mustacheBoxWithSetValue(value, box: box)))
Box.swift:994
                    return try info.tag.render(info.context.extendedContext(self.mustacheBoxWithArrayValue(value, box: box)))
Context.swift:116
        let registeredKeysContext = (self.registeredKeysContext ?? Context()).extendedContext(Box(boxable: [key: box]))
CoreFunctions.swift:688
            let context = info.context.extendedContext(Box(render: Lambda(lambda)))
MustacheBox.swift:491
                    let context = info.context.extendedContext(self)
Template.swift:58
        let rendering = try render(baseContext.extendedContext(box))
Template.swift:136
        baseContext = baseContext.extendedContext(box)
(box: MustacheBox) -> Context { 0103 return Context(type: .Box(box: box, parent: self), registeredKeysContext: registeredKeysContext) 0104 } 0105 0106 /** 0107 Returns a new context with the provided box at the top of the context stack. 0108 Registered keys are looked up first when evaluating Mustache tags. 0109 0110 - parameter key: An identifier. 0111 - parameter box: A box. 0112 - returns: A new context with *box* registered for *key*. 0113 */ 0114 @warn_unused_result(message="Context.contextWithRegisteredKey returns a new Context.") 0115 public func contextWithRegisteredKey
Configuration.swift:288
        baseContext = baseContext.contextWithRegisteredKey(key, box: box)
Template.swift:160
        baseContext = baseContext.contextWithRegisteredKey(key, box: box)
(key: String, box: MustacheBox) -> Context { 0116 let registeredKeysContext = (self.registeredKeysContext ?? Context()).extendedContext(Box(boxable: [key: box])) 0117 return Context(type: self.type, registeredKeysContext: registeredKeysContext) 0118 } 0119 0120 0121 // ========================================================================= 0122 // MARK: - Fetching Values from the Context Stack 0123 0124 /** 0125 Returns the top box of the context stack, the one that would be rendered by 0126 the `{{.}}` tag. 0127 */ 0128 public var topBox
Context.swift:135
            return parent.topBox
ExpressionInvocation.swift:35
            return context.topBox
: MustacheBox { 0129 switch type { 0130 case .Root: 0131 return Box() 0132 case .Box(box: let box, parent: _): 0133 return box 0134 case .PartialOverride(partialOverride: _, parent: let parent): 0135 return parent.topBox 0136 } 0137 } 0138 0139 /** 0140 Returns the boxed value stored in the context stack for the given key. 0141 0142 The following search pattern is used: 0143 0144 1. If the key is "registered", returns the registered box for that key. 0145 0146 2. Otherwise, searches the context stack for a box that has a non-empty 0147 box for the key (see `InspectFunction`). 0148 0149 3. If none of the above situations occurs, returns the empty box. 0150 0151 let data = ["name": "Groucho Marx"] 0152 let context = Context(Box(data)) 0153 0154 // "Groucho Marx" 0155 context.mustacheBoxForKey("name").value 0156 0157 If you want the value for a full Mustache expression such as `user.name` or 0158 `uppercase(user.name)`, use the `mustacheBoxForExpression` method. 0159 0160 - parameter key: A key. 0161 - returns: The MustacheBox for *key*. 0162 */ 0163 public func mustacheBoxForKey
Context.swift:165
            let box = registeredKeysContext.mustacheBoxForKey(key)
Context.swift:177
                return parent.mustacheBoxForKey(key)
Context.swift:182
            return parent.mustacheBoxForKey(key)
ExpressionInvocation.swift:40
            return context.mustacheBoxForKey(identifier)
(key: String) -> MustacheBox { 0164 if let registeredKeysContext = registeredKeysContext { 0165 let box = registeredKeysContext.mustacheBoxForKey(key) 0166 if !box.isEmpty { 0167 return box 0168 } 0169 } 0170 0171 switch type { 0172 case .Root: 0173 return Box() 0174 case .Box(box: let box, parent: let parent): 0175 let innerBox = box.mustacheBoxForKey(key) 0176 if innerBox.isEmpty { 0177 return parent.mustacheBoxForKey(key) 0178 } else { 0179 return innerBox 0180 } 0181 case .PartialOverride(partialOverride: _, parent: let parent): 0182 return parent.mustacheBoxForKey(key) 0183 } 0184 } 0185 0186 /** 0187 Evaluates a Mustache expression such as `name`, or `uppercase(user.name)`. 0188 0189 let data = ["person": ["name": "Albert Einstein"]] 0190 let context = Context(Box(data)) 0191 0192 // "Albert Einstein" 0193 try! context.mustacheBoxForExpression("person.name").value 0194 0195 - parameter string: The expression string. 0196 - parameter error: If there is a problem parsing or evaluating the 0197 expression, throws an error that describes the problem. 0198 0199 - returns: The value of the expression. 0200 */ 0201 public func mustacheBoxForExpression(string: String) throws -> MustacheBox { 0202 let parser = ExpressionParser() 0203 var empty = false 0204 let expression = try parser.parse(string, empty: &empty) 0205 let invocation = ExpressionInvocation(expression: expression) 0206 return try invocation.invokeWithContext(self) 0207 } 0208 0209 0210 // ========================================================================= 0211 // MARK: - Not public 0212 0213 private enum ContextType
Context.swift:220
    private let type: ContextType
Context.swift:263
    private init(type: ContextType, registeredKeysContext: Context? = nil) {
{ 0214 case Root
Context.swift:65
        self.init(type: .Root)
Context.swift:87
        self.init(type: .Root, registeredKeysContext: Context(Box(boxable: [key: box])))
Context.swift:130
        case .Root:
Context.swift:172
        case .Root:
Context.swift:224
        case .Root:
Context.swift:239
        case .Root:
Context.swift:254
        case .Root:
Context.swift:277
        case .Root:
0215 case Box
Context.swift:75
        self.init(type: .Box(box: box, parent: Context()))
Context.swift:103
        return Context(type: .Box(box: box, parent: self), registeredKeysContext: registeredKeysContext)
Context.swift:132
        case .Box(box: let box, parent: _):
Context.swift:174
        case .Box(box: let box, parent: let parent):
Context.swift:226
        case .Box(box: let box, parent: let parent):
Context.swift:241
        case .Box(box: let box, parent: let parent):
Context.swift:256
        case .Box(box: _, parent: let parent):
Context.swift:279
        case .Box(box: let box, parent: let parent):
(box: MustacheBox, parent: Context) 0216 case PartialOverride
Context.swift:134
        case .PartialOverride(partialOverride: _, parent: let parent):
Context.swift:181
        case .PartialOverride(partialOverride: _, parent: let parent):
Context.swift:232
        case .PartialOverride(partialOverride: _, parent: let parent):
Context.swift:247
        case .PartialOverride(partialOverride: _, parent: let parent):
Context.swift:258
        case .PartialOverride(partialOverride: let partialOverride, parent: let parent):
Context.swift:269
        return Context(type: .PartialOverride(partialOverride: partialOverride, parent: self), registeredKeysContext: registeredKeysContext)
Context.swift:281
        case .PartialOverride(partialOverride: _, parent: let parent):
(partialOverride: TemplateASTNode.PartialOverride, parent: Context) 0217 } 0218 0219 private var registeredKeysContext
Context.swift:103
        return Context(type: .Box(box: box, parent: self), registeredKeysContext: registeredKeysContext)
Context.swift:116
        let registeredKeysContext = (self.registeredKeysContext ?? Context()).extendedContext(Box(boxable: [key: box]))
Context.swift:164
        if let registeredKeysContext = registeredKeysContext {
Context.swift:265
        self.registeredKeysContext = registeredKeysContext
Context.swift:269
        return Context(type: .PartialOverride(partialOverride: partialOverride, parent: self), registeredKeysContext: registeredKeysContext)
: Context? 0220 private let type
Context.swift:117
        return Context(type: self.type, registeredKeysContext: registeredKeysContext)
Context.swift:129
        switch type {
Context.swift:171
        switch type {
Context.swift:223
        switch type {
Context.swift:238
        switch type {
Context.swift:253
        switch type {
Context.swift:264
        self.type = type
Context.swift:276
        switch type {
: ContextType 0221 0222 var willRenderStack
Context.swift:228
                return [willRender] + parent.willRenderStack
Context.swift:230
                return parent.willRenderStack
Context.swift:233
            return parent.willRenderStack
RenderingEngine.swift:150
        for willRender in context.willRenderStack {
: [WillRenderFunction] { 0223 switch type { 0224 case .Root: 0225 return [] 0226 case .Box(box: let box, parent: let parent): 0227 if let willRender = box.willRender { 0228 return [willRender] + parent.willRenderStack 0229 } else { 0230 return parent.willRenderStack 0231 } 0232 case .PartialOverride(partialOverride: _, parent: let parent): 0233 return parent.willRenderStack 0234 } 0235 } 0236 0237 var didRenderStack
Context.swift:243
                return parent.didRenderStack + [didRender]
Context.swift:245
                return parent.didRenderStack
Context.swift:248
            return parent.didRenderStack
RenderingEngine.swift:180
            for didRender in context.didRenderStack {
RenderingEngine.swift:201
        for didRender in context.didRenderStack {
: [DidRenderFunction] { 0238 switch type { 0239 case .Root: 0240 return [] 0241 case .Box(box: let box, parent: let parent): 0242 if let didRender = box.didRender { 0243 return parent.didRenderStack + [didRender] 0244 } else { 0245 return parent.didRenderStack 0246 } 0247 case .PartialOverride(partialOverride: _, parent: let parent): 0248 return parent.didRenderStack 0249 } 0250 } 0251 0252 var partialOverrideStack
Context.swift:257
            return parent.partialOverrideStack
Context.swift:259
            return [partialOverride] + parent.partialOverrideStack
RenderingEngine.swift:217
        return context.partialOverrideStack.reduce(block) { (block, partialOverride) in
: [TemplateASTNode.PartialOverride] { 0253 switch type { 0254 case .Root: 0255 return [] 0256 case .Box(box: _, parent: let parent): 0257 return parent.partialOverrideStack 0258 case .PartialOverride(partialOverride: let partialOverride, parent: let parent): 0259 return [partialOverride] + parent.partialOverrideStack 0260 } 0261 } 0262 0263 private init
Context.swift:65
        self.init(type: .Root)
Context.swift:75
        self.init(type: .Box(box: box, parent: Context()))
Context.swift:87
        self.init(type: .Root, registeredKeysContext: Context(Box(boxable: [key: box])))
Context.swift:103
        return Context(type: .Box(box: box, parent: self), registeredKeysContext: registeredKeysContext)
Context.swift:117
        return Context(type: self.type, registeredKeysContext: registeredKeysContext)
Context.swift:269
        return Context(type: .PartialOverride(partialOverride: partialOverride, parent: self), registeredKeysContext: registeredKeysContext)
(type: ContextType, registeredKeysContext: Context? = nil) { 0264 self.type = type 0265 self.registeredKeysContext = registeredKeysContext 0266 } 0267 0268 func extendedContext
RenderingEngine.swift:95
            let context = context.extendedContext(partialOverride: partialOverride)
(partialOverride partialOverride: TemplateASTNode.PartialOverride) -> Context { 0269 return Context(type: .PartialOverride(partialOverride: partialOverride, parent: self), registeredKeysContext: registeredKeysContext) 0270 } 0271 } 0272 0273 extension Context: CustomDebugStringConvertible { 0274 /// A textual representation of `self`, suitable for debugging. 0275 public var debugDescription
Context.swift:280
            return "Context.Box(\(box)):\(parent.debugDescription)"
Context.swift:282
            return "Context.PartialOverride:\(parent.debugDescription)"
: String { 0276 switch type { 0277 case .Root: 0278 return "Context.Root" 0279 case .Box(box: let box, parent: let parent): 0280 return "Context.Box(\(box)):\(parent.debugDescription)" 0281 case .PartialOverride(partialOverride: _, parent: let parent): 0282 return "Context.PartialOverride:\(parent.debugDescription)" 0283 } 0284 } 0285 }