minor code refactoring
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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> {
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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: "")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user