All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gapt.expr.util.ExpressionParseHelper.scala Maven / Gradle / Ivy

The newest version!
package gapt.expr.util

import gapt.expr.Const
import gapt.expr.Expr
import gapt.expr.Var
import gapt.expr.formula.Atom
import gapt.expr.formula.Formula
import gapt.expr.formula.fol.FOLAtom
import gapt.expr.formula.fol.FOLConst
import gapt.expr.formula.fol.FOLExpression
import gapt.expr.formula.fol.FOLFormula
import gapt.expr.formula.fol.FOLTerm
import gapt.expr.formula.fol.FOLVar
import gapt.expr.preExpr
import gapt.expr.ty.Ty
import gapt.expr.util.ExpressionParseHelper.Splice
import gapt.formats.babel._
import gapt.proofs.FOLClause
import gapt.proofs.FOLSequent
import gapt.proofs.HOLClause
import gapt.proofs.HOLSequent
import gapt.proofs.Sequent

object ExpressionParseHelper {
  abstract class Splice[+ForType] {
    def spliceIn: preExpr.Expr
  }
  implicit class IdentifierSplice[+T](val ident: String) extends Splice[T] {
    def spliceIn = preExpr.Ident(ident, preExpr.freshMetaType(), None)
  }
  implicit class ExpressionSplice[+ExprType <: Expr](val expr: ExprType) extends Splice[ExprType] {
    def spliceIn = preExpr.QuoteWhitebox(expr)
  }
}

/**
 * Extension class that provides string interpolation functions for various expression types.
 *
 * @param sc A StringContext
 */
class ExpressionParseHelper(sc: StringContext, file: sourcecode.File, line: sourcecode.Line, sig: BabelSignature) {
  private implicit def _sig: BabelSignature = sig

  private def interpolateHelper(expressions: Seq[Splice[Expr]]): (String, preExpr.Expr => preExpr.Expr) = {
    def repls(name: String): preExpr.Expr =
      expressions(name.drop(placeholder.length).toInt).spliceIn
    def repl(expr: preExpr.Expr): preExpr.Expr = expr match {
      case preExpr.LocAnnotation(e, loc)                            => preExpr.LocAnnotation(repl(e), loc)
      case preExpr.TypeAnnotation(e, ty)                            => preExpr.TypeAnnotation(repl(e), ty)
      case preExpr.Ident(name, _, _) if name startsWith placeholder => repls(name)
      case expr: preExpr.Ident                                      => expr
      case preExpr.Abs(v, sub) =>
        repl(v) match {
          case vNew @ preExpr.Ident(_, _, _) => // If repl(v) = v.
            preExpr.Abs(vNew, repl(sub))
          case preExpr.Quoted(Var(vNew, _), ty, _) => // If repl(v) = v'.
            preExpr.Abs(preExpr.Ident(vNew, ty, None), repl(sub))
          case _ => // Otherwise
            throw new IllegalArgumentException("Trying to substitute non-variable term in binding.")
        }
      case preExpr.App(a, b)    => preExpr.App(repl(a), repl(b))
      case expr: preExpr.Quoted => expr
      case preExpr.FlatOps(children) => preExpr.FlatOps(children.map {
          case Left((n, loc)) if n.startsWith(placeholder) => Right(preExpr.LocAnnotation(repls(n), loc))
          case tok @ Left(_)                               => tok
          case Right(e)                                    => Right(repl(e))
        })
    }

    (sc.parts.init.zipWithIndex.map { case (s, i) => s + " " + placeholder + i + " " }.mkString ++ sc.parts.last, repl)
  }

  private def interpolate(args: Seq[Splice[Expr]], baseAstTransformer: preExpr.Expr => preExpr.Expr): Expr = {
    val (combined, repl) = interpolateHelper(args)

    def astTransformer(expr: preExpr.Expr): preExpr.Expr = baseAstTransformer(repl(expr))

    BabelParser.tryParse(combined, astTransformer) match {
      case Left(error) => throw new IllegalArgumentException(
          s"Parse error at ${file.value}:${line.value}:\n${error.getMessage}"
        )
      case Right(expr) => expr
    }
  }

  def ty(args: Nothing*): Ty =
    BabelParser.tryParseType(sc.parts.mkString) match {
      case Left(error) => throw new IllegalArgumentException(
          s"Parse error at ${file.value}:${line.value}:\n${error.getMessage}"
        )
      case Right(ty) => ty
    }

  // Higher order parsers

  /**
   * Parses a string as a [[Expr]].
   *
   */
  def le(args: Splice[Expr]*): Expr = interpolate(args, identity)

  /**
   * Parses a string as a [[gapt.expr.formula.Formula]].
   *
   * @param args
   * @return
   */
  def hof(args: Splice[Expr]*): Formula = interpolate(args, preExpr.TypeAnnotation(_, preExpr.Bool)).asInstanceOf[Formula]

