Files
swiftpm-stencil/Sources/Tokenizer.swift
Ilya Puchka 39ed9aa753 Fixed using spaces in filter expressions and variables lists (#178)
* fixed using spaces in filter expression

* fixed breaking variables lists and filters by spaces

* simplified smartJoin

* avoid force unwrap
2018-05-13 01:06:38 +01:00

115 lines
2.9 KiB
Swift

import Foundation
extension String {
/// Split a string by a separator leaving quoted phrases together
func smartSplit(separator: Character = " ") -> [String] {
var word = ""
var components: [String] = []
var separate: Character = separator
var singleQuoteCount = 0
var doubleQuoteCount = 0
let specialCharacters = ",|:"
func appendWord(_ word: String) {
if components.count > 0 {
if let precedingChar = components.last?.characters.last, specialCharacters.characters.contains(precedingChar) {
components[components.count-1] += word
} else if specialCharacters.contains(word) {
components[components.count-1] += word
} else {
components.append(word)
}
} else {
components.append(word)
}
}
for character in self.characters {
if character == "'" { singleQuoteCount += 1 }
else if character == "\"" { doubleQuoteCount += 1 }
if character == separate {
if separate != separator {
word.append(separate)
} else if (singleQuoteCount % 2 == 0 || doubleQuoteCount % 2 == 0) && !word.isEmpty {
appendWord(word)
word = ""
}
separate = separator
} else {
if separate == separator && (character == "'" || character == "\"") {
separate = character
}
word.append(character)
}
}
if !word.isEmpty {
appendWord(word)
}
return components
}
}
public enum Token : Equatable {
/// A token representing a piece of text.
case text(value: String)
/// A token representing a variable.
case variable(value: String)
/// A token representing a comment.
case comment(value: String)
/// A token representing a template block.
case block(value: String)
/// Returns the underlying value as an array seperated by spaces
public func components() -> [String] {
switch self {
case .block(let value):
return value.smartSplit()
case .variable(let value):
return value.smartSplit()
case .text(let value):
return value.smartSplit()
case .comment(let value):
return value.smartSplit()
}
}
public var contents: String {
switch self {
case .block(let value):
return value
case .variable(let value):
return value
case .text(let value):
return value
case .comment(let value):
return value
}
}
}
public func == (lhs: Token, rhs: Token) -> Bool {
switch (lhs, rhs) {
case (.text(let lhsValue), .text(let rhsValue)):
return lhsValue == rhsValue
case (.variable(let lhsValue), .variable(let rhsValue)):
return lhsValue == rhsValue
case (.block(let lhsValue), .block(let rhsValue)):
return lhsValue == rhsValue
case (.comment(let lhsValue), .comment(let rhsValue)):
return lhsValue == rhsValue
default:
return false
}
}