Skip to content

Commit

Permalink
Merge pull request #2 from MFB-Technologies-Inc/feature/concurrency
Browse files Browse the repository at this point in the history
Resolve concurrency warnings
  • Loading branch information
r-jarvis authored Jun 17, 2024
2 parents 41785a5 + 8e35277 commit 0126cb1
Show file tree
Hide file tree
Showing 14 changed files with 53 additions and 37 deletions.
4 changes: 2 additions & 2 deletions Sources/Stencil/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

public final class TemplateDoesNotExist: Error, CustomStringConvertible {
let templateNames: [String]
let loader: Loader?
let loader: (any Loader & Sendable)?

public init(templateNames: [String], loader: Loader? = nil) {
public init(templateNames: [String], loader: (any Loader & Sendable)? = nil) {
self.templateNames = templateNames
self.loader = loader
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Stencil/FilterTag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class FilterNode: NodeType {
let token: Token?

class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
let bits = token.components
let bits = token.components()

guard bits.count == 2 else {
throw TemplateSyntaxError("'filter' tag takes one argument, the filter expression")
Expand Down
9 changes: 5 additions & 4 deletions Sources/Stencil/ForTag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class ForNode: NodeType {
let token: Token?

class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
var components = token.components
var components = token.components()

var label: String?
if components.first?.hasSuffix(":") == true {
Expand Down Expand Up @@ -237,7 +237,7 @@ struct LoopTerminationNode: NodeType {
}

static func parse(_ parser: TokenParser, token: Token) throws -> LoopTerminationNode {
let components = token.components
let components = token.components()

guard components.count <= 2 else {
throw TemplateSyntaxError("'\(token.contents)' can accept only one parameter")
Expand Down Expand Up @@ -281,8 +281,9 @@ extension TokenParser {
fileprivate func hasOpenedForTag() -> Bool {
var openForCount = 0
for parsedToken in parsedTokens.reversed() where parsedToken.kind == .block {
if parsedToken.components.first == "endfor" { openForCount -= 1 }
if parsedToken.components.first == "for" { openForCount += 1 }
let components = parsedToken.components()
if components.first == "endfor" { openForCount -= 1 }
if components.first == "for" { openForCount += 1 }
}
return openForCount > 0
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/Stencil/IfTag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ class IfNode: NodeType {
let token: Token?

class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
var components = token.components
var components = token.components()
components.removeFirst()

let expression = try parser.compileExpression(components: components, token: token)
Expand All @@ -255,7 +255,7 @@ class IfNode: NodeType {

var nextToken = parser.nextToken()
while let current = nextToken, current.contents.hasPrefix("elif") {
var components = current.components
var components = current.components()
components.removeFirst()
let expression = try parser.compileExpression(components: components, token: current)

Expand All @@ -277,7 +277,7 @@ class IfNode: NodeType {
}

class func parse_ifnot(_ parser: TokenParser, token: Token) throws -> NodeType {
var components = token.components
var components = token.components()
guard components.count == 2 else {
throw TemplateSyntaxError("'ifnot' statements should use the following syntax 'ifnot condition'.")
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Stencil/Include.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class IncludeNode: NodeType {
let token: Token?

class func parse(_: TokenParser, token: Token) throws -> NodeType {
let bits = token.components
let bits = token.components()

guard bits.count == 2 || bits.count == 3 else {
throw TemplateSyntaxError(
Expand Down
4 changes: 2 additions & 2 deletions Sources/Stencil/Inheritance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class ExtendsNode: NodeType {
let token: Token?

class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
let bits = token.components
let bits = token.components()

guard bits.count == 2 else {
throw TemplateSyntaxError("'extends' takes one argument, the template file to be extended")
Expand Down Expand Up @@ -127,7 +127,7 @@ class BlockNode: NodeType {
let token: Token?

class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
let bits = token.components
let bits = token.components()

guard bits.count == 2 else {
throw TemplateSyntaxError("'block' tag takes one argument, the block name")
Expand Down
19 changes: 14 additions & 5 deletions Sources/Stencil/Lexer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,10 @@ struct Lexer {
/// the line.
func rangeLocation(_ range: Range<String.Index>) -> ContentLocation {
guard let line = lines.first(where: { $0.range.contains(range.lowerBound) }) else {
return ("", 0, 0)
return ContentLocation(content: "", lineNumber: 0, lineOffset: 0)
}
let offset = templateString.distance(from: line.range.lowerBound, to: range.lowerBound)
return (line.content, line.number, offset)
return ContentLocation(content: line.content, lineNumber: line.number, lineOffset: offset)
}
}

Expand Down Expand Up @@ -264,7 +264,16 @@ extension String {
}
}

// swiftlint:disable large_tuple
/// Location in some content (text)
public typealias ContentLocation = (content: String, lineNumber: UInt, lineOffset: Int)
// swiftlint:enable large_tuple
public struct ContentLocation: Hashable, Sendable {
public var content: String
public var lineNumber: UInt
public var lineOffset: Int

@inlinable
public init(content: String, lineNumber: UInt, lineOffset: Int) {
self.content = content
self.lineNumber = lineNumber
self.lineOffset = lineOffset
}
}
6 changes: 3 additions & 3 deletions Sources/Stencil/Loader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public protocol Loader {
func loadTemplate(names: [String], environment: Environment) throws -> Template
}

extension Loader {
extension Loader where Self: Sendable {
/// Default implementation, tries to load the first template that exists from the list of given names
public func loadTemplate(names: [String], environment: Environment) throws -> Template {
for name in names {
Expand All @@ -38,7 +38,7 @@ extension Loader {
}

// A class for loading a template from disk
public final class FileSystemLoader: Loader, CustomStringConvertible {
public final class FileSystemLoader: Loader, CustomStringConvertible, Sendable {
public let paths: [Path]

public init(paths: [Path]) {
Expand Down Expand Up @@ -90,7 +90,7 @@ public final class FileSystemLoader: Loader, CustomStringConvertible {
}
}

public class DictionaryLoader: Loader {
public final class DictionaryLoader: Loader, Sendable {
public let templates: [String: String]

public init(templates: [String: String]) {
Expand Down
2 changes: 1 addition & 1 deletion Sources/Stencil/Node.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public class VariableNode: NodeType {
let elseExpression: Resolvable?

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 {
components.count > (index + 1) && components[index] == token
Expand Down
2 changes: 1 addition & 1 deletion Sources/Stencil/NowTag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
class func parse(_: TokenParser, token: Token) throws -> NodeType {
var format: Variable?

let components = token.components
let components = token.components()
guard components.count <= 2 else {
throw TemplateSyntaxError("'now' tags may only have one argument: the format string.")
}
Expand Down
9 changes: 5 additions & 4 deletions Sources/Stencil/Parser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/// Useful for example for scanning until a given "end"-node.
public func until(_ tags: [String]) -> ((TokenParser, Token) -> Bool) {
{ _, token in
if let name = token.components.first {
if let name = token.components().first {
for tag in tags where name == tag {
return true
}
Expand Down Expand Up @@ -65,11 +65,12 @@ public class TokenParser {
return nodes
}

if var tag = token.components.first {
let components = token.components()
if var tag = components.first {
do {
// special case for labeled tags (such as for loops)
if tag.hasSuffix(":"), token.components.count >= 2 {
tag = token.components[1]
if tag.hasSuffix(":"), components.count >= 2 {
tag = components[1]
}

let parser = try environment.findTag(name: tag)
Expand Down
17 changes: 11 additions & 6 deletions Sources/Stencil/Tokenizer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,14 @@ extension String {
}
}

public struct SourceMap: Equatable {
public struct SourceMap: Equatable, Sendable {
public let filename: String?
public let location: ContentLocation

init(filename: String? = nil, location: ContentLocation = ("", 0, 0)) {
init(
filename: String? = nil,
location: ContentLocation = ContentLocation(content: "", lineNumber: 0, lineOffset: 0)
) {
self.filename = filename
self.location = location
}
Expand All @@ -108,8 +111,8 @@ public struct WhitespaceBehaviour: Equatable, Sendable {
public static let unspecified = WhitespaceBehaviour(leading: .unspecified, trailing: .unspecified)
}

public final class Token: Equatable {
public enum Kind: Equatable {
public final class Token: Equatable, Sendable {
public enum Kind: Equatable, Sendable {
/// A token representing a piece of text.
case text
/// A token representing a variable.
Expand All @@ -123,10 +126,12 @@ public final class Token: Equatable {
public let contents: String
public let kind: Kind
public let sourceMap: SourceMap
public var whitespace: WhitespaceBehaviour?
public let whitespace: WhitespaceBehaviour?

/// Returns the underlying value as an array seperated by spaces
public private(set) lazy var components: [String] = self.contents.smartSplit()
public func components() -> [String] {
contents.smartSplit()
}

init(contents: String, kind: Kind, sourceMap: SourceMap, whitespace: WhitespaceBehaviour? = nil) {
self.contents = contents
Expand Down
2 changes: 1 addition & 1 deletion Tests/StencilTests/Helpers/ExampleLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import Stencil

class ExampleLoader: Loader {
final class ExampleLoader: Loader, Sendable {
func loadTemplate(name: String, environment: Environment) throws -> Template {
if name == "example.html" {
return Template(templateString: "Hello World!", environment: environment, name: name)
Expand Down
6 changes: 3 additions & 3 deletions Tests/StencilTests/TokenTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ final class TokenTests: XCTestCase {
func testToken() throws {
_ = {
let token = Token.text(value: "hello world", at: .unknown)
let components = token.components
let components = token.components()

XCTAssertEqual(
components.count,
Expand All @@ -37,7 +37,7 @@ final class TokenTests: XCTestCase {

_ = {
let token = Token.text(value: "hello 'kyle fuller'", at: .unknown)
let components = token.components
let components = token.components()

XCTAssertEqual(
components.count,
Expand All @@ -58,7 +58,7 @@ final class TokenTests: XCTestCase {

_ = {
let token = Token.text(value: "hello \"kyle fuller\"", at: .unknown)
let components = token.components
let components = token.components()

XCTAssertEqual(
components.count,
Expand Down

0 comments on commit 0126cb1

Please sign in to comment.