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) }