SParser creates easy to use file or string parsers in swift code using a file format that is based on Backus–Naur form
To user Sparser:
- Create a .sparser file that describes the file format.
- Run SParser to compile the .sparser file to .sparser.swift.
- compile .sparser.swift with the code that uses the .sparser along with SParserLibs.
The SParser parser is written in SParser, which provides an exsample of how to use it. Quotes are from this file. See SParser.sparser.
When compiled, Sparser.sparser generates SParser.sparser.swift
The file contains an optinal imports rule and one or more rules.
The import rule converts each import in to a swift import statement, allowing the generated swift code to use other packages.
SParserLibs provides the Parser, Streams objects required to parse the file. This should always be used.
imports
Foundation
SParserLibs
import Foundation
import SParserLibs
A SParser file contains rules that describe the file format.
Each rule has the following:
- Name
- Type
- One or more patterns.
rules (1)
type (2)
[Rule] (2)
::= rules rule (3)
return rules + [rule] (3)
::= (3)
return [] (3)
rule (1)
type (2)
Rule (2)
::= name "\n" indent type patterns dedent (3)
return Rule(name: name, type: type, patterns: patterns) (3)
Each rule is compiled to a to a Parser typealias of the type, and Parser read function.
extension Parser {
public typealias RuleType = [String]
public func readRule() throws -> RuleType? {
Patterns describe a expected sequence for the rule and an evaluator to run when the pattern matches what is read from the file.
A pattern consists of:
- "::="
- Zero or more terms.
- A evaluator that is ran when the pattern matches.
patterns
type
[Pattern]
::=(1) pattern(2) patterns(2)
return [pattern] + patterns (3)
::=(1) (2)
return [] (3)
pattern
type
Pattern
::=(1) "::="(2) cws(2) terms(2) "\n"(2) multiLineString(2)
return Pattern(terms: terms, evaluator: multiLineString) (3)
Each evaluator is compiled to an eval swift function.
fileprivate func evalPatterns(pattern: Parser.PatternType, patterns: Parser.PatternsType) -> Parser.PatternsType {
return [pattern] + patterns
}
fileprivate func evalPatterns() -> Parser.PatternsType {
return []
}
A Term describes a componet in a pattern. There are two types.
-
String matching terms
string matching terms are strings surounded by ", such as the "::=" term in the pattern rule.
-
Rule matching terms.
Rule matching terms use the name of a rule. This
::= name(1) "\n"(2) indent(2) type(2) patterns(2) dedent(2)
Each term calls it's read function calls:
- Matches(string) for quoted terms
- The generated by the .cparser file
- Parser function named read().
public func readType() throws -> TypeType? {
if matches(string: "type\n") {
if let indent = try readIndent() {
if let line = try readLine() {
if let dedent = try readDedent() {
return try recursivelyRead(type: evalType(indent: indent, line: line, dedent: dedent))
}
try throwError(message:"error parsing type. expect dedent")
}
try throwError(message:"error parsing type. expect line")
}
try throwError(message:"error parsing type. expect indent")
}
return nil
}
set as a dependency in the Package.swift file:
let package = Package(
name: "MyProject",
dependencies: [
.Package(url: "https://github.com/amnykon/SParser.git", majorVersion: 0),
...
]
...
)
Build Sparser
swift build
Run SParser
This will create a .swift file in the same location.
SParser Source/SParserPrivate/SParser.sparser