Skip to content

Commit

Permalink
Add documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Lippo committed Jan 13, 2021
1 parent 13c7e08 commit ca2d7fb
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 81 deletions.
Expand Up @@ -18,7 +18,7 @@ case class GrammarGenerator(verbs: Verb*) extends Generator {

case class ItemGenerator(items: Model#Item*) extends Generator {

import io.github.scalaquest.core.parsing.engine.dsl._
import io.github.scalaquest.core.parsing.engine.clause.dsl._

def np: CompoundBuilder = CompoundBuilder("np")

Expand Down
Expand Up @@ -20,7 +20,7 @@ sealed trait Verb {

object Verb {
import io.github.scalaquest.core.parsing.engine._
import io.github.scalaquest.core.parsing.engine.dsl._
import io.github.scalaquest.core.parsing.engine.clause.dsl._

def betaReduce(functor: String, variablesNum: Int): Term = {
@tailrec
Expand Down
@@ -0,0 +1,150 @@
package io.github.scalaquest.core.parsing.engine

/** A Prolog clause. */
sealed trait Clause {

/** String representation of the `Clause`. */
def generate: String
}

/** A Prolog term. */
sealed trait Term extends Clause {

/**
* Template method for all infix operators.
*
* @note All operators that use this method should be right associative.
*/
protected def infixOp(op: String)(left: Term): Compound = Compound(Atom(op), left, List(this))

/** Implementation of the infix `^` Prolog operator. */
def ^:(left: Term): Compound = infixOp("^")(left)

/** Implementation of the infix `/` Prolog operator. */
def /:(left: Term): Compound = infixOp("/")(left)
}

/** A Prolog atom. */
case class Atom(name: String) extends Term {
override def generate: String = name
}

/** A Prolog number */
case class Number(n: Int) extends Term {
override def generate: String = n.toString
}

/** A Prolog variable. */
case class Variable(name: String) extends Term {
override def generate: String = name
}

/**
* A Prolog compound term.
* @param functor the atom used as a functor
* @param arg1 the first mandatory term
* @param args the other optional terms
*/
case class Compound(functor: Atom, arg1: Term, args: List[Term] = List()) extends Term {
override def generate: String = s"${functor.generate}(${(arg1 +: args).map(_.generate).mkString(",")})"
}

/** A Prolog list. */
case class ListP(terms: Term*) extends Term {
override def generate: String = terms.map(_.generate).mkString("[", ",", "]")
}

/** A Prolog fact. */
case class Fact(body: Term) extends Clause {

/**
* Allows the creation of a [[DCGRule]].
* @param right the right side of the operation
* @return the resulting DCG rule.
*/
def -->(right: Term): DCGRule = DCGRule(body, right)

// def :-(right: Term): Rule = Rule(body, right)

override def generate: String = s"${body.generate}."
}

//case class Rule(head: Term, body: Term) extends Clause {
// override def generate: String = s"${head.generate} :- ${body.generate}."
//}

/**
* A declarative clause grammar rule.
* @param left the left term
* @param right the right term
*
* Example:
* {{{
* DCGRule(Compound(Atom("ciao"), Atom("mondo")), ListP(Atom("ciao"), Atom("mondo"))).generate
* }}}
*
* Should result in the following Prolog clause being printed:
* {{{
* hello(world) --> ["hello","world"].
* }}}
*/
case class DCGRule(left: Term, right: Term) extends Clause {
override def generate: String = s"${left.generate} --> ${right.generate}."
}

/** This object is mimicking a package declaration. */
object clause {

/**
* This package includes some facility methods in order to create terms in a
* Prolog-like syntax.
*
* Example:
* {{{
* val hello = CompoundBuilder("hello")
* val X = Variable("X")
* (hello(X) --> ListP("hello", X)).generate
* }}}
*
* Should result in the following Prolog clause being printed:
* {{{
* hello(X) --> ["hello", X].
* }}}
*/
object dsl {

/**
* A `CompoundBuilder` allows the generation of compound terms using a
* Prolog-like syntax that is checked by the scala compiler.
* @param functor the atom used as a functor by the generated compound terms
*
* Example:
* {{{
* val hello = CompoundTerm(Atom("hello"))
* (hello(Atom("darkness"), Atom("my"), Atom("old"), Atom("friend"))).generate
* }}}
*
* Should result in the following compound term being printed:
* {{{
* hello(darkness, my, old, friend)
* }}}
*/
case class CompoundBuilder(functor: Atom) {

/**
* This method allows to simulate the Prolog compound term declaration.
* @param arg the first mandatory term
* @param args the other optional terms
* @return a [[Compound]] which has `functor` as functor and the arguments
* as the compound term arguments.
*/
def apply(arg: Term, args: Term*): Compound = Compound(functor, arg, args.toList)
}

implicit def stringToAtom(name: String): Atom = Atom(name)
implicit def intToNumber(n: Int): Number = Number(n)
implicit def termToFact(term: Term): Fact = Fact(term)
implicit def seqToListP(seq: Seq[Term]): ListP = ListP(seq: _*)

}
}

This file was deleted.

Expand Up @@ -4,7 +4,7 @@ import alice.tuprolog.{Library => TuPrologLibrary}
import alice.tuprolog.lib.{DCGLibrary => TuPrologDCGLibrary}

/** Representation of a Prolog library */
sealed trait BaseLibrary
abstract class BaseLibrary

/** A tuProlog enabled library */
trait TuProlog { self: BaseLibrary =>
Expand Down
@@ -1,18 +1,12 @@
package io.github.scalaquest.core.parsing.engine.exceptions

trait InvalidTheoryException extends Throwable {

def line: Int

def pos: Int
}
/**
* An exception that is thrown if an [[io.github.scalaquest.core.parsing.engine.Engine]]
* was provided an invalid theory.
*/
case class InvalidTheoryException(line: Int, pos: Int) extends Throwable

object InvalidTheoryException {

def apply(e: alice.tuprolog.InvalidTheoryException): InvalidTheoryException =
new InvalidTheoryException() {
override def line: Int = e.line

override def pos: Int = e.pos
}
def apply(e: alice.tuprolog.InvalidTheoryException): InvalidTheoryException = InvalidTheoryException(e.line, e.pos)
}
Expand Up @@ -6,23 +6,23 @@ import io.github.scalaquest.core.pipeline.lexer.LexerResult
case class SimpleParserResult(tree: AbstractSyntaxTree) extends ParserResult

/**
* A [[Parser]] implementation that takes advantage of an [[Engine]] in order
* A [[Parser]] implementation that takes advantage of an [[io.github.scalaquest.core.parsing.engine.Engine]] in order
* to perform the syntactical analysis.
*/
abstract class PrologParser extends Parser {

/** The [[Engine]] used. */
/** The [[io.github.scalaquest.core.parsing.engine.Engine]] used. */
protected def engine: Engine

object dsl {
import io.github.scalaquest.core.parsing.engine.dsl._
import io.github.scalaquest.core.parsing.engine.clause.dsl._
val X = Variable("X")
val i = CompoundBuilder("i")
val phrase = CompoundBuilder("phrase")
}

override def parse(lexerResult: LexerResult): Option[ParserResult] = {
import io.github.scalaquest.core.parsing.engine.dsl.seqToListP
import io.github.scalaquest.core.parsing.engine.clause.dsl.seqToListP
import dsl._
val tokens = lexerResult.tokens.map(Atom)
val query = phrase(i(X), tokens)
Expand Down
Expand Up @@ -83,7 +83,7 @@ class ClausesTest extends AnyWordSpec {
}

"Compound builder" should {
import io.github.scalaquest.core.parsing.engine.dsl.CompoundBuilder
import io.github.scalaquest.core.parsing.engine.clause.dsl.CompoundBuilder
val hello = CompoundBuilder(Atom("hello"))

"allow for the creation of a compound term" in {
Expand All @@ -103,7 +103,7 @@ class ClausesTest extends AnyWordSpec {
}

"Implicit operators" should {
import io.github.scalaquest.core.parsing.engine.dsl._
import io.github.scalaquest.core.parsing.engine.clause.dsl._
val hello = CompoundBuilder(Atom("hello"))
"allow the usage of strings as atoms" in {
assert(hello("world") == Compound(Atom("hello"), Atom("world")))
Expand Down

0 comments on commit ca2d7fb

Please sign in to comment.