Convert Token from enum to struct (#256)
* convert Token from enum to struct * private setter for components * updated CHANGELOG
This commit is contained in:
@@ -20,7 +20,9 @@ _None_
|
|||||||
|
|
||||||
### Internal Changes
|
### Internal Changes
|
||||||
|
|
||||||
_None_
|
- `Token` type converted to struct to allow computing token components only once.
|
||||||
|
[Ilya Puchka](https://github.com/ilyapuchka)
|
||||||
|
[#256](https://github.com/stencilproject/Stencil/pull/256)
|
||||||
|
|
||||||
|
|
||||||
## 0.13.1
|
## 0.13.1
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ class FilterNode : NodeType {
|
|||||||
let token: Token?
|
let token: Token?
|
||||||
|
|
||||||
class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
|
class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
|
||||||
let bits = token.components()
|
let bits = token.components
|
||||||
|
|
||||||
guard bits.count == 2 else {
|
guard bits.count == 2 else {
|
||||||
throw TemplateSyntaxError("'filter' tag takes one argument, the filter expression")
|
throw TemplateSyntaxError("'filter' tag takes one argument, the filter expression")
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class ForNode : NodeType {
|
|||||||
let token: Token?
|
let token: Token?
|
||||||
|
|
||||||
class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
|
class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
|
||||||
let components = token.components()
|
let components = token.components
|
||||||
|
|
||||||
func hasToken(_ token: String, at index: Int) -> Bool {
|
func hasToken(_ token: String, at index: Int) -> Bool {
|
||||||
return components.count > (index + 1) && components[index] == token
|
return components.count > (index + 1) && components[index] == token
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ class IfNode : NodeType {
|
|||||||
let token: Token?
|
let token: Token?
|
||||||
|
|
||||||
class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
|
class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
|
||||||
var components = token.components()
|
var components = token.components
|
||||||
components.removeFirst()
|
components.removeFirst()
|
||||||
|
|
||||||
let expression = try parseExpression(components: components, tokenParser: parser, token: token)
|
let expression = try parseExpression(components: components, tokenParser: parser, token: token)
|
||||||
@@ -251,7 +251,7 @@ class IfNode : NodeType {
|
|||||||
|
|
||||||
var nextToken = parser.nextToken()
|
var nextToken = parser.nextToken()
|
||||||
while let current = nextToken, current.contents.hasPrefix("elif") {
|
while let current = nextToken, current.contents.hasPrefix("elif") {
|
||||||
var components = current.components()
|
var components = current.components
|
||||||
components.removeFirst()
|
components.removeFirst()
|
||||||
let expression = try parseExpression(components: components, tokenParser: parser, token: current)
|
let expression = try parseExpression(components: components, tokenParser: parser, token: current)
|
||||||
|
|
||||||
@@ -273,7 +273,7 @@ class IfNode : NodeType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class func parse_ifnot(_ parser: TokenParser, token: Token) throws -> NodeType {
|
class func parse_ifnot(_ parser: TokenParser, token: Token) throws -> NodeType {
|
||||||
var components = token.components()
|
var components = token.components
|
||||||
guard components.count == 2 else {
|
guard components.count == 2 else {
|
||||||
throw TemplateSyntaxError("'ifnot' statements should use the following syntax 'ifnot condition'.")
|
throw TemplateSyntaxError("'ifnot' statements should use the following syntax 'ifnot condition'.")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ class IncludeNode : NodeType {
|
|||||||
let token: Token?
|
let token: Token?
|
||||||
|
|
||||||
class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
|
class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
|
||||||
let bits = token.components()
|
let bits = token.components
|
||||||
|
|
||||||
guard bits.count == 2 || bits.count == 3 else {
|
guard bits.count == 2 || bits.count == 3 else {
|
||||||
throw TemplateSyntaxError("""
|
throw TemplateSyntaxError("""
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class ExtendsNode : NodeType {
|
|||||||
let token: Token?
|
let token: Token?
|
||||||
|
|
||||||
class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
|
class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
|
||||||
let bits = token.components()
|
let bits = token.components
|
||||||
|
|
||||||
guard bits.count == 2 else {
|
guard bits.count == 2 else {
|
||||||
throw TemplateSyntaxError("'extends' takes one argument, the template file to be extended")
|
throw TemplateSyntaxError("'extends' takes one argument, the template file to be extended")
|
||||||
@@ -124,7 +124,7 @@ class BlockNode : NodeType {
|
|||||||
let token: Token?
|
let token: Token?
|
||||||
|
|
||||||
class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
|
class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
|
||||||
let bits = token.components()
|
let bits = token.components
|
||||||
|
|
||||||
guard bits.count == 2 else {
|
guard bits.count == 2 else {
|
||||||
throw TemplateSyntaxError("'block' tag takes one argument, the block name")
|
throw TemplateSyntaxError("'block' tag takes one argument, the block name")
|
||||||
@@ -163,7 +163,7 @@ class BlockNode : NodeType {
|
|||||||
var childContext: [String: Any] = [BlockContext.contextKey: blockContext]
|
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 let token = $0.token, case .variable = token.kind, token.contents == "block.super" { return true }
|
||||||
else { return false}
|
else { return false}
|
||||||
}) {
|
}) {
|
||||||
do {
|
do {
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public class VariableNode : NodeType {
|
|||||||
let elseExpression: Resolvable?
|
let elseExpression: Resolvable?
|
||||||
|
|
||||||
class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
|
class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
|
||||||
var components = token.components()
|
var components = token.components
|
||||||
|
|
||||||
func hasToken(_ token: String, at index: Int) -> Bool {
|
func hasToken(_ token: String, at index: Int) -> Bool {
|
||||||
return components.count > (index + 1) && components[index] == token
|
return components.count > (index + 1) && components[index] == token
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class NowNode : NodeType {
|
|||||||
class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
|
class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
|
||||||
var format:Variable?
|
var format:Variable?
|
||||||
|
|
||||||
let components = token.components()
|
let components = token.components
|
||||||
guard components.count <= 2 else {
|
guard components.count <= 2 else {
|
||||||
throw TemplateSyntaxError("'now' tags may only have one argument: the format string.")
|
throw TemplateSyntaxError("'now' tags may only have one argument: the format string.")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
public func until(_ tags: [String]) -> ((TokenParser, Token) -> Bool) {
|
public func until(_ tags: [String]) -> ((TokenParser, Token) -> Bool) {
|
||||||
return { parser, token in
|
return { parser, token in
|
||||||
if let name = token.components().first {
|
if let name = token.components.first {
|
||||||
for tag in tags {
|
for tag in tags {
|
||||||
if name == tag {
|
if name == tag {
|
||||||
return true
|
return true
|
||||||
@@ -36,9 +36,9 @@ public class TokenParser {
|
|||||||
while tokens.count > 0 {
|
while tokens.count > 0 {
|
||||||
let token = nextToken()!
|
let token = nextToken()!
|
||||||
|
|
||||||
switch token {
|
switch token.kind {
|
||||||
case .text(let text, _):
|
case .text:
|
||||||
nodes.append(TextNode(text: text))
|
nodes.append(TextNode(text: token.contents))
|
||||||
case .variable:
|
case .variable:
|
||||||
try nodes.append(VariableNode.parse(self, token: token))
|
try nodes.append(VariableNode.parse(self, token: token))
|
||||||
case .block:
|
case .block:
|
||||||
@@ -47,7 +47,7 @@ public class TokenParser {
|
|||||||
return nodes
|
return nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
if let tag = token.components().first {
|
if let tag = token.components.first {
|
||||||
do {
|
do {
|
||||||
let parser = try findTag(name: tag)
|
let parser = try findTag(name: tag)
|
||||||
let node = try parser(self, token)
|
let node = try parser(self, token)
|
||||||
|
|||||||
@@ -71,47 +71,53 @@ public struct SourceMap: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Token : Equatable {
|
public class Token: Equatable {
|
||||||
|
public enum Kind: Equatable {
|
||||||
/// A token representing a piece of text.
|
/// A token representing a piece of text.
|
||||||
case text(value: String, at: SourceMap)
|
case text
|
||||||
|
|
||||||
/// A token representing a variable.
|
/// A token representing a variable.
|
||||||
case variable(value: String, at: SourceMap)
|
case variable
|
||||||
|
|
||||||
/// A token representing a comment.
|
/// A token representing a comment.
|
||||||
case comment(value: String, at: SourceMap)
|
case comment
|
||||||
|
|
||||||
/// A token representing a template block.
|
/// A token representing a template block.
|
||||||
case block(value: String, at: SourceMap)
|
case block
|
||||||
|
}
|
||||||
|
|
||||||
|
public let contents: String
|
||||||
|
public let kind: Kind
|
||||||
|
public let sourceMap: SourceMap
|
||||||
|
|
||||||
/// Returns the underlying value as an array seperated by spaces
|
/// Returns the underlying value as an array seperated by spaces
|
||||||
public func components() -> [String] {
|
public private(set) lazy var components: [String] = self.contents.smartSplit()
|
||||||
switch self {
|
|
||||||
case .block(let value, _),
|
init(contents: String, kind: Kind, sourceMap: SourceMap) {
|
||||||
.variable(let value, _),
|
self.contents = contents
|
||||||
.text(let value, _),
|
self.kind = kind
|
||||||
.comment(let value, _):
|
self.sourceMap = sourceMap
|
||||||
return value.smartSplit()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public var contents: String {
|
/// A token representing a piece of text.
|
||||||
switch self {
|
public static func text(value: String, at sourceMap: SourceMap) -> Token {
|
||||||
case .block(let value, _),
|
return Token(contents: value, kind: .text, sourceMap: sourceMap)
|
||||||
.variable(let value, _),
|
|
||||||
.text(let value, _),
|
|
||||||
.comment(let value, _):
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public var sourceMap: SourceMap {
|
/// A token representing a variable.
|
||||||
switch self {
|
public static func variable(value: String, at sourceMap: SourceMap) -> Token {
|
||||||
case .block(_, let sourceMap),
|
return Token(contents: value, kind: .variable, sourceMap: sourceMap)
|
||||||
.variable(_, let sourceMap),
|
|
||||||
.text(_, let sourceMap),
|
|
||||||
.comment(_, let sourceMap):
|
|
||||||
return sourceMap
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A token representing a comment.
|
||||||
|
public static func comment(value: String, at sourceMap: SourceMap) -> Token {
|
||||||
|
return Token(contents: value, kind: .comment, sourceMap: sourceMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A token representing a template block.
|
||||||
|
public static func block(value: String, at sourceMap: SourceMap) -> Token {
|
||||||
|
return Token(contents: value, kind: .block, sourceMap: sourceMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func == (lhs: Token, rhs: Token) -> Bool {
|
||||||
|
return lhs.contents == rhs.contents && lhs.kind == rhs.kind && lhs.sourceMap == rhs.sourceMap
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ class TokenTests: XCTestCase {
|
|||||||
describe("Token") {
|
describe("Token") {
|
||||||
$0.it("can split the contents into components") {
|
$0.it("can split the contents into components") {
|
||||||
let token = Token.text(value: "hello world", at: .unknown)
|
let token = Token.text(value: "hello world", at: .unknown)
|
||||||
let components = token.components()
|
let components = token.components
|
||||||
|
|
||||||
try expect(components.count) == 2
|
try expect(components.count) == 2
|
||||||
try expect(components[0]) == "hello"
|
try expect(components[0]) == "hello"
|
||||||
@@ -16,7 +16,7 @@ class TokenTests: XCTestCase {
|
|||||||
|
|
||||||
$0.it("can split the contents into components with single quoted strings") {
|
$0.it("can split the contents into components with single quoted strings") {
|
||||||
let token = Token.text(value: "hello 'kyle fuller'", at: .unknown)
|
let token = Token.text(value: "hello 'kyle fuller'", at: .unknown)
|
||||||
let components = token.components()
|
let components = token.components
|
||||||
|
|
||||||
try expect(components.count) == 2
|
try expect(components.count) == 2
|
||||||
try expect(components[0]) == "hello"
|
try expect(components[0]) == "hello"
|
||||||
@@ -25,7 +25,7 @@ class TokenTests: XCTestCase {
|
|||||||
|
|
||||||
$0.it("can split the contents into components with double quoted strings") {
|
$0.it("can split the contents into components with double quoted strings") {
|
||||||
let token = Token.text(value: "hello \"kyle fuller\"", at: .unknown)
|
let token = Token.text(value: "hello \"kyle fuller\"", at: .unknown)
|
||||||
let components = token.components()
|
let components = token.components
|
||||||
|
|
||||||
try expect(components.count) == 2
|
try expect(components.count) == 2
|
||||||
try expect(components[0]) == "hello"
|
try expect(components[0]) == "hello"
|
||||||
|
|||||||
Reference in New Issue
Block a user