minor code refactoring

This commit is contained in:
Ilya Puchka
2017-12-27 19:29:17 +01:00
parent 662849e968
commit d6766b43da
5 changed files with 58 additions and 60 deletions

View File

@@ -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 { public protocol ErrorReporter: class {
func renderError(_ error: Error) -> String func renderError(_ error: Error) -> String
} }

View File

@@ -24,10 +24,6 @@ class ForNode : NodeType {
let variable = components[3] let variable = components[3]
let filter = try parser.compileFilter(variable, containedIn: token) let filter = try parser.compileFilter(variable, containedIn: token)
var emptyNodes = [NodeType]()
let forNodes = try parser.parse(until(["endfor", "empty"]))
let `where`: Expression? let `where`: Expression?
if components.count >= 6 { if components.count >= 6 {
`where` = try parseExpression(components: Array(components.suffix(from: 5)), tokenParser: parser, token: token) `where` = try parseExpression(components: Array(components.suffix(from: 5)), tokenParser: parser, token: token)
@@ -35,10 +31,13 @@ class ForNode : NodeType {
`where` = nil `where` = nil
} }
let forNodes = try parser.parse(until(["endfor", "empty"]))
guard let token = parser.nextToken() else { guard let token = parser.nextToken() else {
throw TemplateSyntaxError("`endfor` was not found.") throw TemplateSyntaxError("`endfor` was not found.")
} }
var emptyNodes = [NodeType]()
if token.contents == "empty" { if token.contents == "empty" {
emptyNodes = try parser.parse(until(["endfor"])) emptyNodes = try parser.parse(until(["endfor"]))
_ = parser.nextToken() _ = parser.nextToken()
@@ -90,7 +89,7 @@ class ForNode : NodeType {
var values: [Any] var values: [Any]
if let dictionary = resolved as? [String: Any], !dictionary.isEmpty { 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] { } else if let array = resolved as? [Any] {
values = array values = array
} else if let range = resolved as? CountableClosedRange<Int> { } else if let range = resolved as? CountableClosedRange<Int> {

View File

@@ -4,11 +4,12 @@ class BlockContext {
// contains mapping of block names to their nodes and templates where they are defined // contains mapping of block names to their nodes and templates where they are defined
var blocks: [String: [BlockNode]] var blocks: [String: [BlockNode]]
init(blocks: [String: [BlockNode]]) { init(blocks: [String: BlockNode]) {
self.blocks = blocks 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] { if var blocks = blocks[blockName] {
blocks.append(block) blocks.append(block)
self.blocks[blockName] = blocks 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] { if var blocks = blocks[blockName] {
let block = blocks.removeFirst() let block = blocks.removeFirst()
if blocks.isEmpty { if blocks.isEmpty {
@@ -88,14 +89,12 @@ class ExtendsNode : NodeType {
let baseTemplate = try context.environment.loadTemplate(name: templateName) let baseTemplate = try context.environment.loadTemplate(name: templateName)
let blockContext: BlockContext let blockContext: BlockContext
if let _blockContext = context[BlockContext.contextKey] as? BlockContext { if let currentBlockContext = context[BlockContext.contextKey] as? BlockContext {
blockContext = _blockContext blockContext = currentBlockContext
for (name, block) in blocks { for (name, block) in blocks {
blockContext.pushBlock(block, named: name) blockContext.push(block, forKey: name)
} }
} else { } else {
var blocks = [String: [BlockNode]]()
self.blocks.forEach { blocks[$0.key] = [$0.value] }
blockContext = BlockContext(blocks: blocks) blockContext = BlockContext(blocks: blocks)
} }
@@ -144,18 +143,32 @@ class BlockNode : NodeType {
} }
func render(_ context: Context) throws -> String { func render(_ context: Context) throws -> String {
if let blockContext = context[BlockContext.contextKey] as? BlockContext, let child = blockContext.popBlock(named: name) { if let blockContext = context[BlockContext.contextKey] as? BlockContext, let child = blockContext.pop(name) {
// child node is a block node from child template that extends this node (has the same name) let childContext = try self.childContext(child, blockContext: blockContext, context: context)
// render extension node
do {
return try context.push(dictionary: childContext) {
return try child.render(context)
}
} catch {
throw error.withToken(child.token)
}
}
var newContext: [String: Any] = [BlockContext.contextKey: blockContext] 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 let blockSuperNode = child.nodes.first(where: {
if case .variable(let variable, _)? = $0.token, variable == "block.super" { return true } if case .variable(let variable, _)? = $0.token, variable == "block.super" { return true }
else { return false} else { return false}
}) { }) {
do { do {
// render current (base) node so that its content can be used as part of node that extends it // render base node so that its content can be used as part of child node that extends it
newContext["block"] = ["super": try self.render(context)] childContext["block"] = ["super": try self.render(context)]
} catch { } catch {
if let error = error as? TemplateSyntaxError { if let error = error as? TemplateSyntaxError {
throw TemplateSyntaxError( throw TemplateSyntaxError(
@@ -170,22 +183,7 @@ class BlockNode : NodeType {
} }
} }
} }
return childContext
// render extension node
do {
return try context.push(dictionary: newContext) {
return try child.render(context)
}
} catch {
if var error = error as? TemplateSyntaxError {
error.token = error.token ?? child.token
throw error
} else {
throw error
}
}
} }
return try renderNodes(nodes, context)
}
} }

View File

@@ -15,12 +15,7 @@ public func renderNodes(_ nodes:[NodeType], _ context:Context) throws -> String
do { do {
return try $0.render(context) return try $0.render(context)
} catch { } catch {
if var error = error as? TemplateSyntaxError { throw error.withToken($0.token)
error.token = error.token ?? $0.token
throw error
} else {
throw error
}
} }
}).joined(separator: "") }).joined(separator: "")
} }

View File

@@ -54,12 +54,7 @@ public class TokenParser {
let node = try parser(self, token) let node = try parser(self, token)
nodes.append(node) nodes.append(node)
} catch { } catch {
if var error = error as? TemplateSyntaxError { throw error.withToken(token)
error.token = error.token ?? token
throw error
} else {
throw error
}
} }
} }
case .comment: case .comment: