///|
priv struct ParsedFilter {
name : String
parameters : Array[String]
}
///|
priv struct LoopModifiers {
limit : Int?
offset : Int?
reversed : Bool
}
///|
fn parsed_filter(name : String, parameters : Array[String]) -> ParsedFilter {
{ name, parameters, }
}
///|
/// Find a delimiter outside single- and double-quoted Liquid strings.
fn find_unquoted(text : String, delimiter : String) -> Int? {
let mut quote : UInt16 = 0
for i in 0.. Array[String] {
let parts : Array[String] = []
let mut rest = text
while find_unquoted(rest, delimiter) is Some(index) {
parts.push(rest[:index].to_owned())
rest = rest[index + delimiter.length():].to_owned()
}
parts.push(rest)
parts
}
///|
fn parse_output(expression : String) -> (String, Array[ParsedFilter]) {
let parts = split_unquoted(expression, "|")
let filters : Array[ParsedFilter] = []
for part in parts[1:] {
match find_unquoted(part, ":") {
Some(index) =>
filters.push(
parsed_filter(
part[:index].trim().to_owned(),
split_unquoted(part[index + 1:].to_owned(), ",").map(fn(p) {
p.trim().to_owned()
}),
),
)
None => filters.push(parsed_filter(part.trim().to_owned(), []))
}
}
(parts[0].trim().to_owned(), filters)
}
///|
fn parse_for_loop_modifiers(collection_str : String) -> (String, LoopModifiers) {
let parts = collection_str
.split(":")
.map(fn(s) { s.to_owned() })
.collect()
.join(" : ")
.split(" ")
.flat_map(fn(part) { part.split("\t") })
.filter(fn(part) { !part.is_empty() })
.collect()
let collection = parts[0].to_owned()
let mut limit : Int? = None
let mut offset : Int? = None
let mut reversed = false
let mut i = 1
while i < parts.length() {
let part = parts[i]
if (part == "limit" || part == "offset") &&
i + 2 < parts.length() &&
parts[i + 1] == ":" {
let count = @semantics.parse_integer(parts[i + 2].to_owned())
if part == "limit" {
limit = count
} else {
offset = count
}
i += 3
} else {
if part == "reversed" {
reversed = true
}
i += 1
}
}
(collection, { limit, offset, reversed, })
}