Swift 解析器组合器框架
除了简单的组合器,Parsey 还支持源位置/范围跟踪、回溯预防和自定义错误消息。
组合器接口
|
, ~~
, ~~>
, <~~
, ^^
组合器运算符词法分析器原语
Lexer.whitespace
, Lexer.signedInteger
, ...类似正则表达式的组合器
.+
用于 .many()
。let arrayLiteral = "[" ~~> expression.+ <~~ "]"
.*
用于 .manyOrNone()
。let classDef = (attribute | method).*
.?
用于 .optional()
。let declaration = "let" ~~> id ~~ (":" ~~> type).? ~~ ("=" ~~> expression)
+
用于 .manyConcatenated()
。let skippedSpaces = (Lexer.space | Lexer.tab)+
+
用于 .concatenatingResult(with:)
。let type = Lexer.upperLetter + Lexer.letter*
Lexer.regex(_:)
用于直接应用正则表达式。let id = Lexer.regex("[a-zA-Z][a-zA-Z0-9]*")
回溯预防
.!
后缀运算符或 .nonbacktracking()
解析器标记,用于错误消息
<!--
运算符或 .tagged(_:)
带有源位置的丰富错误消息
Parse failure at 2:4 ----
(+ %% 1 -20) 2 3)
^~~~~~~~~~~~~~
Expecting an expression, but found "%"
源范围跟踪
^^^
运算符或 .mapParse(_:)
\n(+ \n\n(+ +1 -20) 2 3)
被解析为以下范围跟踪的 ASTExpr:(2:1..<4:16):[
ID:(2:2..<2:3):+,
Expr:(4:1..<4:11):[
ID:(4:2..<4:3):+,
Int:(4:4..<4:6):1,
Int:(4:7..<4:10):-20],
Int:(4:12..<4:13):2,
Int:(4:14..<4:15):3]
Swift 3
任何操作系统
要在您的 Swift 项目中使用它,请将以下依赖项添加到您的 Swift 包描述文件中。
.Package(url: "https://github.com/rxwei/Parsey", majorVersion: 1)
indirect enum Expression {
case integer(Int)
case symbol(String)
case infix(String, Expression, Expression)
}
enum Grammar {
static let integer = Lexer.signedInteger
^^ {Int($0)!} ^^ Expression.integer
static let symbol = Lexer.regex("[a-zA-Z][0-9a-zA-Z]*")
^^ Expression.symbol
static let addOp = Lexer.anyCharacter(in: "+-")
^^ { op in { Expression.infix(op, $0, $1) } }
static let multOp = Lexer.anyCharacter(in: "*/")
^^ { op in { Expression.infix(op, $0, $1) } }
/// Left-associative multiplication
static let multiplication = (integer | symbol).infixedLeft(by: multOp)
/// Left-associative addition
static let addition = multiplication.infixedLeft(by: addOp)
static let expression: Parser<Expression> = addition
}
try print(Grammar.expression.parse("2"))
/// Output:
/// Expression.integer(2)
try print(Grammar.expression.parse("2+1+2*a"))
/// Output:
/// Expression.infix("+",
/// .infix("+", .integer(2), .integer(1)),
/// .infix("*", .integer(2), .symbol("a")))
indirect enum Expr {
case sExp([Expr])
case int(Int)
case id(String)
}
enum Grammar {
static let whitespaces = (Lexer.space | Lexer.tab | Lexer.newLine)+
static let anInt = Lexer.signedInteger ^^ { Int($0)! } ^^ Expr.int
static let anID = Lexer.regex("[a-zA-Z_+\\-*/][0-9a-zA-Z_+\\-*/]*") ^^ Expr.id
static let aSExp: Parser<Expr> =
"(" ~~> (anExp.!).many(separatedBy: whitespaces).amid(whitespaces.?) <~~ ")"
^^ Expr.sExp
static let anExp = anInt | anID | aSExp <!-- "an expression"
}
/// Success
try Grammar.anExp.parse("(+ (+ 1 -20) 2 3)")
/// Output: Expr.sExp(...)
/// Failure
try Grammar.anExp.parse("(+ \n(+ %% 1 -20) 2 3)")
/// Output: Parse failure at 2:4 ----
/// (+ %% 1 -20) 2 3)
/// ^~~~~~~~~~~~~~
/// Expecting an expression, but found "%"
indirect enum Expr {
case sExp([Expr], SourceRange)
case int(Int, SourceRange)
case id(String, SourceRange)
}
enum Grammar {
static let whitespaces = (Lexer.space | Lexer.tab | Lexer.newLine)+
static let anInt = Lexer.signedInteger
^^^ { Expr.int(Int($0.target)!, $0.range) }
static let anID = Lexer.regex("[a-zA-Z_+\\-*/][0-9a-zA-Z_+\\-*/]*")
^^^ { Expr.id($0.target, $0.range) }
static let aSExp: Parser<Expr> =
"(" ~~> (anExp.!).many(separatedBy: whitespaces).amid(whitespaces.?) <~~ ")"
^^^ { Expr.sExp($0.target, $0.range) }
static let anExp = anInt | anID | aSExp <!-- "an expression"
}
/// Success
try Grammar.anExp.parse("(+ (+ 1 -20) 2 3)")
/// Output: Expr.sExp(...)
/// Failure
try Grammar.anExp.parse("(+ \n(+ %% 1 -20) 2 3)")
/// Output: Parse failure at 2:4 ----
/// (+ %% 1 -20) 2 3)
/// ^~~~~~~~~~~~~~
/// Expecting an expression, but found "%"
MIT 许可证