Commit 66cdf43f authored by Martin Spoto's avatar Martin Spoto
Browse files

Add builtins and support for redo.

parents 81e66e24 aabac752
package ch.heiafr.prolograal;
import com.oracle.truffle.api.TruffleFile;
import java.io.IOException;
import java.nio.charset.Charset;
public final class ProloGraalFileDetector implements TruffleFile.FileTypeDetector {
@Override
public String findMimeType(TruffleFile file) throws IOException {
String name = file.getName();
if (name != null && name.endsWith(".pl")) {
return ProloGraalLanguage.MIME_TYPE;
}
return null;
}
@Override
public String findMimeType(TruffleFile file) {
String name = file.getName();
if (name != null && name.endsWith(".pl")) {
return ProloGraalLanguage.MIME_TYPE;
}
return null;
}
@Override
public Charset findEncoding(TruffleFile file) throws IOException {
return null;
}
@Override
public Charset findEncoding(TruffleFile file) {
return null;
}
}
\ No newline at end of file
package ch.heiafr.prolograal;
import ch.heiafr.prolograal.builtins.ProloGraalBuiltinNode;
import ch.heiafr.prolograal.nodes.ProloGraalEvalRootNode;
import ch.heiafr.prolograal.parser.ProloGraalParserImpl;
import ch.heiafr.prolograal.runtime.ProloGraalBoolean;
......@@ -12,7 +11,6 @@ import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.TruffleLanguage.ContextPolicy;
import com.oracle.truffle.api.dsl.NodeFactory;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
......@@ -21,123 +19,117 @@ import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@TruffleLanguage.Registration(id = ProloGraalLanguage.ID, name = "Prolog", defaultMimeType = ProloGraalLanguage.MIME_TYPE, characterMimeTypes = ProloGraalLanguage.MIME_TYPE, contextPolicy = ContextPolicy.SHARED, fileTypeDetectors = ProloGraalFileDetector.class)
@TruffleLanguage.Registration(id = ProloGraalLanguage.ID, name = "Prolog", defaultMimeType =
ProloGraalLanguage.MIME_TYPE, characterMimeTypes = ProloGraalLanguage.MIME_TYPE, contextPolicy =
ContextPolicy.SHARED, fileTypeDetectors = ProloGraalFileDetector.class)
public class ProloGraalLanguage extends TruffleLanguage<ProloGraalContext> {
public static volatile int counter;
public static final String ID = "pl";
public static final String MIME_TYPE = "application/x-prolog";
public static final boolean DEBUG_MODE = false;
static {
if(DEBUG_MODE) {
System.setOut(new PrintStream(System.out) {
@Override
public void println(String x) {
super.println("(DEBUG) " + x);
}
});
}
}
public ProloGraalLanguage() {
counter++;
}
@Override
protected ProloGraalContext createContext(Env env) {
return new ProloGraalContext(this, env);
}
@Override
protected CallTarget parse(ParsingRequest request) throws Exception {
Source source = request.getSource();
ProloGraalRuntime result = null;
if (request.getArgumentNames().isEmpty()) {
long time = System.currentTimeMillis();
result = ProloGraalParserImpl.parseProloGraal(this, source);
long time2 = System.currentTimeMillis();
if(DEBUG_MODE)
System.out.println("Parsing time : " + (time2-time) + "ms");
}
RootNode eval = new ProloGraalEvalRootNode(this, result);
return Truffle.getRuntime().createCallTarget(eval);
}
// TODO find out what this function does
@Override
protected boolean isVisible(ProloGraalContext context, Object value) {
return !InteropLibrary.getFactory().getUncached(value).isNull(value);
}
@Override
protected boolean isObjectOfLanguage(Object object) {
if (!(object instanceof TruffleObject)) {
return false;
}
return object instanceof ProloGraalTerm<?> || object instanceof ProloGraalBoolean;
}
@Override
protected String toString(ProloGraalContext context, Object value) {
return toString(value);
}
public static String toString(Object value) {
try {
if (value == null) {
return "ANY";
} else if(value instanceof ProloGraalTerm<?> || value instanceof ProloGraalBoolean) {
return value.toString();
}
InteropLibrary interop = InteropLibrary.getFactory().getUncached(value);
if (interop.isString(value)) {
return interop.asString(value);
} else {
return "Unsupported";
public static volatile int counter;
public static final String ID = "pl";
public static final String MIME_TYPE = "application/x-prolog";
// controls debug output for the whole application
public static final boolean DEBUG_MODE = false;
static {
if (DEBUG_MODE) {
System.setOut(new PrintStream(System.out) {
@Override
public void println(String x) {
super.println("(DEBUG) " + x);
}
} catch(UnsupportedMessageException e) {
CompilerDirectives.transferToInterpreter();
throw new AssertionError();
}
}
@Override
protected Object findMetaObject(ProloGraalContext context, Object value) {
return getMetaObject(value);
}
// FIXME when all types are declared
public static String getMetaObject(Object value) {
if(value == null) {
});
}
}
public ProloGraalLanguage() {
counter++;
}
@Override
protected ProloGraalContext createContext(Env env) {
return new ProloGraalContext(env);
}
@Override
protected CallTarget parse(ParsingRequest request) throws Exception {
Source source = request.getSource();
ProloGraalRuntime result = null;
if (request.getArgumentNames().isEmpty()) {
long time = System.currentTimeMillis();
result = ProloGraalParserImpl.parseProloGraal(this, source);
long time2 = System.currentTimeMillis();
if (DEBUG_MODE) {
System.out.println("Parsing time : " + (time2 - time) + "ms");
}
}
RootNode eval = new ProloGraalEvalRootNode(this, result);
return Truffle.getRuntime().createCallTarget(eval);
}
// TODO find out what this function does
@Override
protected boolean isVisible(ProloGraalContext context, Object value) {
return !InteropLibrary.getFactory().getUncached(value).isNull(value);
}
@Override
protected boolean isObjectOfLanguage(Object object) {
if (!(object instanceof TruffleObject)) {
return false;
}
return object instanceof ProloGraalTerm<?> || object instanceof ProloGraalBoolean;
}
@Override
protected String toString(ProloGraalContext context, Object value) {
return toString(value);
}
public static String toString(Object value) {
try {
if (value == null) {
return "ANY";
}
InteropLibrary interop = InteropLibrary.getFactory().getUncached(value);
if(interop.isString(value)) {
return "String";
} else {
} else if (value instanceof ProloGraalTerm<?> || value instanceof ProloGraalBoolean) {
return value.toString();
}
InteropLibrary interop = InteropLibrary.getFactory().getUncached(value);
if (interop.isString(value)) {
return interop.asString(value);
} else {
return "Unsupported";
}
}
@Override
protected SourceSection findSourceLocation(ProloGraalContext context, Object value) {
// FIXME maybe ? seems not applicable for Prolog
return null;
}
private static final List<NodeFactory<? extends ProloGraalBuiltinNode>> EXTERNAL_BUILTINS = Collections.synchronizedList(new ArrayList<>());
public static void installBuiltin(NodeFactory<? extends ProloGraalBuiltinNode> builtin) {
EXTERNAL_BUILTINS.add(builtin);
}
}
} catch (UnsupportedMessageException e) {
CompilerDirectives.transferToInterpreter();
throw new AssertionError();
}
}
@Override
protected Object findMetaObject(ProloGraalContext context, Object value) {
return getMetaObject(value);
}
private static String getMetaObject(Object value) {
if (value == null) {
return "ANY";
}
InteropLibrary interop = InteropLibrary.getFactory().getUncached(value);
if (interop.isString(value)) {
return "String";
} else {
return "Unsupported";
}
}
@Override
protected SourceSection findSourceLocation(ProloGraalContext context, Object value) {
// FIXME maybe ? seems not applicable for Prolog
return null;
}
}
\ No newline at end of file
......@@ -3,6 +3,6 @@ package ch.heiafr.prolograal.builtins;
import ch.heiafr.prolograal.runtime.ProloGraalAtom;
public final class ProloGraalBuiltinAtoms {
public static final ProloGraalAtom EMPTY_LIST = new ProloGraalAtom(null, "[]");
public static final ProloGraalAtom DOT_OPERATOR = new ProloGraalAtom(null, "'.'");
public static final ProloGraalAtom EMPTY_LIST = new ProloGraalAtom(null, "[]");
public static final ProloGraalAtom DOT_OPERATOR = new ProloGraalAtom(null, "'.'");
}
\ No newline at end of file
package ch.heiafr.prolograal.builtins;
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
/**
* Base class for all builtin functions. It contains the Truffle DSL annotation {@link NodeChild}
* that defines the function arguments.<br>
* The builtin functions are registered in {@link SLContext#installBuiltins}. Every builtin node
* subclass is instantiated there, wrapped into a function, and added to the
* {@link SLFunctionRegistry}. This ensures that builtin functions can be called like user-defined
* functions; there is no special function lookup or call node for builtin functions.
*/
//@NodeChild(value = "arguments", type = SLExpressionNode[].class)
@GenerateNodeFactory
public abstract class ProloGraalBuiltinNode extends Node {
protected abstract Object execute(VirtualFrame frame);
}
package ch.heiafr.prolograal.builtins.predicates;
import ch.heiafr.prolograal.runtime.ProloGraalClause;
public abstract class ProloGraalBultinClause extends ProloGraalClause {
public void execute() {
// default behaviour is to do nothing...
}
// we want the built-ins to override this because otherwise they will lose their "ProloGraalBultinClause" status
@Override
public abstract ProloGraalClause copy();
}
package ch.heiafr.prolograal.builtins.predicates;
import ch.heiafr.prolograal.runtime.*;
import java.util.Map;
/**
* @see ProloGraalRuntime for registration of the built-in
*/
public class ProloGraalVarBuiltin extends ProloGraalBultinClause {
// create a custom head for the predicate so we can customize the unification process
protected static class VarPredicateHead extends ProloGraalStructure {
public VarPredicateHead(Map<ProloGraalVariable, ProloGraalVariable> variables) {
super(variables);
setFunctor(new ProloGraalAtom(variables, "var"));
addSubterm(new ProloGraalVariable(variables, "_"));
}
@Override
public boolean unify(ProloGraalTerm<?> other) {
if (other instanceof ProloGraalStructure) {
ProloGraalStructure struct = (ProloGraalStructure) other;
if (struct.getFunctor().equals(getFunctor()) && struct.getArity() == 1) {
return struct.getArguments().get(0).getRootValue() instanceof ProloGraalVariable;
}
}
return false;
}
@Override
public ProloGraalStructure copy(Map<ProloGraalVariable, ProloGraalVariable> variables) {
return new VarPredicateHead(variables);
}
}
public ProloGraalVarBuiltin() {
super();
VarPredicateHead head = new VarPredicateHead(getVariables());
setHead(head);
}
@Override
public ProloGraalClause copy() {
return new ProloGraalVarBuiltin();
}
}
package ch.heiafr.prolograal.builtins.predicates;
import ch.heiafr.prolograal.runtime.*;
import java.io.PrintWriter;
/**
* @see ProloGraalRuntime for registration of the built-in
*/
public class ProloGraalWriteBuiltin extends ProloGraalBultinClause {
private final PrintWriter writer;
private final ProloGraalContext context;
private ProloGraalVariable arg;
public ProloGraalWriteBuiltin(ProloGraalContext context) {
super();
this.writer = new PrintWriter(context.getOutput(), true);
this.context = context;
// create the head of this clause. We keep the variable for later use
ProloGraalStructure head = new ProloGraalStructure(getVariables());
head.setFunctor(new ProloGraalAtom(getVariables(), "write"));
arg = new ProloGraalVariable(getVariables(), "_");
head.addSubterm(arg);
setHead(head);
}
@Override
public void execute() {
// will print whatever the variable is currently bound to, i.e. what we want to print
String str = arg.getRootValue().toString();
if(str.startsWith("'") && str.endsWith("'")) {
// strip single quotes
str = str.substring(1, str.length()-1);
}
writer.print(str);
writer.flush();
}
@Override
public ProloGraalClause copy() {
return new ProloGraalWriteBuiltin(context);
}
}
package ch.heiafr.prolograal.exceptions;
import ch.heiafr.prolograal.runtime.ProloGraalTerm;
import com.oracle.truffle.api.nodes.ControlFlowException;
public class ProloGraalExistenceError extends ControlFlowException {
private static final long serialVersionUID = 0xd4cc78cfb9ef9000L;
// cannot use built-in because of inheritance from ControlFlowException
private String message;
public ProloGraalExistenceError(ProloGraalTerm<?> what) {
message = what.toString();
}
@Override
public String getMessage() {
return message;
}
private static final long serialVersionUID = 0xd4cc78cfb9ef9000L;
}
\ No newline at end of file
package ch.heiafr.prolograal.nodes;
public abstract class ProloGraalAtomNode extends ProloGraalTermNode {
private String value;
public ProloGraalAtomNode(String value) {
this.value = value;
}
@Override
public String toString() {
return "ProloGraalAtomNode(" + value + ")";
}
}
\ No newline at end of file
package ch.heiafr.prolograal.nodes;
import com.oracle.truffle.api.nodes.Node;
public abstract class ProloGraalClauseNode extends Node {
}
\ No newline at end of file
package ch.heiafr.prolograal.nodes;
import ch.heiafr.prolograal.ProloGraalLanguage;
import ch.heiafr.prolograal.runtime.ProloGraalContext;
import ch.heiafr.prolograal.runtime.ProloGraalRuntime;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.RootNode;
import ch.heiafr.prolograal.ProloGraalLanguage;
import ch.heiafr.prolograal.runtime.ProloGraalContext;
import ch.heiafr.prolograal.runtime.ProloGraalRuntime;
public final class ProloGraalEvalRootNode extends RootNode {
private final ProloGraalLanguage language;
private final ProloGraalRuntime runtime;
@CompilationFinal
private boolean registered;
private final ContextReference<ProloGraalContext> reference;
@Child
private DirectCallNode mainCallNode;
public ProloGraalEvalRootNode(ProloGraalLanguage language, ProloGraalRuntime runtime) {
super(null); // internal frame
this.runtime = runtime;
this.mainCallNode = null;
this.language = language;
this.reference = language.getContextReference();
}
@Override
protected boolean isInstrumentable() {
return false;
}
@Override
public String getName() {
return "root eval";
}
@Override
public String toString() {
return getName();
}
@Override
public Object execute(VirtualFrame frame) {
/* Lazy registrations of clauses on first execution. */
if (!registered) {
/* Function registration is a slow-path operation that must not be compiled. */
CompilerDirectives.transferToInterpreterAndInvalidate();
reference.get().registerRuntime(runtime);
ProloGraalInterpreterNode interpreterNode = new ProloGraalInterpreterNode(language);
ProloGraalResolverNode resolverNode = new ProloGraalResolverNode(language);
reference.get().registerInterpreter(interpreterNode);
reference.get().registerResolver(resolverNode);
registered = true;
}
return Truffle.getRuntime().createCallTarget(reference.get().getInterpreterNode()).call();
}
private final ProloGraalLanguage language;
private final ProloGraalRuntime runtime;
@CompilationFinal
private boolean registered;
private final ContextReference<ProloGraalContext> reference;
public ProloGraalEvalRootNode(ProloGraalLanguage language, ProloGraalRuntime runtime) {
super(null); // internal frame
this.runtime = runtime;
this.language = language;
this.reference = language.getContextReference();
}
@Override
protected boolean isInstrumentable() {
return false;
}
@Override
public String getName() {