  /**
   * Parses a string as a [[gapt.expr.formula.Atom]].
   *
   * @param args
   * @return
   */
  def hoa(args: Splice[Expr]*): Atom = hof(args: _*) match {
    case atom: Atom => atom
    case expr =>
      throw new IllegalArgumentException(s"Expression $expr appears not to be a HOL atom. Parse it with hof.")
  }

  /**
   * Parses a string as a [[Var]].
   *
   * @param args
   * @return
   */
  def hov(args: Splice[Expr]*): Var = le(args: _*) match {
    case v: Var => v
    case expr =>
      throw new IllegalArgumentException(s"Expression $expr cannot be read as a variable. Parse it with le.")
  }

  /**
   * Parses a string as a [[Const]].
   *
   * @param args
   * @return
   */
  def hoc(args: Splice[Expr]*): Const = le(args: _*) match {
    case c: Const  => c
    case Var(n, t) => Const(n, t)
    case expr =>
      throw new IllegalArgumentException(s"Expression $expr cannot be read as a constant. Parse it with le.")
  }

  // First order parsers

  /**
   * Parses a string as a [[gapt.expr.formula.fol.FOLExpression]].
   *
   * @param args
   * @return
   */
  def foe(args: Splice[FOLExpression]*): FOLExpression = le(args: _*) match {
    case folExpression: FOLExpression => folExpression
    case expr =>
      throw new IllegalArgumentException(s"Expression $expr appears not to be a FOL expression. Parse it with le.")
  }

  /**
   * Parses a string as a [[gapt.expr.formula.fol.FOLFormula]].
   *
   * @param args
   * @return
   */
  def fof(args: Splice[FOLExpression]*): FOLFormula = hof(args: _*) match {
    case formula: FOLFormula => formula
    case expr =>
      throw new IllegalArgumentException(s"Formula $expr appears not to be a FOL formula. Parse it with hof.")
  }

  /**
   * Parses a string as a [[gapt.expr.formula.fol.FOLAtom]].
   *
   * @param args
   * @return
   */
  def foa(args: Splice[FOLExpression]*): FOLAtom = fof(args: _*) match {
    case atom: FOLAtom => atom
    case expr =>
      throw new IllegalArgumentException(s"Formula $expr appears not to be an atom. Parse it with fof.")
  }

  /**
   * Parses a string as a [[gapt.expr.formula.fol.FOLTerm]].
   *
   * @param args
   * @return
   */
  def fot(args: Splice[FOLTerm]*): FOLTerm = le(args: _*) match {
    case term: FOLTerm => term
    case expr =>
      throw new IllegalArgumentException(s"Expression $expr appears not to be FOL term. Parse it with le.")
  }

  /**
   * Parses a string as a [[gapt.expr.formula.fol.FOLVar]].
   *
   * @param args
   * @return
   */
  def fov(args: Splice[FOLTerm]*): FOLVar = le(args: _*) match {
    case Var(n, _) => FOLVar(n)
    case expr =>
      throw new IllegalArgumentException(s"Term $expr cannot be read as a FOL variable. Parse it with fot.")
  }

  /**
   * Parses a string as a [[gapt.expr.formula.fol.FOLConst]].
   *
   * @param args
   * @return
   */
  def foc(args: Splice[FOLTerm]*): FOLConst = fot(args: _*) match {
    case c: FOLConst => c
    case expr =>
      throw new IllegalArgumentException(s"Term $expr cannot be read as a FOL constant. Parse it with fot.")
  }

  /** Parses a string as a [[gapt.proofs.HOLSequent]]. */
  def hos(args: Splice[Expr]*): HOLSequent = {
    val (combined, repl) = interpolateHelper(args)

    BabelParser.tryParseSequent(combined, e => preExpr.TypeAnnotation(repl(e), preExpr.Bool)) match {
      case Left(error) => throw new IllegalArgumentException(
          s"Parse error at ${file.value}:${line.value}:\n${error.getMessage}"
        )
      case Right(sequent) => sequent.map(_.asInstanceOf[Formula])
    }
  }

  /** Parses a string as a labelled sequent. */
  def hols(args: Splice[Expr]*): Sequent[(String, Formula)] = {
    val (combined, repl) = interpolateHelper(args)

    BabelParser.tryParseLabelledSequent(combined, repl) match {
      case Left(error) => throw new IllegalArgumentException(
          s"Parse error at ${file.value}:${line.value}:\n${error.getMessage}"
        )
      case Right(sequent) => sequent
    }
  }

  /** Parses a string as a [[gapt.proofs.HOLClause]]. */
  def hcl(args: Splice[Expr]*): HOLClause = hos(args: _*).map(_.asInstanceOf[Atom])

  /** Parses a string as a [[gapt.proofs.FOLSequent]]. */
  def fos(args: Splice[Expr]*): FOLSequent = hos(args: _*).map(_.asInstanceOf[FOLFormula])

  /** Parses a string as a [[gapt.proofs.FOLClause]]. */
  def fcl(args: Splice[Expr]*): FOLClause = hos(args: _*).map(_.asInstanceOf[FOLAtom])

  private def placeholder = "__qq_"
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy