Commit 43dd651d authored by Martin Spoto's avatar Martin Spoto
Browse files

More comments (up to ProloGraal.g4)

parent e5803d68
......@@ -6,6 +6,7 @@ import com.oracle.truffle.api.nodes.ControlFlowException;
/**
* Class representing an error caused by the non-existence of a clause.
* Thrown when looking for possible clauses for the current goal, and finding nothing.
* @see ch.heiafr.prolograal.nodes.ProloGraalProofTreeNode
* @author Martin Spoto
*/
public class ProloGraalExistenceError extends ControlFlowException {
......
......@@ -13,6 +13,7 @@ import com.oracle.truffle.api.nodes.RootNode;
/**
* Class representing the Truffle root node for evaluation of source code.
* Taken and adapted from the SimpleLanguage demo implementation.
* @see ProloGraalLanguage
* @author Martin Spoto
*/
public final class ProloGraalEvalRootNode extends RootNode {
......
......@@ -15,6 +15,8 @@ import java.util.stream.IntStream;
/**
* Class representing a node of the proof tree.
* Each node is characterized by its goals.
* This class is a Truffle executable {@link Node}.
* @see ProloGraalResolverNode
* @author Martin Spoto
*/
@NodeInfo(shortName = "ProofTreeNode")
......@@ -51,7 +53,8 @@ public class ProloGraalProofTreeNode extends Node {
return new ProloGraalSuccess();
}
ProloGraalTerm<?> currentGoal = goals.getFirst();
ProloGraalTerm<?> currentGoal = goals.peek();
// get the list of all possible clauses based on the name of the predicate
List<ProloGraalClause> possibleClauses = clauses.get(currentGoal);
if (possibleClauses == null || possibleClauses.isEmpty()) // if no match, throw an error
{
......@@ -60,10 +63,11 @@ public class ProloGraalProofTreeNode extends Node {
int start = 0;
if (!branches.isEmpty()) {
// if we're redoing we need to skip to the right branch directly
start = branches.pop();
}
// filter clauses that are unifiable with the current goal
// filter clauses that are unifiable with the current goal, creating copies and saving variables state as needed
List<ProloGraalClause> unifiableClauses =
IntStream.range(0, possibleClauses.size())
.filter(x -> {
......@@ -73,10 +77,11 @@ public class ProloGraalProofTreeNode extends Node {
currentGoal.undo();
return r;
})
.mapToObj(x -> possibleClauses.get(x).copy())
.mapToObj(x -> possibleClauses.get(x).copy()) // create a copy of each filtered clauses
.collect(Collectors.toList());
for (int i = start; i < unifiableClauses.size(); i++) {
// no need to copy here since it is already one
ProloGraalClause unifiableClause = unifiableClauses.get(i);
currentGoal.save();
......@@ -87,6 +92,7 @@ public class ProloGraalProofTreeNode extends Node {
System.out.println("Unified " + currentGoal + " with " + unifiableClause.getHead());
}
// only execute built-in the first time we traverse their nodes
if (branches.isEmpty()) {
if (unifiableClause instanceof ProloGraalBuiltinClause) {
// if the clause is a built-in, execute its internal behaviour
......@@ -100,7 +106,7 @@ public class ProloGraalProofTreeNode extends Node {
List<ProloGraalTerm<?>> body = unifiableClause.getGoals();
// always remove the first goal since it will be replaced
newGoals.pollFirst();
newGoals.poll();
// no need for distinction between facts and regular clauses
// add all the new goals
......@@ -108,7 +114,8 @@ public class ProloGraalProofTreeNode extends Node {
body.forEach(newGoals::addFirst);
if (new ProloGraalProofTreeNode(clauses, newGoals).execute(branches).asBoolean()) {
if (!branches.isEmpty() || i + 1 < unifiableClauses.size()) { // skip last possible nodes if empty
// skip last possible nodes if empty, or always add if we already have added a path
if (!branches.isEmpty() || i + 1 < unifiableClauses.size()) {
if (branches.isEmpty()) {
i = i + 1; // if we're at the bottom go directly to next node
}
......
......@@ -8,11 +8,18 @@ import com.oracle.truffle.api.nodes.RootNode;
import java.util.*;
/**
* Class handling the start and end of a resolution.
* This class extends {@link RootNode} as it is a starting point in the execution process (a root of the AST).
* @see ProloGraalInterpreterNode
* @see ProloGraalProofTreeNode
* @author Martin Spoto
*/
@NodeInfo(language = "Prolog", description = "Root node that spawns a proof tree")
public final class ProloGraalResolverNode extends RootNode {
private final ProloGraalContext context;
private final Map<ProloGraalTerm<?>, List<ProloGraalClause>> clauses;
private final ProloGraalContext context; // the context
private final Map<ProloGraalTerm<?>, List<ProloGraalClause>> clauses; // reference to the context clauses
public ProloGraalResolverNode(ProloGraalLanguage language) {
super(language);
......@@ -22,6 +29,7 @@ public final class ProloGraalResolverNode extends RootNode {
@Override
public Object execute(VirtualFrame frame) {
// we get the goal runtime and the current branches from the frame arguments, passed by the interpreter
ProloGraalRuntime goalRuntime = (ProloGraalRuntime) frame.getArguments()[0];
@SuppressWarnings("unchecked")
Deque<Integer> branches = (Deque<Integer>) frame.getArguments()[1];
......@@ -31,12 +39,20 @@ public final class ProloGraalResolverNode extends RootNode {
System.out.println("Branches : " + branches);
}
// copy the first clause of the goal (there should be only one) to prevent unwanted side effects
ProloGraalClause clause = goalRuntime.getFirstClause().copy();
// get the goals of the clause as a deque
// a deque is used to be able to efficiently remove / add at the start of the collection
// it is possible to use a stack by reversing everything but doing it like that is more logical
// also, the javadoc for the Stack encourages the use of a Deque instead
Deque<ProloGraalTerm<?>> goals = new ArrayDeque<>(clause.getGoals());
// create the root node of the proof tree
ProloGraalProofTreeNode proofTreeNode = new ProloGraalProofTreeNode(clauses, goals);
// start the execution of the proof tree, and stores the result
ProloGraalBoolean r = proofTreeNode.execute(branches);
// if the result is a success, we need to store the variables state and pass them in a ProloGraalSuccess
// to display them later in the interpreter
if (r.asBoolean()) {
r = new ProloGraalSuccess(clause.getVariables());
}
......
// This file contains the ANTLR4 grammar for our subset of Prolog
//
grammar ProloGraal;
// parser
prolograal :
clause* EOF
clause* EOF // zero or more clauses and the EOF
;
// an atom can be the lexical definition of an atom or an empty list
atom :
ATOM |
LIST_START LIST_END // empty list
LIST_START LIST_END
;
number :
......@@ -20,9 +26,10 @@ VARIABLE
;
functor :
atom
atom // a functor can only be an atom
;
// a composed term is a functor followed by one or more parenthesis enclosed, comma separated terms.
composedTerm :
functor ('(' term (',' term)* ')')
;
......@@ -44,24 +51,30 @@ fact :
head TERMINATOR
;
// a goal can only be either an atom or a composed term, it cannot be a number or something else.
goal :
atom |
composedTerm
;
// a composed clause is an head follow by one or more goals separated with a comma
composedClause :
head CLAUSE_MARKER goal (SEPARATOR goal)* TERMINATOR
;
// a clause is either a fact or a composed clause
clause :
fact |
composedClause
;
// the tail of a list can be any term
tail :
term
;
// a list is bracket enclosed, and contains one or more terms followed by a possible tail
// note that it cannot be empty since the empty list is an atom
list :
LIST_START
term (SEPARATOR term)* (LIST_ENDING tail)?
......@@ -84,6 +97,12 @@ fragment LOWERCASE : [a-z];
fragment UPPERCASE : [A-Z];
fragment DIGITS : [0-9];
// an atom must start with a lowercase
// it can also be anything enclosed in single quotes
ATOM : (LOWERCASE (LOWERCASE | UPPERCASE | DIGITS | UNDERSCORE)*) | ('\'' .*? '\'');
// a variable must start by an uppercase or an underscore
// that means that during parsing no difference is made between single use (anonymous) and "normal" variables.
VARIABLE : ((UPPERCASE | UNDERSCORE) (LOWERCASE | UPPERCASE | DIGITS | UNDERSCORE)*);
// a number is one or more digits followed by possibly a dot and more digits
// that means that during parsing no difference is made between integer and floating points.
NUMBER : DIGITS+ ('.' DIGITS+)?;
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment