Merge branch 'master' into errors-logs-improvements
This commit is contained in:
@@ -11,25 +11,28 @@ class ForNode : NodeType {
|
||||
class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
|
||||
let components = token.components()
|
||||
|
||||
guard components.count >= 3 && components[2] == "in" &&
|
||||
(components.count == 4 || (components.count >= 6 && components[4] == "where")) else {
|
||||
throw TemplateSyntaxError("'for' statements should use the following syntax 'for x in y where condition'.")
|
||||
func hasToken(_ token: String, at index: Int) -> Bool {
|
||||
return components.count > (index + 1) && components[index] == token
|
||||
}
|
||||
|
||||
func endsOrHasToken(_ token: String, at index: Int) -> Bool {
|
||||
return components.count == index || hasToken(token, at: index)
|
||||
}
|
||||
|
||||
guard hasToken("in", at: 2) && endsOrHasToken("where", at: 4) else {
|
||||
throw TemplateSyntaxError("'for' statements should use the syntax: `for <x> in <y> [where <condition>]`.")
|
||||
}
|
||||
|
||||
let loopVariables = components[1].characters
|
||||
.split(separator: ",")
|
||||
.map(String.init)
|
||||
.map { $0.trimmingCharacters(in: CharacterSet.whitespaces) }
|
||||
.map { $0.trim(character: " ") }
|
||||
|
||||
let variable = components[3]
|
||||
let filter = try parser.compileFilter(variable, containedIn: token)
|
||||
let resolvable = try parser.compileResolvable(components[3], containedIn: token)
|
||||
|
||||
let `where`: Expression?
|
||||
if components.count >= 6 {
|
||||
`where` = try parseExpression(components: Array(components.suffix(from: 5)), tokenParser: parser, token: token)
|
||||
} else {
|
||||
`where` = nil
|
||||
}
|
||||
let `where` = hasToken("where", at: 4)
|
||||
? try parseExpression(components: Array(components.suffix(from: 5)), tokenParser: parser, token: token)
|
||||
: nil
|
||||
|
||||
let forNodes = try parser.parse(until(["endfor", "empty"]))
|
||||
|
||||
@@ -43,7 +46,7 @@ class ForNode : NodeType {
|
||||
_ = parser.nextToken()
|
||||
}
|
||||
|
||||
return ForNode(resolvable: filter, loopVariables: loopVariables, nodes: forNodes, emptyNodes:emptyNodes, where: `where`, token: token)
|
||||
return ForNode(resolvable: resolvable, loopVariables: loopVariables, nodes: forNodes, emptyNodes:emptyNodes, where: `where`, token: token)
|
||||
}
|
||||
|
||||
init(resolvable: Resolvable, loopVariables: [String], nodes:[NodeType], emptyNodes:[NodeType], where: Expression? = nil, token: Token? = nil) {
|
||||
@@ -55,25 +58,26 @@ class ForNode : NodeType {
|
||||
self.token = token
|
||||
}
|
||||
|
||||
func push<Result>(value: Any, context: Context, closure: () throws -> (Result)) rethrows -> Result {
|
||||
func push<Result>(value: Any, context: Context, closure: () throws -> (Result)) throws -> Result {
|
||||
if loopVariables.isEmpty {
|
||||
return try context.push() {
|
||||
return try closure()
|
||||
}
|
||||
}
|
||||
|
||||
if let value = value as? (Any, Any) {
|
||||
let first = loopVariables[0]
|
||||
|
||||
if loopVariables.count == 2 {
|
||||
let second = loopVariables[1]
|
||||
|
||||
return try context.push(dictionary: [first: value.0, second: value.1]) {
|
||||
return try closure()
|
||||
}
|
||||
let valueMirror = Mirror(reflecting: value)
|
||||
if case .tuple? = valueMirror.displayStyle {
|
||||
if loopVariables.count > Int(valueMirror.children.count) {
|
||||
throw TemplateSyntaxError("Tuple '\(value)' has less values than loop variables")
|
||||
}
|
||||
var variablesContext = [String: Any]()
|
||||
valueMirror.children.prefix(loopVariables.count).enumerated().forEach({ (offset, element) in
|
||||
if loopVariables[offset] != "_" {
|
||||
variablesContext[loopVariables[offset]] = element.value
|
||||
}
|
||||
})
|
||||
|
||||
return try context.push(dictionary: [first: value.0]) {
|
||||
return try context.push(dictionary: variablesContext) {
|
||||
return try closure()
|
||||
}
|
||||
}
|
||||
@@ -133,14 +137,15 @@ class ForNode : NodeType {
|
||||
"last": index == (count - 1),
|
||||
"counter": index + 1,
|
||||
"counter0": index,
|
||||
]
|
||||
"length": count
|
||||
]
|
||||
|
||||
return try context.push(dictionary: ["forloop": forContext]) {
|
||||
return try push(value: item, context: context) {
|
||||
try renderNodes(nodes, context)
|
||||
}
|
||||
}
|
||||
}.joined(separator: "")
|
||||
}.joined(separator: "")
|
||||
}
|
||||
|
||||
return try context.push {
|
||||
|
||||
Reference in New Issue
Block a user