diff --git a/documentatie/verslag.tex b/documentatie/verslag.tex index 49c1846..9eefcda 100644 --- a/documentatie/verslag.tex +++ b/documentatie/verslag.tex @@ -1,17 +1,126 @@ %! Author = tdpeuter %! Date = 27/03/2025 -% Preamble -\documentclass[11pt]{article} +\documentclass[11pt,a4paper]{article} -% Packages \usepackage{amsmath} +\usepackage[dutch]{babel} % Nederlands taal +\usepackage{enumitem} % Aanpasbare lijsten +\usepackage[margin=1in]{geometry} % Sane marges +\usepackage{multicol} % Meerdere kolommen + +\title{Ghent Prolog} +\author{Tibo De Peuter} +\date{\today} % Document \begin{document} + \maketitle % Lexer op basis van https://craftinginterpreters.com/scanning.html + \appendix + \newpage + \section{Geïmplementeerde predicaten}\label{sec:predicaten} + + \begin{multicols}{2} + \begin{itemize}[label={}] + \item \textbf{Analysing and Constructing Terms} + \begin{itemize} + \item \texttt{functor/3} + \item \texttt{arg/3} + \item \texttt{=..} + \item \texttt{numbervars/1} + \item \texttt{numbervars/3} + \end{itemize} + \item \textbf{Arithmetic} + \begin{itemize} + \item \texttt{between/3} + \item \texttt{succ/2} + \item \texttt{plus/3} + \item \texttt{=\textbackslash=/2} + \item \texttt{=:=/2} + \item \texttt{is/2} + \item \texttt{-/1} + \item \texttt{+/1} + \item \texttt{+/2} + \item \texttt{*/2} + \item \texttt{//2} + \item \texttt{inf/0} + \end{itemize} + \item \textbf{Comparison and Unification of Terms} + \begin{itemize} + \item \texttt{=/2} + \item \texttt{\textbackslash=/2} + \item \texttt{==/2} + \item \texttt{\textbackslash==/2} + \end{itemize} + \item \textbf{Control Predicates} + \begin{itemize} + \item \texttt{fail/0} + \item \texttt{false/0} + \item \texttt{true/0} + \item \texttt{!/0} + \item \texttt{,/2} + \item \texttt{;/2} + \item \texttt{|/2} + \item \texttt{\textbackslash+/1} + \end{itemize} + \item \textbf{Database} + \begin{itemize} + \item \texttt{retract/1} + \item \texttt{retractall/1} + \item \texttt{asserta/1} + \item \texttt{assertz/1} + \item \texttt{assert/1} + \end{itemize} + \item \textbf{Declaring predicate properties} + \begin{itemize} + \item \texttt{dynamic/1} + \end{itemize} + \item \textbf{Delimited continuations} + \begin{itemize} + \item \texttt{reset/3} + \item \texttt{shift/1} + \end{itemize} + \item \textbf{Examining the program} + \begin{itemize} + \item \texttt{clause/2} + \end{itemize} + \item \textbf{Forall} + \begin{itemize} + \item \texttt{forall/2} + \end{itemize} + \item \textbf{Loading Prolog source files} + \begin{itemize} + \item \texttt{consult/1} + \item \texttt{initialization/1} + \end{itemize} + \item \textbf{Meta-Call Predicates} + \begin{itemize} + \item \texttt{call/1} + \item \texttt{once/1} + \item \texttt{ignore/1} + \end{itemize} + \item \textbf{Primitive character I/O} + \begin{itemize} + \item \texttt{nl/0} + \end{itemize} + \item \textbf{Term reading and writing} + \begin{itemize} + \item \texttt{write/1} + \item \texttt{writeln/1} + \item \texttt{read/1} + \end{itemize} + \item \textbf{Verify Type of a Term} + \begin{itemize} + \item \texttt{var/1} + \item \texttt{nonvar/1} + \item \texttt{atom/1} + \item \texttt{compound/1} + \end{itemize} + \end{itemize} + \end{multicols} \end{document} \ No newline at end of file diff --git a/src/interpreter/Preprocessor.kt b/src/interpreter/Preprocessor.kt index 19d8f2b..fb72dcf 100644 --- a/src/interpreter/Preprocessor.kt +++ b/src/interpreter/Preprocessor.kt @@ -107,6 +107,10 @@ open class Preprocessor { Successor(args[0] as Expression, args[1] as Expression) } else term + Functor.of("plus/3") -> if (args.all { it is Expression }) { + Plus(args[0] as Expression, args[1] as Expression, args[2] as Expression) + } else term + // Control Functor.of("fail/0") -> Fail Functor.of("false/0") -> False @@ -158,12 +162,16 @@ open class Preprocessor { Functor.of("member/2") -> Member(args[0], args[1]) Functor.of("append/3") -> Append(args[0], args[1], args[2]) + // Loading + Functor.of("consult/1") -> Consult(args[0]) + Functor.of("initialization/1") -> Initialization(args[0] as Goal) + // Meta Functor.of("call/1") -> Call(args[0]) + Functor.of("once/1") -> Once(args[0] as Goal) Functor.of("ignore/1") -> Ignore(args[0] as Goal) // Other - Functor.of("initialization/1") -> Initialization(args[0] as Goal) Functor.of("forall/2") -> ForAll(args[0] as LogicOperand, args[1] as Goal) // Unification diff --git a/src/prolog/builtins/arithmeticOperators.kt b/src/prolog/builtins/arithmeticOperators.kt index 2a3b1fd..dbdccf4 100644 --- a/src/prolog/builtins/arithmeticOperators.kt +++ b/src/prolog/builtins/arithmeticOperators.kt @@ -122,6 +122,11 @@ open class Add(private val expr1: Expression, private val expr2: Expression) : ) } +class Plus(private val expr1: Expression, private val expr2: Expression, private val expr3: Expression) : + CompoundTerm("plus", expr1, expr2, expr3) { + override fun satisfy(subs: Substitutions): Answers = plus(expr1, expr2, expr3, subs) +} + /** * Result = Expr1 - Expr2 */ diff --git a/src/prolog/builtins/delimitedContinuationsOperators.kt b/src/prolog/builtins/delimitedContinuationsOperators.kt index b6d18fa..43f6e22 100644 --- a/src/prolog/builtins/delimitedContinuationsOperators.kt +++ b/src/prolog/builtins/delimitedContinuationsOperators.kt @@ -3,7 +3,6 @@ package prolog.builtins import prolog.Answers import prolog.Substitutions import prolog.ast.arithmetic.Integer -import prolog.ast.terms.Atom import prolog.ast.terms.Goal import prolog.ast.terms.Structure import prolog.ast.terms.Term diff --git a/src/prolog/builtins/loadingSourceOperators.kt b/src/prolog/builtins/loadingSourceOperators.kt new file mode 100644 index 0000000..0f002f3 --- /dev/null +++ b/src/prolog/builtins/loadingSourceOperators.kt @@ -0,0 +1,39 @@ +package prolog.builtins + +import interpreter.FileLoader +import prolog.Answers +import prolog.Substitutions +import prolog.ast.logic.LogicOperand +import prolog.ast.logic.LogicOperator +import prolog.ast.terms.Atom +import prolog.ast.terms.Operator +import prolog.ast.terms.Term +import prolog.logic.applySubstitution + +class Consult(val file: Term) : Operator("consult", rightOperand = file) { + private val fileLoader = FileLoader() + + override fun satisfy(subs: Substitutions): Answers { + val fileAtom = applySubstitution(file, subs) + require(fileAtom is Atom) { "File name must be an atom" } + + var filePath = fileAtom.name + if (!filePath.endsWith(".pl")) { + filePath += ".pl" + } + + try { + fileLoader.load(filePath) + return sequenceOf(Result.success(emptyMap())) + } catch (e: Exception) { + return sequenceOf(Result.failure(e)) + } + } + + override fun toString(): String = "consult($file)" +} + +class Initialization(val goal: LogicOperand) : LogicOperator(":-", rightOperand = goal) { + override fun satisfy(subs: Substitutions): Answers = goal.satisfy(subs).take(1) + override fun toString(): String = goal.toString() +} diff --git a/src/prolog/builtins/metaOperators.kt b/src/prolog/builtins/metaOperators.kt index 2477c26..3abbabb 100644 --- a/src/prolog/builtins/metaOperators.kt +++ b/src/prolog/builtins/metaOperators.kt @@ -2,7 +2,6 @@ package prolog.builtins import prolog.Answers import prolog.Substitutions -import prolog.ast.terms.Atom import prolog.ast.terms.Goal import prolog.ast.terms.Operator import prolog.ast.terms.Term @@ -16,10 +15,18 @@ class Call(private val goal: Term) : Operator("call", rightOperand = goal) { } } +/** + * Make a possibly nondeterministic [Goal] semideterministic, i.e. succeed at most once. + */ +class Once(private val goal: Term) : Operator("once", rightOperand = goal) { + private val conjunction = Conjunction(Call(goal), Cut()) + override fun satisfy(subs: Substitutions): Answers = conjunction.satisfy(subs).take(1) +} + /** * Calls [Goal] once, but succeeds, regardless of whether Goal succeeded or not. */ -class Ignore(goal: Goal) : Operator("ignore", rightOperand = goal) { +class Ignore(goal: Term) : Operator("ignore", rightOperand = goal) { private val disjunction = Disjunction( Conjunction(Call(goal), Cut()), True diff --git a/src/prolog/builtins/other.kt b/src/prolog/builtins/other.kt index 3c5599c..88170fb 100644 --- a/src/prolog/builtins/other.kt +++ b/src/prolog/builtins/other.kt @@ -6,11 +6,6 @@ import prolog.ast.logic.LogicOperand import prolog.ast.logic.LogicOperator import prolog.ast.terms.Goal -class Initialization(val goal: LogicOperand) : LogicOperator(":-", rightOperand = goal) { - override fun satisfy(subs: Substitutions): Answers = goal.satisfy(subs).take(1) - override fun toString(): String = goal.toString() -} - class Query(val query: LogicOperand) : LogicOperator("?-", rightOperand = query) { override fun satisfy(subs: Substitutions): Answers = query.satisfy(subs) }