replaced Token with Lexeme protocol on TemplateSyntaxError
This commit is contained in:
@@ -17,3 +17,29 @@ public class TemplateDoesNotExist: Error, CustomStringConvertible {
|
||||
return "Template named `\(templates)` does not exist. No loaders found"
|
||||
}
|
||||
}
|
||||
|
||||
public struct TemplateSyntaxError : Error, Equatable, CustomStringConvertible {
|
||||
public let description:String
|
||||
var lexeme: Lexeme?
|
||||
|
||||
public init(_ description:String) {
|
||||
self.description = description
|
||||
}
|
||||
|
||||
public static func ==(lhs:TemplateSyntaxError, rhs:TemplateSyntaxError) -> Bool {
|
||||
return lhs.description == rhs.description
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Range where Bound == String.Index {
|
||||
internal static var unknown: Range {
|
||||
return "".range
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
var range: Range<String.Index> {
|
||||
return startIndex..<endIndex
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,8 +53,29 @@ struct Lexer {
|
||||
|
||||
return tokens
|
||||
}
|
||||
|
||||
func lexemeLine(_ lexeme: Lexeme) -> (content: String, number: Int, offset: String.IndexDistance) {
|
||||
var lineNumber: Int = 0
|
||||
var offset = 0
|
||||
var lineContent = ""
|
||||
|
||||
templateString.enumerateLines { (line, stop) in
|
||||
lineNumber += 1
|
||||
lineContent = line
|
||||
if let rangeOfLine = self.templateString.range(of: line), rangeOfLine.contains(lexeme.range.lowerBound) {
|
||||
offset = self.templateString.distance(from: rangeOfLine.lowerBound, to:
|
||||
lexeme.range.lowerBound)
|
||||
stop = true
|
||||
}
|
||||
}
|
||||
return (lineContent, lineNumber, offset)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protocol Lexeme {
|
||||
var range: Range<String.Index> { get }
|
||||
}
|
||||
|
||||
class Scanner {
|
||||
let _content: String //stores original content
|
||||
@@ -163,20 +184,4 @@ extension String {
|
||||
return String(self[first..<last])
|
||||
}
|
||||
|
||||
func lineAndPosition(at range: Range<String.Index>) -> (content: String, number: Int, offset: String.IndexDistance) {
|
||||
var lineNumber: Int = 0
|
||||
var offset = 0
|
||||
var lineContent = ""
|
||||
|
||||
enumerateLines { (line, stop) in
|
||||
lineNumber += 1
|
||||
lineContent = line
|
||||
if let rangeOfLine = self.range(of: line), rangeOfLine.contains(range.lowerBound) {
|
||||
offset = self.distance(from: rangeOfLine.lowerBound, to: range.lowerBound)
|
||||
stop = true
|
||||
}
|
||||
}
|
||||
return (lineContent, lineNumber, offset)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,32 +1,5 @@
|
||||
import Foundation
|
||||
|
||||
|
||||
public struct TemplateSyntaxError : Error, Equatable, CustomStringConvertible {
|
||||
public let description:String
|
||||
public var token: Token?
|
||||
|
||||
public init(_ description:String) {
|
||||
self.description = description
|
||||
}
|
||||
|
||||
public func contextAwareError(templateName: String?, templateContent: String) -> TemplateSyntaxError? {
|
||||
guard let token = token, token.range != .unknown else { return nil }
|
||||
let templateName = templateName.map({ "\($0):" }) ?? ""
|
||||
let (line, lineNumber, offset) = templateContent.lineAndPosition(at: token.range)
|
||||
let tokenContent = templateContent.substring(with: token.range)
|
||||
let highlight = "\(String(Array(repeating: " ", count: offset)))^\(String(Array(repeating: "~", count: max(tokenContent.count - 1, 0))))"
|
||||
let description = "\(templateName)\(lineNumber):\(offset): error: " + self.description + "\n\(line)\n\(highlight)\n"
|
||||
return TemplateSyntaxError(description)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public func ==(lhs:TemplateSyntaxError, rhs:TemplateSyntaxError) -> Bool {
|
||||
return lhs.description == rhs.description
|
||||
}
|
||||
|
||||
|
||||
public protocol NodeType {
|
||||
/// Render the node in the given context
|
||||
func render(_ context:Context) throws -> String
|
||||
|
||||
@@ -53,8 +53,8 @@ public class TokenParser {
|
||||
let node = try parser(self, token)
|
||||
nodes.append(node)
|
||||
} catch {
|
||||
if var syntaxError = error as? TemplateSyntaxError, syntaxError.token == nil {
|
||||
syntaxError.token = token
|
||||
if var syntaxError = error as? TemplateSyntaxError, syntaxError.lexeme == nil {
|
||||
syntaxError.lexeme = token
|
||||
throw syntaxError
|
||||
} else {
|
||||
throw error
|
||||
|
||||
@@ -68,17 +68,8 @@ open class Template: ExpressibleByStringLiteral {
|
||||
func render(_ context: Context) throws -> String {
|
||||
let context = context
|
||||
let parser = TokenParser(tokens: tokens, environment: context.environment)
|
||||
do {
|
||||
let nodes = try parser.parse()
|
||||
return try renderNodes(nodes, context)
|
||||
} catch {
|
||||
if let syntaxError = error as? TemplateSyntaxError,
|
||||
let error = syntaxError.contextAwareError(templateName: name, templateContent: templateString) {
|
||||
throw error
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Render the given template
|
||||
|
||||
@@ -40,19 +40,7 @@ extension String {
|
||||
}
|
||||
}
|
||||
|
||||
extension Range where Bound == String.Index {
|
||||
internal static var unknown: Range {
|
||||
return "".range
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
var range: Range<String.Index> {
|
||||
return startIndex..<endIndex
|
||||
}
|
||||
}
|
||||
|
||||
public enum Token : Equatable {
|
||||
public enum Token : Equatable, Lexeme {
|
||||
/// A token representing a piece of text.
|
||||
case text(value: String, at: Range<String.Index>)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user