From d6766b43da8c32f6c5cbfc14b8d3cb2a15f00276 Mon Sep 17 00:00:00 2001 From: Ilya Puchka Date: Wed, 27 Dec 2017 19:29:17 +0100 Subject: [PATCH] minor code refactoring --- Sources/Errors.swift | 11 +++++ Sources/ForTag.swift | 9 ++--- Sources/Inheritence.swift | 84 +++++++++++++++++++-------------------- Sources/Node.swift | 7 +--- Sources/Parser.swift | 7 +--- 5 files changed, 58 insertions(+), 60 deletions(-) diff --git a/Sources/Errors.swift b/Sources/Errors.swift index 4c01dfe..407a9e2 100644 --- a/Sources/Errors.swift +++ b/Sources/Errors.swift @@ -44,6 +44,17 @@ public struct TemplateSyntaxError : Error, Equatable, CustomStringConvertible { } +extension Error { + func withToken(_ token: Token?) -> Error { + if var error = self as? TemplateSyntaxError { + error.token = error.token ?? token + return error + } else { + return TemplateSyntaxError(reason: "\(self)", token: token) + } + } +} + public protocol ErrorReporter: class { func renderError(_ error: Error) -> String } diff --git a/Sources/ForTag.swift b/Sources/ForTag.swift index 6685d0b..1b6b1d2 100644 --- a/Sources/ForTag.swift +++ b/Sources/ForTag.swift @@ -24,10 +24,6 @@ class ForNode : NodeType { let variable = components[3] let filter = try parser.compileFilter(variable, containedIn: token) - var emptyNodes = [NodeType]() - - let forNodes = try parser.parse(until(["endfor", "empty"])) - let `where`: Expression? if components.count >= 6 { `where` = try parseExpression(components: Array(components.suffix(from: 5)), tokenParser: parser, token: token) @@ -35,10 +31,13 @@ class ForNode : NodeType { `where` = nil } + let forNodes = try parser.parse(until(["endfor", "empty"])) + guard let token = parser.nextToken() else { throw TemplateSyntaxError("`endfor` was not found.") } + var emptyNodes = [NodeType]() if token.contents == "empty" { emptyNodes = try parser.parse(until(["endfor"])) _ = parser.nextToken() @@ -90,7 +89,7 @@ class ForNode : NodeType { var values: [Any] if let dictionary = resolved as? [String: Any], !dictionary.isEmpty { - values = dictionary.map { ($0.key, $0.value) } as [(String, Any)] + values = dictionary.map { ($0.key, $0.value) } } else if let array = resolved as? [Any] { values = array } else if let range = resolved as? CountableClosedRange { diff --git a/Sources/Inheritence.swift b/Sources/Inheritence.swift index 9d70e72..db2d67f 100644 --- a/Sources/Inheritence.swift +++ b/Sources/Inheritence.swift @@ -4,11 +4,12 @@ class BlockContext { // contains mapping of block names to their nodes and templates where they are defined var blocks: [String: [BlockNode]] - init(blocks: [String: [BlockNode]]) { - self.blocks = blocks + init(blocks: [String: BlockNode]) { + self.blocks = [:] + blocks.forEach { self.blocks[$0.key] = [$0.value] } } - func pushBlock(_ block: BlockNode, named blockName: String) { + func push(_ block: BlockNode, forKey blockName: String) { if var blocks = blocks[blockName] { blocks.append(block) self.blocks[blockName] = blocks @@ -17,7 +18,7 @@ class BlockContext { } } - func popBlock(named blockName: String) -> BlockNode? { + func pop(_ blockName: String) -> BlockNode? { if var blocks = blocks[blockName] { let block = blocks.removeFirst() if blocks.isEmpty { @@ -88,14 +89,12 @@ class ExtendsNode : NodeType { let baseTemplate = try context.environment.loadTemplate(name: templateName) let blockContext: BlockContext - if let _blockContext = context[BlockContext.contextKey] as? BlockContext { - blockContext = _blockContext + if let currentBlockContext = context[BlockContext.contextKey] as? BlockContext { + blockContext = currentBlockContext for (name, block) in blocks { - blockContext.pushBlock(block, named: name) + blockContext.push(block, forKey: name) } } else { - var blocks = [String: [BlockNode]]() - self.blocks.forEach { blocks[$0.key] = [$0.value] } blockContext = BlockContext(blocks: blocks) } @@ -144,48 +143,47 @@ class BlockNode : NodeType { } func render(_ context: Context) throws -> String { - if let blockContext = context[BlockContext.contextKey] as? BlockContext, let child = blockContext.popBlock(named: name) { - // child node is a block node from child template that extends this node (has the same name) - - var newContext: [String: Any] = [BlockContext.contextKey: blockContext] - - if let blockSuperNode = child.nodes.first(where: { - if case .variable(let variable, _)? = $0.token, variable == "block.super" { return true } - else { return false} - }) { - do { - // render current (base) node so that its content can be used as part of node that extends it - newContext["block"] = ["super": try self.render(context)] - } catch { - if let error = error as? TemplateSyntaxError { - throw TemplateSyntaxError( - reason: error.reason, - token: blockSuperNode.token, - stackTrace: error.allTokens) - } else { - throw TemplateSyntaxError( - reason: "\(error)", - token: blockSuperNode.token, - stackTrace: []) - } - } - } - + if let blockContext = context[BlockContext.contextKey] as? BlockContext, let child = blockContext.pop(name) { + let childContext = try self.childContext(child, blockContext: blockContext, context: context) // render extension node do { - return try context.push(dictionary: newContext) { + return try context.push(dictionary: childContext) { return try child.render(context) } } catch { - if var error = error as? TemplateSyntaxError { - error.token = error.token ?? child.token - throw error - } else { - throw error - } + throw error.withToken(child.token) } } return try renderNodes(nodes, context) } + + // child node is a block node from child template that extends this node (has the same name) + func childContext(_ child: BlockNode, blockContext: BlockContext, context: Context) throws -> [String: Any?] { + var childContext: [String: Any?] = [BlockContext.contextKey: blockContext] + + if let blockSuperNode = child.nodes.first(where: { + if case .variable(let variable, _)? = $0.token, variable == "block.super" { return true } + else { return false} + }) { + do { + // render base node so that its content can be used as part of child node that extends it + childContext["block"] = ["super": try self.render(context)] + } catch { + if let error = error as? TemplateSyntaxError { + throw TemplateSyntaxError( + reason: error.reason, + token: blockSuperNode.token, + stackTrace: error.allTokens) + } else { + throw TemplateSyntaxError( + reason: "\(error)", + token: blockSuperNode.token, + stackTrace: []) + } + } + } + return childContext + } + } diff --git a/Sources/Node.swift b/Sources/Node.swift index 1e8195f..84a114f 100644 --- a/Sources/Node.swift +++ b/Sources/Node.swift @@ -15,12 +15,7 @@ public func renderNodes(_ nodes:[NodeType], _ context:Context) throws -> String do { return try $0.render(context) } catch { - if var error = error as? TemplateSyntaxError { - error.token = error.token ?? $0.token - throw error - } else { - throw error - } + throw error.withToken($0.token) } }).joined(separator: "") } diff --git a/Sources/Parser.swift b/Sources/Parser.swift index 09c5e18..4a0b2c6 100644 --- a/Sources/Parser.swift +++ b/Sources/Parser.swift @@ -54,12 +54,7 @@ public class TokenParser { let node = try parser(self, token) nodes.append(node) } catch { - if var error = error as? TemplateSyntaxError { - error.token = error.token ?? token - throw error - } else { - throw error - } + throw error.withToken(token) } } case .comment: