Refactor more components to use enum
This commit is contained in:
@@ -138,31 +138,33 @@ public class ForNode : Node {
|
|||||||
if count == 4 && components[2] == "in" {
|
if count == 4 && components[2] == "in" {
|
||||||
let loopVariable = components[1]
|
let loopVariable = components[1]
|
||||||
let variable = components[3]
|
let variable = components[3]
|
||||||
let (nodes, error) = parser.parse(until(["endfor", "empty"]))
|
|
||||||
|
var forNodes:[Node]!
|
||||||
var emptyNodes = [Node]()
|
var emptyNodes = [Node]()
|
||||||
|
|
||||||
if let error = error {
|
switch parser.parse(until(["endfor", "empty"])) {
|
||||||
return .Error(error: error)
|
case .Success(let nodes):
|
||||||
|
forNodes = nodes
|
||||||
|
case .Error(let error):
|
||||||
|
return .Error(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let token = parser.nextToken() {
|
if let token = parser.nextToken() {
|
||||||
if token.contents == "empty" {
|
if token.contents == "empty" {
|
||||||
let (nodes, error) = parser.parse(until(["endfor"]))
|
switch parser.parse(until(["endfor"])) {
|
||||||
parser.nextToken()
|
case .Success(let nodes):
|
||||||
|
|
||||||
if let error = error {
|
|
||||||
return .Error(error: error)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let nodes = nodes {
|
|
||||||
emptyNodes = nodes
|
emptyNodes = nodes
|
||||||
|
case .Error(let error):
|
||||||
|
return .Error(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parser.nextToken()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return .Error(error: NodeError(token: token, message: "`endfor` was not found."))
|
return .Error(error: NodeError(token: token, message: "`endfor` was not found."))
|
||||||
}
|
}
|
||||||
|
|
||||||
return .Success(node:ForNode(variable: variable, loopVariable: loopVariable, nodes: nodes!, emptyNodes:emptyNodes))
|
return .Success(node:ForNode(variable: variable, loopVariable: loopVariable, nodes: forNodes, emptyNodes:emptyNodes))
|
||||||
}
|
}
|
||||||
|
|
||||||
return .Error(error: NodeError(token: token, message: "Invalid syntax. Expected `for x in y`."))
|
return .Error(error: NodeError(token: token, message: "Invalid syntax. Expected `for x in y`."))
|
||||||
@@ -206,61 +208,60 @@ public class IfNode : Node {
|
|||||||
|
|
||||||
public class func parse(parser:TokenParser, token:Token) -> TokenParser.Result {
|
public class func parse(parser:TokenParser, token:Token) -> TokenParser.Result {
|
||||||
let variable = token.components()[1]
|
let variable = token.components()[1]
|
||||||
|
var trueNodes = [Node]()
|
||||||
let (trueNodes, error) = parser.parse(until(["endif", "else"]))
|
|
||||||
if let error = error {
|
|
||||||
return .Error(error:error)
|
|
||||||
}
|
|
||||||
|
|
||||||
var falseNodes = [Node]()
|
var falseNodes = [Node]()
|
||||||
|
|
||||||
|
switch parser.parse(until(["endif", "else"])) {
|
||||||
|
case .Success(let nodes):
|
||||||
|
trueNodes = nodes
|
||||||
|
case .Error(let error):
|
||||||
|
return .Error(error)
|
||||||
|
}
|
||||||
|
|
||||||
if let token = parser.nextToken() {
|
if let token = parser.nextToken() {
|
||||||
if token.contents == "else" {
|
if token.contents == "else" {
|
||||||
let (nodes, error) = parser.parse(until(["endif"]))
|
switch parser.parse(until(["endif"])) {
|
||||||
parser.nextToken()
|
case .Success(let nodes):
|
||||||
|
|
||||||
if let error = error {
|
|
||||||
return .Error(error:error)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let nodes = nodes {
|
|
||||||
falseNodes = nodes
|
falseNodes = nodes
|
||||||
|
case .Error(let error):
|
||||||
|
return .Error(error)
|
||||||
}
|
}
|
||||||
|
parser.nextToken()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return .Error(error:NodeError(token: token, message: "`endif` was not found."))
|
return .Error(error:NodeError(token: token, message: "`endif` was not found."))
|
||||||
}
|
}
|
||||||
|
|
||||||
return .Success(node:IfNode(variable: variable, trueNodes: trueNodes!, falseNodes: falseNodes))
|
return .Success(node:IfNode(variable: variable, trueNodes: trueNodes, falseNodes: falseNodes))
|
||||||
}
|
}
|
||||||
|
|
||||||
public class func parse_ifnot(parser:TokenParser, token:Token) -> TokenParser.Result {
|
public class func parse_ifnot(parser:TokenParser, token:Token) -> TokenParser.Result {
|
||||||
let variable = token.components()[1]
|
let variable = token.components()[1]
|
||||||
|
|
||||||
let (falseNodes, error) = parser.parse(until(["endif", "else"]))
|
|
||||||
if let error = error {
|
|
||||||
return .Error(error:error)
|
|
||||||
}
|
|
||||||
var trueNodes = [Node]()
|
var trueNodes = [Node]()
|
||||||
|
var falseNodes = [Node]()
|
||||||
|
|
||||||
|
switch parser.parse(until(["endif", "else"])) {
|
||||||
|
case .Success(let nodes):
|
||||||
|
falseNodes = nodes
|
||||||
|
case .Error(let error):
|
||||||
|
return .Error(error)
|
||||||
|
}
|
||||||
|
|
||||||
if let token = parser.nextToken() {
|
if let token = parser.nextToken() {
|
||||||
if token.contents == "else" {
|
if token.contents == "else" {
|
||||||
let (nodes, error) = parser.parse(until(["endif"]))
|
switch parser.parse(until(["endif"])) {
|
||||||
if let error = error {
|
case .Success(let nodes):
|
||||||
return .Error(error:error)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let nodes = nodes {
|
|
||||||
trueNodes = nodes
|
trueNodes = nodes
|
||||||
|
case .Error(let error):
|
||||||
|
return .Error(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.nextToken()
|
parser.nextToken()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return .Error(error:NodeError(token: token, message: "`endif` was not found."))
|
return .Error(error:NodeError(token: token, message: "`endif` was not found."))
|
||||||
}
|
}
|
||||||
|
|
||||||
return .Success(node: IfNode(variable: variable, trueNodes: trueNodes, falseNodes: falseNodes!))
|
return .Success(node:IfNode(variable: variable, trueNodes: trueNodes, falseNodes: falseNodes))
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(variable:String, trueNodes:[Node], falseNodes:[Node]) {
|
public init(variable:String, trueNodes:[Node], falseNodes:[Node]) {
|
||||||
|
|||||||
@@ -13,12 +13,18 @@ public func until(tags:[String])(parser:TokenParser, token:Token) -> Bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class TokenParser {
|
public class TokenParser {
|
||||||
|
public typealias TagParser = (TokenParser, Token) -> Result
|
||||||
|
public typealias NodeList = [Node]
|
||||||
|
|
||||||
public enum Result {
|
public enum Result {
|
||||||
case Success(node: Node)
|
case Success(node: Node)
|
||||||
case Error(error: Stencil.Error)
|
case Error(error: Stencil.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias TagParser = (TokenParser, Token) -> Result
|
public enum Results {
|
||||||
|
case Success(nodes: NodeList)
|
||||||
|
case Error(error: Stencil.Error)
|
||||||
|
}
|
||||||
|
|
||||||
private var tokens:[Token]
|
private var tokens:[Token]
|
||||||
private var tags = Dictionary<String, TagParser>()
|
private var tags = Dictionary<String, TagParser>()
|
||||||
@@ -31,12 +37,12 @@ public class TokenParser {
|
|||||||
tags["ifnot"] = IfNode.parse_ifnot
|
tags["ifnot"] = IfNode.parse_ifnot
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parse() -> (nodes:[Node]?, error:Error?) {
|
public func parse() -> Results {
|
||||||
return parse(nil)
|
return parse(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parse(parse_until:((parser:TokenParser, token:Token) -> (Bool))?) -> (nodes:[Node]?, error:Error?) {
|
public func parse(parse_until:((parser:TokenParser, token:Token) -> (Bool))?) -> TokenParser.Results {
|
||||||
var nodes = [Node]()
|
var nodes = NodeList()
|
||||||
|
|
||||||
while tokens.count > 0 {
|
while tokens.count > 0 {
|
||||||
let token = nextToken()!
|
let token = nextToken()!
|
||||||
@@ -52,7 +58,7 @@ public class TokenParser {
|
|||||||
if let parse_until = parse_until {
|
if let parse_until = parse_until {
|
||||||
if parse_until(parser: self, token: token) {
|
if parse_until(parser: self, token: token) {
|
||||||
prependToken(token)
|
prependToken(token)
|
||||||
return (nodes, nil)
|
return .Success(nodes:nodes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +68,7 @@ public class TokenParser {
|
|||||||
case .Success(let node):
|
case .Success(let node):
|
||||||
nodes.append(node)
|
nodes.append(node)
|
||||||
case .Error(let error):
|
case .Error(let error):
|
||||||
return (nil, error)
|
return .Error(error:error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,7 +77,7 @@ public class TokenParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (nodes, nil)
|
return .Success(nodes:nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func nextToken() -> Token? {
|
public func nextToken() -> Token? {
|
||||||
|
|||||||
@@ -37,18 +37,18 @@ public class Template {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func render(context:Context) -> Result {
|
public func render(context:Context) -> Result {
|
||||||
let (nodes, error) = parser.parse()
|
switch parser.parse() {
|
||||||
|
case .Success(let nodes):
|
||||||
if let error = error {
|
let (result, error) = renderNodes(nodes, context)
|
||||||
|
if let result = result {
|
||||||
|
return .Success(string:result)
|
||||||
|
} else if let error = error {
|
||||||
return .Error(error:error)
|
return .Error(error:error)
|
||||||
} else if let nodes = nodes {
|
|
||||||
let result = renderNodes(nodes, context)
|
|
||||||
if let string = result.0 {
|
|
||||||
return .Success(string: string)
|
|
||||||
} else {
|
|
||||||
return .Error(error: result.1!)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return .Success(string:"")
|
return .Success(string:"")
|
||||||
|
|
||||||
|
case .Error(let error):
|
||||||
|
return .Error(error:error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,19 +93,19 @@ class IfNodeTests: NodeTests {
|
|||||||
]
|
]
|
||||||
|
|
||||||
let parser = TokenParser(tokens: tokens)
|
let parser = TokenParser(tokens: tokens)
|
||||||
let (nodes, error) = parser.parse()
|
assertSuccess(parser.parse()) { nodes in
|
||||||
let node = nodes!.first! as IfNode
|
let node = nodes.first! as IfNode
|
||||||
let trueNode = node.trueNodes.first! as TextNode
|
let trueNode = node.trueNodes.first! as TextNode
|
||||||
let falseNode = node.falseNodes.first! as TextNode
|
let falseNode = node.falseNodes.first! as TextNode
|
||||||
|
|
||||||
XCTAssertTrue(error == nil)
|
XCTAssertEqual(nodes.count, 1)
|
||||||
XCTAssertEqual(nodes!.count, 1)
|
|
||||||
XCTAssertEqual(node.variable.variable, "value")
|
XCTAssertEqual(node.variable.variable, "value")
|
||||||
XCTAssertEqual(node.trueNodes.count, 1)
|
XCTAssertEqual(node.trueNodes.count, 1)
|
||||||
XCTAssertEqual(trueNode.text, "true")
|
XCTAssertEqual(trueNode.text, "true")
|
||||||
XCTAssertEqual(node.falseNodes.count, 1)
|
XCTAssertEqual(node.falseNodes.count, 1)
|
||||||
XCTAssertEqual(falseNode.text, "false")
|
XCTAssertEqual(falseNode.text, "false")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testParseIfNot() {
|
func testParseIfNot() {
|
||||||
let tokens = [
|
let tokens = [
|
||||||
@@ -117,19 +117,19 @@ class IfNodeTests: NodeTests {
|
|||||||
]
|
]
|
||||||
|
|
||||||
let parser = TokenParser(tokens: tokens)
|
let parser = TokenParser(tokens: tokens)
|
||||||
let (nodes, error) = parser.parse()
|
assertSuccess(parser.parse()) { nodes in
|
||||||
let node = nodes!.first! as IfNode
|
let node = nodes.first! as IfNode
|
||||||
let trueNode = node.trueNodes.first! as TextNode
|
let trueNode = node.trueNodes.first! as TextNode
|
||||||
let falseNode = node.falseNodes.first! as TextNode
|
let falseNode = node.falseNodes.first! as TextNode
|
||||||
|
|
||||||
XCTAssertTrue(error == nil)
|
XCTAssertEqual(nodes.count, 1)
|
||||||
XCTAssertEqual(nodes!.count, 1)
|
|
||||||
XCTAssertEqual(node.variable.variable, "value")
|
XCTAssertEqual(node.variable.variable, "value")
|
||||||
XCTAssertEqual(node.trueNodes.count, 1)
|
XCTAssertEqual(node.trueNodes.count, 1)
|
||||||
XCTAssertEqual(trueNode.text, "true")
|
XCTAssertEqual(trueNode.text, "true")
|
||||||
XCTAssertEqual(node.falseNodes.count, 1)
|
XCTAssertEqual(node.falseNodes.count, 1)
|
||||||
XCTAssertEqual(falseNode.text, "false")
|
XCTAssertEqual(falseNode.text, "false")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testParseIfWithoutEndIfError() {
|
func testParseIfWithoutEndIfError() {
|
||||||
let tokens = [
|
let tokens = [
|
||||||
@@ -137,10 +137,7 @@ class IfNodeTests: NodeTests {
|
|||||||
]
|
]
|
||||||
|
|
||||||
let parser = TokenParser(tokens: tokens)
|
let parser = TokenParser(tokens: tokens)
|
||||||
let (nodes, error) = parser.parse()
|
assertFailure(parser.parse(), "if: `endif` was not found.")
|
||||||
|
|
||||||
XCTAssertTrue(nodes == nil)
|
|
||||||
XCTAssertEqual(error!.description, "if: `endif` was not found.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testParseIfNotWithoutEndIfError() {
|
func testParseIfNotWithoutEndIfError() {
|
||||||
@@ -149,10 +146,7 @@ class IfNodeTests: NodeTests {
|
|||||||
]
|
]
|
||||||
|
|
||||||
let parser = TokenParser(tokens: tokens)
|
let parser = TokenParser(tokens: tokens)
|
||||||
let (nodes, error) = parser.parse()
|
assertFailure(parser.parse(), "ifnot: `endif` was not found.")
|
||||||
|
|
||||||
XCTAssertTrue(nodes == nil)
|
|
||||||
XCTAssertEqual(error!.description, "ifnot: `endif` was not found.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Rendering
|
// MARK: Rendering
|
||||||
@@ -180,26 +174,24 @@ class NowNodeTests: NodeTests {
|
|||||||
func testParseDefaultNow() {
|
func testParseDefaultNow() {
|
||||||
let tokens = [ Token.Block(value: "now") ]
|
let tokens = [ Token.Block(value: "now") ]
|
||||||
let parser = TokenParser(tokens: tokens)
|
let parser = TokenParser(tokens: tokens)
|
||||||
let (nodes, error) = parser.parse()
|
|
||||||
|
|
||||||
let node = nodes!.first! as NowNode
|
assertSuccess(parser.parse()) { nodes in
|
||||||
|
let node = nodes.first! as NowNode
|
||||||
XCTAssertTrue(error == nil)
|
XCTAssertEqual(nodes.count, 1)
|
||||||
XCTAssertEqual(nodes!.count, 1)
|
|
||||||
XCTAssertEqual(node.format.variable, "\"yyyy-MM-dd 'at' HH:mm\"")
|
XCTAssertEqual(node.format.variable, "\"yyyy-MM-dd 'at' HH:mm\"")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testParseNowWithFormat() {
|
func testParseNowWithFormat() {
|
||||||
let tokens = [ Token.Block(value: "now \"HH:mm\"") ]
|
let tokens = [ Token.Block(value: "now \"HH:mm\"") ]
|
||||||
let parser = TokenParser(tokens: tokens)
|
let parser = TokenParser(tokens: tokens)
|
||||||
let (nodes, error) = parser.parse()
|
|
||||||
|
|
||||||
let node = nodes!.first! as NowNode
|
assertSuccess(parser.parse()) { nodes in
|
||||||
|
let node = nodes.first! as NowNode
|
||||||
XCTAssertTrue(error == nil)
|
XCTAssertEqual(nodes.count, 1)
|
||||||
XCTAssertEqual(nodes!.count, 1)
|
|
||||||
XCTAssertEqual(node.format.variable, "\"HH:mm\"")
|
XCTAssertEqual(node.format.variable, "\"HH:mm\"")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Rendering
|
// MARK: Rendering
|
||||||
|
|
||||||
|
|||||||
@@ -8,26 +8,23 @@ class TokenParserTests: XCTestCase {
|
|||||||
Token.Text(value: "Hello World")
|
Token.Text(value: "Hello World")
|
||||||
])
|
])
|
||||||
|
|
||||||
let (nodes, error) = parser.parse()
|
assertSuccess(parser.parse()) { nodes in
|
||||||
let node = nodes!.first as TextNode!
|
let node = nodes.first as TextNode!
|
||||||
|
XCTAssertEqual(nodes.count, 1)
|
||||||
XCTAssertTrue(error == nil)
|
|
||||||
XCTAssertEqual(nodes!.count, 1)
|
|
||||||
XCTAssertEqual(node.text, "Hello World")
|
XCTAssertEqual(node.text, "Hello World")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testParsingVariableToken() {
|
func testParsingVariableToken() {
|
||||||
let parser = TokenParser(tokens: [
|
let parser = TokenParser(tokens: [
|
||||||
Token.Variable(value: "name")
|
Token.Variable(value: "name")
|
||||||
])
|
])
|
||||||
|
|
||||||
let (nodes, error) = parser.parse()
|
assertSuccess(parser.parse()) { nodes in
|
||||||
let node = nodes!.first as VariableNode!
|
let node = nodes.first as VariableNode!
|
||||||
let variable = node.variable
|
XCTAssertEqual(nodes.count, 1)
|
||||||
|
XCTAssertEqual(node.variable, Variable("name"))
|
||||||
XCTAssertTrue(error == nil)
|
}
|
||||||
XCTAssertEqual(nodes!.count, 1)
|
|
||||||
XCTAssertEqual(variable, Variable("name"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testParsingCommentToken() {
|
func testParsingCommentToken() {
|
||||||
@@ -35,9 +32,9 @@ class TokenParserTests: XCTestCase {
|
|||||||
Token.Comment(value: "Secret stuff!")
|
Token.Comment(value: "Secret stuff!")
|
||||||
])
|
])
|
||||||
|
|
||||||
let (nodes, error) = parser.parse()
|
assertSuccess(parser.parse()) { nodes in
|
||||||
|
XCTAssertEqual(nodes.count, 0)
|
||||||
XCTAssertEqual(nodes!.count, 0)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testParsingTagToken() {
|
func testParsingTagToken() {
|
||||||
@@ -45,9 +42,8 @@ class TokenParserTests: XCTestCase {
|
|||||||
Token.Block(value: "now"),
|
Token.Block(value: "now"),
|
||||||
])
|
])
|
||||||
|
|
||||||
let (nodes, error) = parser.parse()
|
assertSuccess(parser.parse()) { nodes in
|
||||||
let node = nodes!.first as NowNode!
|
XCTAssertEqual(nodes.count, 1)
|
||||||
XCTAssertTrue(error == nil)
|
}
|
||||||
XCTAssertEqual(nodes!.count, 1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,24 @@ import Cocoa
|
|||||||
import XCTest
|
import XCTest
|
||||||
import Stencil
|
import Stencil
|
||||||
|
|
||||||
|
func assertSuccess(result:TokenParser.Results, block:(([Node]) -> ())) {
|
||||||
|
switch result {
|
||||||
|
case .Success(let nodes):
|
||||||
|
block(nodes)
|
||||||
|
case .Error(let error):
|
||||||
|
XCTAssert(false, "Unexpected error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertFailure(result:TokenParser.Results, description:String) {
|
||||||
|
switch result {
|
||||||
|
case .Success(let nodes):
|
||||||
|
XCTAssert(false, "Unexpected error")
|
||||||
|
case .Error(let error):
|
||||||
|
XCTAssertEqual("\(error)", description)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class StencilTests: XCTestCase {
|
class StencilTests: XCTestCase {
|
||||||
func testReadmeExample() {
|
func testReadmeExample() {
|
||||||
let templateString = "There are {{ articles.count }} articles.\n" +
|
let templateString = "There are {{ articles.count }} articles.\n" +
|
||||||
|
|||||||
Reference in New Issue
Block a user