gapt.formats.lisp.SExpression.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gapt_3 Show documentation
Show all versions of gapt_3 Show documentation
General Architecture for Proof Theory
The newest version!
package gapt.formats.lisp
import gapt.formats.{InputFile, lisp}
import gapt.utils.Doc
import org.parboiled2._
import scala.util.{Failure, Success, Try}
/**
* Lisp SExpression Datatypes and Parser
* This is a basic LISP S-expression parser, without quote character, macros or other fancy stuff.
* Atoms have a reduced namespace and need to be extended if necessary.
*
* Printing a Datastructure should output valid Lisp.
*/
sealed abstract class SExpression {
def toDoc: Doc
override def toString: String = toDoc.render(80)
}
sealed abstract class LAtom extends SExpression
case class LKeyword(name: String) extends LAtom {
def toDoc = Doc.text(s":$name")
}
case class LSymbol(name: String) extends LAtom {
def toDoc = Doc.text {
name match {
case "" => "||"
case LSymbol.needsToBeEscaped() =>
"|" + name.replace("\\", "\\\\").replace("|", "\\|") + "|"
case _ => name
}
}
}
object LSymbol extends (String => LAtom) {
private val needsToBeEscaped = ".*[\n\r\t\f \")(;:|\\\\].*".r
}
case class LList(elements: SExpression*) extends SExpression {
def ::(head: SExpression) = LList(head +: elements: _*)
def ++(list2: LList) = LList(elements ++ list2.elements: _*)
def toDoc =
(Doc.text("(") <> Doc.wordwrap2(elements.map(_.toDoc), "") <> ")").nest(2).group
}
object LList {
def apply(elements: Iterable[SExpression]): LList =
LList(elements.toSeq: _*)
}
object LFun {
def apply(head: String, args: SExpression*): LList =
LList((LSymbol(head) +: args): _*)
def unapplySeq(list: LList): Option[(String, Seq[SExpression])] = list match {
case LList(LSymbol(head), args @ _*) => Some(head, args)
case _ => None
}
}
object LFunOrAtom {
def unapplySeq(expression: SExpression): Option[(String, Seq[SExpression])] = expression match {
case LFun(name, args @ _*) => Some(name, args)
case LSymbol(name) => Some(name, Seq())
case _ => None
}
}
case class LCons(car: SExpression, cdr: SExpression) extends SExpression {
def toDoc = (Doc.text("(") <> car.toDoc <+> "." > cdr.toDoc <> ")").nest(2).group
}
object SExpressionParser {
def parse(fn: InputFile): List[SExpression] = {
val parser = new SExpressionParser(fn.read)
parser.File.run() match {
case Failure(error: ParseError) =>
throw new IllegalArgumentException(parser.formatError(error))
case Failure(exception) => throw exception
case Success(value) => value.toList
}
}
def tryParse(fn: InputFile): Try[List[SExpression]] =
new SExpressionParser(fn.read).File.run().map { _.toList }
private class SExpressionParser(val input: ParserInput) extends Parser {
private def WhiteSpace = rule { zeroOrMore(anyOf(" \n\r\t\f") | (';' ~ zeroOrMore(noneOf("\n")))) }
private def Str = rule { '"' ~ capture(zeroOrMore(noneOf("\""))) ~ '"' ~ WhiteSpace ~> { lisp.LSymbol(_) } }
private def Symbol = rule {
capture('.' ~ oneOrMore(noneOf("() |\n\r\t\f;\""))) ~ WhiteSpace ~> { lisp.LSymbol(_) } |
capture(noneOf(".:() |\n\r\t\f;\"") ~ zeroOrMore(noneOf("() |\n\r\t\f;\""))) ~ WhiteSpace ~> { lisp.LSymbol(_) }
}
private def QuotedSymbolEscapeSequence: Rule0 = rule { '\\' ~ (ch('|') | '\\') }
private def QuotedSymbolBody: Rule1[String] = rule {
zeroOrMore(
capture(QuotedSymbolEscapeSequence) ~> { _.substring(1) } |
capture(noneOf("\\|"))
) ~> { (_: Seq[String]).mkString("") }
}
private def QuotedSymbol = rule {
'|' ~ QuotedSymbolBody ~ '|' ~ WhiteSpace ~> { lisp.LSymbol(_) }
}
private def Keyword = rule {
':' ~ capture(oneOrMore(noneOf(":() |\n\r\t\f;\""))) ~ WhiteSpace ~> {
lisp.LKeyword(_)
}
}
private def SExpr: Rule1[lisp.SExpression] = rule {
(Str | QuotedSymbol | Symbol | Keyword | Parens2 | Parens1)
}
private def Parens2 = rule {
'(' ~ WhiteSpace ~ optional(oneOrMore(SExpr) ~> { ts => LList(ts) }) ~ ')' ~ WhiteSpace ~> { _.getOrElse(LList()) }
}
private def Parens1 = rule {
('(' ~ WhiteSpace ~ SExpr ~ '.' ~ WhiteSpace ~ SExpr ~ ')' ~ WhiteSpace) ~> {
LCons(_, _)
}
}
def File: Rule1[Seq[lisp.SExpression]] = rule { WhiteSpace ~ zeroOrMore(SExpr) ~ EOI }
}
}