diff --git a/com.oracle.truffle.r.engine/hbase-site.xml b/com.oracle.truffle.r.engine/hbase-site.xml new file mode 100644 index 0000000000000000000000000000000000000000..31dd14dcb2e1e47a491832a98d9ae943d1ca9f2a --- /dev/null +++ b/com.oracle.truffle.r.engine/hbase-site.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> +<?xml-stylesheet type="text/xsl" href="configuration.xsl"?> +<!-- +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<configuration> + <property> + <name>hbase.rootdir</name> + <value>file:///home/julien/hbase/root</value> + </property> + <property> + <name>hbase.zookeeper.property.dataDir</name> + <value>/home/julien/hbase/root/zookeeper</value> + </property> +</configuration> diff --git a/com.oracle.truffle.r.engine/oracle.config b/com.oracle.truffle.r.engine/oracle.config new file mode 100644 index 0000000000000000000000000000000000000000..b49e79d8cbbd5096f744aea3ce597c3b68a250e6 --- /dev/null +++ b/com.oracle.truffle.r.engine/oracle.config @@ -0,0 +1,5 @@ +ora.host = myoracle.com +ora.sid = myview +ora.port = 7658 +ora.user = julilope +ora.passwd = AVONEJ$sartec3 diff --git a/com.oracle.truffle.r.engine/postgre.config b/com.oracle.truffle.r.engine/postgre.config new file mode 100644 index 0000000000000000000000000000000000000000..e0fd54220004434f43609a593cd2742976a62f94 --- /dev/null +++ b/com.oracle.truffle.r.engine/postgre.config @@ -0,0 +1,5 @@ +pgsql.host = localhost +pgsql.sid = postgres +pgsql.port = 5432 +pgsql.user = julien +pgsql.passwd = Pa$$w0rd diff --git a/com.oracle.truffle.r.engine/postgre2.config b/com.oracle.truffle.r.engine/postgre2.config new file mode 100644 index 0000000000000000000000000000000000000000..2c7bf365357d7ebc332e3c58037ae417bce07bed --- /dev/null +++ b/com.oracle.truffle.r.engine/postgre2.config @@ -0,0 +1,5 @@ +pgsql.host = localhost +pgsql.sid = other +pgsql.port = 5432 +pgsql.user = julien +pgsql.passwd = Pa$$w0rd diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index 4a728419ba3a28c76bdd368045462c2075c066d7..ce52a7a9c44a63aee2d0e792ec0f4c0203c7665b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -120,8 +120,10 @@ import com.oracle.truffle.r.nodes.builtin.fastr.FastRTry; import com.oracle.truffle.r.nodes.builtin.fastr.FastRTryNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastrDqrls; import com.oracle.truffle.r.nodes.builtin.fastr.FastrDqrlsNodeGen; -import com.oracle.truffle.r.nodes.builtin.rquery.RQuery; -import com.oracle.truffle.r.nodes.builtin.rquery.RQueryNodeGen; +import com.oracle.truffle.r.nodes.query.RNextResQueryBuiltin; +import com.oracle.truffle.r.nodes.query.RNextResQueryBuiltinNodeGen; +import com.oracle.truffle.r.nodes.query.RTableBuiltin; +import com.oracle.truffle.r.nodes.query.RTableBuiltinNodeGen; import com.oracle.truffle.r.nodes.unary.UnaryNotNode; import com.oracle.truffle.r.nodes.unary.UnaryNotNodeGen; import com.oracle.truffle.r.runtime.RVisibility; @@ -680,7 +682,8 @@ public class BasePackage extends RBuiltinPackage { add(Xtfrm.class, XtfrmNodeGen::create); // query - add(RQuery.class, RQueryNodeGen::create); + add(RNextResQueryBuiltin.class, RNextResQueryBuiltinNodeGen::create); + add(RTableBuiltin.class, RTableBuiltinNodeGen::create); // infix functions add(Subscript.class, SubscriptNodeGen::create, Subscript::special); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/query/RNextResQueryBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/query/RNextResQueryBuiltin.java new file mode 100644 index 0000000000000000000000000000000000000000..fe678bcb47ded0dc427ce009d176e441ea45692e --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/query/RNextResQueryBuiltin.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.query; + +import qir.ast.QIRNode; + +import static com.oracle.truffle.r.runtime.RVisibility.OFF; +import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX; +import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.qirinterface.QIRInterface; +import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.env.REnvironment; +import com.oracle.truffle.r.runtime.env.REnvironment.PutException; + +/** + * This builtin takes an object returned by a query and returns a tuple from the result. This tuple + * is an object with a "get" method to fetch a column given the name. + */ +@RBuiltin(name = "query.force", visibility = OFF, kind = PRIMITIVE, parameterNames = {"query"}, behavior = COMPLEX) +public abstract class RNextResQueryBuiltin extends RBuiltinNode { + @TruffleBoundary + @Specialization + public static final RList force(final REnvironment rQuery) { + // Every query is identified by an integer included in the object returned by the query. + final int queryId = (int) rQuery.get("queryId"); + if (queryId == RContext.INVALID_QUERY_ID) + throw new RuntimeException("Not a query object."); + + // TODO: Handle results given in streaming. + QIRNode query = RContext.queries.get(queryId); + if (query == null) + throw new RuntimeException("Unrecognized or empty query: " + queryId); + + RList queryResults = RContext.results.get(queryId); + if (queryResults != null) // The query has been run before. + return queryResults; + query = QIRInterface.normalize(query, RContext.envs.get(queryId)); + RContext.queries.set(queryId, query); + + queryResults = RDataFactory.createList(QIRInterface.run(query).stream().map(h -> { + final REnvironment env = RDataFactory.createNewEnv(null); + h.entrySet().stream().forEach(entry -> { + try { + env.put(entry.getKey(), entry.getValue()); + } catch (PutException e) { + e.printStackTrace(); + } + }); + return env; + }).toArray()); + RContext.results.set(queryId, queryResults); + + return queryResults; + } +} \ No newline at end of file diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/rquery/RQuery.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/query/RTableBuiltin.java similarity index 54% rename from com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/rquery/RQuery.java rename to com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/query/RTableBuiltin.java index a7f8f803a118bdb0a551aca8d0ddfc03d398b334..2e4ac6ab46ecf726ea755fa4d0a0c5e2fa7448de 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/rquery/RQuery.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/query/RTableBuiltin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,24 +20,36 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.r.nodes.builtin.rquery; +package com.oracle.truffle.r.nodes.query; -import static com.oracle.truffle.r.runtime.builtins.RBehavior.IO; +import static com.oracle.truffle.r.runtime.RVisibility.OFF; +import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.CompilerDirectives.*; +import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; -import com.oracle.truffle.r.runtime.RVisibility; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.env.REnvironment; +import com.oracle.truffle.r.runtime.env.REnvironment.PutException; -@RBuiltin(name = "query", visibility = RVisibility.ON, kind = PRIMITIVE, parameterNames = {}, behavior = IO) -public abstract class RQuery extends RBuiltinNode { - @Specialization +@RBuiltin(name = "new.table", visibility = OFF, kind = PRIMITIVE, parameterNames = {"tableName", "dbName", "configFile", "schemaName"}, behavior = PURE) +public abstract class RTableBuiltin extends RBuiltinNode { @TruffleBoundary - protected REnvironment createQuery() { - return RDataFactory.createNewEnv(null); + @Specialization + public static final REnvironment table(final String tableName, final String dbName, final String configFile, final String schemaName) { + final REnvironment res = RDataFactory.createNewEnv(null); + + try { + res.put("tableName", tableName); + res.put("dbName", dbName); + res.put("configFile", configFile); + res.put("schemaName", schemaName); + } catch (PutException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return res; } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java index 4b35745a57d38575a5f0b42a2bcb630315bdc1bc..90e78439df32c303ec92378b0b5389076df6968f 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java @@ -50,6 +50,10 @@ import com.oracle.truffle.r.nodes.function.RCallSpecialNode; import com.oracle.truffle.r.nodes.function.SaveArgumentsNode; import com.oracle.truffle.r.nodes.function.WrapDefaultArgumentNode; import com.oracle.truffle.r.nodes.function.signature.MissingNode; +import com.oracle.truffle.r.nodes.query.RFromNode; +import com.oracle.truffle.r.nodes.query.RQueryVisitor; +import com.oracle.truffle.r.nodes.query.RSelectNode; +import com.oracle.truffle.r.nodes.query.RWhereNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RRuntime; @@ -148,6 +152,26 @@ public final class RASTBuilder implements RCodeBuilder<RSyntaxNode> { return RCallSpecialNode.createCall(source, lhs.asRNode(), createSignature(args), createArguments(args)); } + @Override + public final RSyntaxNode handleQueries(final RSyntaxNode expression) { + return expression.accept(RQueryVisitor.instance); + } + + @Override + public final RSyntaxNode select(final SourceSection source, final RSyntaxNode formatter, final RSyntaxNode child) { + return new RSelectNode(source, formatter.asRNode(), child.asRNode()); + } + + @Override + public final RSyntaxNode from(final SourceSection source, final RSyntaxNode child) { + return new RFromNode(source, child.asRNode()); + } + + @Override + public final RSyntaxNode where(final SourceSection source, final RSyntaxNode filter, final RSyntaxNode child) { + return new RWhereNode(source, filter.asRNode(), child.asRNode()); + } + private static ArgumentsSignature createSignature(List<Argument<RSyntaxNode>> args) { String[] argumentNames = args.stream().map(arg -> arg.name).toArray(String[]::new); ArgumentsSignature signature = ArgumentsSignature.get(argumentNames); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java index 656bb60251dcb3dce02e777cbf5a03097e58f4ad..396fd5c39cffee2274f1ad97d3d5a7bdea709d95 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java @@ -55,11 +55,11 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; public final class ReplacementDispatchNode extends OperatorNode { // these are only @Child to make instrumentation work - @Child private RNode lhs; - @Child private RNode rhs; + @Child public RNode lhs; + @Child public RNode rhs; - private final boolean isSuper; - private final int tempNamesStartIndex; + public final boolean isSuper; + public final int tempNamesStartIndex; public ReplacementDispatchNode(SourceSection src, RSyntaxLookup operator, RSyntaxNode lhs, RSyntaxNode rhs, boolean isSuper, int tempNamesStartIndex) { super(src, operator); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java index f2d43aac13c4ad98e85c1f8c4a03426b8f074c1b..2d0f542a9fb23b5a2a72e5f0b640ed9bf290aa6c 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java @@ -122,7 +122,7 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode private final RSyntaxNode[] arguments; private final ArgumentsSignature signature; - private final RFunction expectedFunction; + public final RFunction expectedFunction; /** * If this is true, then any bailout should simply be forwarded by re-throwing the exception. diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/qirinterface/QIRInterface.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/qirinterface/QIRInterface.java index bb18c7aca4b0aefffe934575c1a5965b861fb366..18cb4bec10d3fd779241ec53b0987047d9e5ada6 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/qirinterface/QIRInterface.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/qirinterface/QIRInterface.java @@ -35,9 +35,12 @@ import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; +import com.oracle.truffle.r.nodes.function.FunctionExpressionNode; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.context.RContext; - +import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.env.REnvironment; import qir.ast.*; import qir.ast.data.*; import qir.ast.value.*; @@ -80,19 +83,19 @@ public final class QIRInterface { * * @param arg The query to be executed in the targeted database * @param frame The environment of execution - * @param context The other part of the environment of execution * @return The closed query */ - public static final QIRNode normalize(final QIRNode arg, final Frame frame, final RContext context) { + public static final QIRNode normalize(final QIRNode arg, final Frame frame) { QIRNode query = arg; final SourceSection dummy = Source.newBuilder("").name("QIR interface").mimeType(RRuntime.R_APP_MIME).build().createUnavailableSection(); for (Map<String, QIRVariable> fvs = QIRDriver.getFreeVars(query); !fvs.isEmpty(); fvs = QIRDriver.getFreeVars(query)) for (final QIRVariable fv : fvs.values()) { final String varName = fv.getId(); - final FrameSlot varSlot = fv.getSlot(); + final FrameSlot varSlot = frame.getFrameDescriptor().findFrameSlot(varName); + // TODO: Handle functions other than builtins query = new QIRApply(dummy, new QIRLambda(dummy, null, new QIRVariable(dummy, varName, varSlot), query), - RToQIRType(fv.sourceSection, varSlot != null ? frame.getValue(varSlot) : context.stateREnvVars.get(varName))); + RToQIRType(fv.sourceSection, varSlot != null ? frame.getValue(varSlot) : RContext.lookupBuiltin(varName))); } return query; } @@ -191,6 +194,55 @@ public final class QIRInterface { return new QIRBoolean(src, (Boolean) value); if (value instanceof String) return new QIRString(src, (String) value); + if (value instanceof FunctionExpressionNode) { + final FunctionExpressionNode fun = (FunctionExpressionNode) value; + if (fun.getCallTarget() == null) + return new QIRBuiltin(src, fun.getSyntaxDebugName()); + final String funName = fun.getSyntaxDebugName(); + try { + QIRNode res = ((FunctionDefinitionNode) fun.getCallTarget().getRootNode()).getBody().accept(QIRTranslateVisitor.instance); + final String[] args = ((FunctionDefinitionNode) fun.getCallTarget().getRootNode()).getSignature().getNames(); + for (int i = 0; i < args.length; i++) + res = new QIRLambda(src, funName, new QIRVariable(null, args[i], null), res); + return res; + } catch (UnsupportedOperationException e) { + final SourceSection funSrc = fun.getCallTarget().getRootNode().getSourceSection(); + final String program = funSrc.getCode() + "\n" + funName; + // TODO: Handle function dependencies + return new QIRTruffleNode(funSrc, program); + } + } + if (value instanceof REnvironment) { + REnvironment env = (REnvironment) value; + final Object queryId = env.get("queryId"); + if (queryId != null) { // The object is a query + final int qid = ((Long) queryId).intValue(); + return normalize(RContext.queries.get(qid), RContext.envs.get(qid)); + } + + final String tableName = (String) env.get("tableName"); + final String schemaName = (String) env.get("schemaName"); + final String dbName = (String) env.get("dbName"); + final String configFile = (String) env.get("configFile"); + if (tableName != null && dbName != null && configFile != null) // The object is a table + return new QIRTable<>(src, new QIRString(null, tableName), new QIRString(null, schemaName), createDriver(dbName, configFile)); + // else, the object is considered a tuple + QIRTuple tuple = QIRTnil.getInstance(); + for (final Object x : env.getFrame().getFrameDescriptor().getIdentifiers()) + tuple = new QIRTcons(src, (String) x, RToQIRType(src, env.get((String) x)), tuple); + return tuple; + } + if (value instanceof RFunction && ((RFunction) value).isBuiltin()) { + switch (((RFunction) value).getName()) { + case "new.env": + return new QIRLambda(null, "new.env", new QIRVariable(null, "_", null), QIRTnil.getInstance()); + case "return": + final QIRVariable x = new QIRVariable(null, "x", null); + return new QIRLambda(null, "identity", x, x); + default: + throw new RuntimeException("Unsupported value: " + value + " : " + value.getClass()); + } + } throw new RuntimeException("Unsupported value: " + value); } } \ No newline at end of file diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/qirinterface/QIRTranslateVisitor.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/qirinterface/QIRTranslateVisitor.java index fff041f2ca6b50b5c1dfb956310b6934fae02bfc..607c4a16f07b16016d4eaf729f70ac822e9b7b42 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/qirinterface/QIRTranslateVisitor.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/qirinterface/QIRTranslateVisitor.java @@ -1,5 +1,9 @@ package com.oracle.truffle.r.nodes.qirinterface; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.nodes.RSyntaxNodeVisitor; @@ -18,16 +22,27 @@ import com.oracle.truffle.r.runtime.nodes.RNode; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; import qir.ast.*; +import qir.ast.data.QIRTcons; +import qir.ast.data.QIRTdestr; +import qir.ast.expression.arithmetic.QIRDiv; +import qir.ast.expression.arithmetic.QIRMinus; +import qir.ast.expression.arithmetic.QIRPlus; +import qir.ast.expression.arithmetic.QIRStar; +import qir.ast.expression.logic.QIRAnd; +import qir.ast.expression.logic.QIRNot; +import qir.ast.expression.logic.QIROr; +import qir.ast.expression.relational.QIREqual; +import qir.ast.expression.relational.QIRLowerOrEqual; +import qir.ast.expression.relational.QIRLowerThan; import qir.ast.operator.*; /** * This visitor translates a {@link RNode} into a {@link QIRNode}. */ public final class QIRTranslateVisitor implements RSyntaxNodeVisitor<QIRNode> { - private final RContext context; + public static final QIRTranslateVisitor instance = new QIRTranslateVisitor(); - public QIRTranslateVisitor(RContext context) { - this.context = context; + private QIRTranslateVisitor() { } private final SourceSection dummy = Source.newBuilder("").name("QIR translate").mimeType(RRuntime.R_APP_MIME).build().createUnavailableSection(); @@ -69,14 +84,32 @@ public final class QIRTranslateVisitor implements RSyntaxNodeVisitor<QIRNode> { for (int i = len - 2; i > -1; i--) { final RNode child = children[i]; if (child instanceof WriteLocalFrameVariableNode) { // STRAD-ASSIGN-ID - final Object name = ((WriteLocalFrameVariableNode) child).getName(); final RNode value = ((WriteLocalFrameVariableNode) child).getRhs(); // If the assignment value reads an argument, then we translate to a lambda. - result = new QIRLambda(dummy, null, new QIRVariable(dummy, (String) name, null), result); + result = new QIRLambda(dummy, null, new QIRVariable(dummy, (String) ((WriteLocalFrameVariableNode) child).getName(), null), result); + // Else we apply STRAD-ASSIGN-ID normally + if (!(value instanceof AccessArgumentNode)) + result = new QIRApply(dummy, result, value.asRSyntaxNode().accept(this)); + } else if (child instanceof ReplacementDispatchNode && ((ReplacementDispatchNode) child).lhs instanceof ReadVariableNode) { + final RNode value = ((ReplacementDispatchNode) child).rhs; + + // If the assignment value reads an argument, then we translate to a lambda. + result = new QIRLambda(dummy, null, new QIRVariable(dummy, ((ReadVariableNode) ((ReplacementDispatchNode) child).lhs).getIdentifier(), null), result); // Else we apply STRAD-ASSIGN-ID normally if (!(value instanceof AccessArgumentNode)) result = new QIRApply(dummy, result, value.asRSyntaxNode().accept(this)); + } else if (child instanceof ReplacementDispatchNode) { // STRAD-ASSIGN-FIELD and + // STRAD-ASSIGN-DOT + // TODO: Take care of STRAD-ASSIGN-DOT + // TODO: RCallSpecialNode is not necessarily a write + final ReplacementDispatchNode repl = (ReplacementDispatchNode) child; + final RCallSpecialNode lhs = (RCallSpecialNode) repl.lhs; + final ReadVariableNode receiver = (ReadVariableNode) lhs.getSyntaxArguments()[0]; + final ConstantNode eid = (ConstantNode) lhs.getSyntaxArguments()[1]; + final RNode value = repl.rhs; + result = new QIRApply(dummy, new QIRLambda(dummy, null, new QIRVariable(dummy, receiver.getIdentifier(), null), result), + new QIRTcons(dummy, (String) eid.getValue(), value.asRSyntaxNode().accept(this), receiver.accept(this))); } else throw new UnsupportedOperationException("Cannot translate \"" + block.getSourceSection() + "\" to QIR: untranslatable sequence."); } @@ -96,7 +129,7 @@ public final class QIRTranslateVisitor implements RSyntaxNodeVisitor<QIRNode> { @Override public final QIRNode visit(final FunctionExpressionNode fun) { - throw new RuntimeException("Can't translate R function to QIR."); + return QIRInterface.RToQIRType(fun.getSourceSection(), fun); } @Override @@ -114,13 +147,47 @@ public final class QIRTranslateVisitor implements RSyntaxNodeVisitor<QIRNode> { } @Override - public final QIRNode visit(final RCallSpecialNode call) { - throw new RuntimeException("Can't translate R special call to QIR."); + public final QIRNode visit(final RCallSpecialNode dot) { + final String name = dot.expectedFunction.getName(); + final List<QIRNode> nodes = Arrays.stream(dot.getSyntaxArguments()).map(arg -> ((RSyntaxNode) arg).accept(this)).collect(Collectors.toList()); + switch (name) { + case "$": + return new QIRTdestr(dot.getSourceSection(), nodes.get(0), (String) ((ConstantNode) dot.getSyntaxArguments()[1]).getValue()); + case "+": + return new QIRPlus(dot.getSourceSection(), nodes.get(0), nodes.get(1)); + case "-": + return new QIRMinus(dot.getSourceSection(), nodes.get(0), nodes.get(1)); + case "*": + return new QIRStar(dot.getSourceSection(), nodes.get(0), nodes.get(1)); + case "/": + return new QIRDiv(dot.getSourceSection(), nodes.get(0), nodes.get(1)); + case "==": + return new QIREqual(dot.getSourceSection(), nodes.get(0), nodes.get(1)); + case "&": + case "&&": + return new QIRAnd(dot.getSourceSection(), nodes.get(0), nodes.get(1)); + case "|": + case "||": + return new QIROr(dot.getSourceSection(), nodes.get(0), nodes.get(1)); + case "<=": + return new QIRLowerOrEqual(dot.getSourceSection(), nodes.get(0), nodes.get(1)); + case "<": + return new QIRLowerThan(dot.getSourceSection(), nodes.get(0), nodes.get(1)); + case ">=": + return new QIRNot(dot.getSourceSection(), new QIRLowerThan(dot.getSourceSection(), nodes.get(0), nodes.get(1))); + case ">": + return new QIRNot(dot.getSourceSection(), new QIRLowerOrEqual(dot.getSourceSection(), nodes.get(0), nodes.get(1))); + case "!": + return new QIRNot(dot.getSourceSection(), nodes.get(0)); + default: + throw new RuntimeException("Unknown call special node: " + name); + } } @Override public final QIRNode visit(final ReplacementDispatchNode repl) { - throw new RuntimeException("Can't translate R replacement node to QIR."); + // STRAD-ASSIGN-FIELD and STRAD-ASSIGN-DOT should be handled in BlockNode. + throw new RuntimeException("Error in translation to QIR: should not have visited an assignment."); } /** @@ -128,7 +195,7 @@ public final class QIRTranslateVisitor implements RSyntaxNodeVisitor<QIRNode> { */ @Override public final QIRNode visit(final RQIRWrapperNode query) { - return context.queries.get(query.id); + return RContext.queries.get(query.id); } @Override diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQIRWrapperNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQIRWrapperNode.java index d6acb68a46ac9ebce12e0c8a9ee706b645ca6f46..bb96aeafc0b8c75d4ce0fb09dd4a5ee85b12308c 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQIRWrapperNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQIRWrapperNode.java @@ -25,34 +25,39 @@ package com.oracle.truffle.r.nodes.query; import com.oracle.truffle.api.CompilerDirectives.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.object.*; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.env.REnvironment; +import com.oracle.truffle.r.runtime.env.REnvironment.PutException; import com.oracle.truffle.r.runtime.nodes.RSourceSectionNode; @NodeInfo(shortName = "query", description = "The node representing a query") public final class RQIRWrapperNode extends RSourceSectionNode { - private final RContext context; // The unique identifier of the query public final int id; - public RQIRWrapperNode(final SourceSection src, final RContext context) { + public RQIRWrapperNode(final SourceSection src) { super(src); - this.context = context; - this.id = context.createFreshQuery(); + this.id = RContext.createFreshQuery(); } @Override - public final DynamicObject execute(VirtualFrame frame) { - final int instanceId = context.envs.get(id) == null ? id : context.createFreshQueryFrom(id); - context.envs.set(instanceId, frame); + public final REnvironment execute(VirtualFrame frame) { + final int instanceId = RContext.envs.get(id) == null ? id : RContext.createFreshQueryFrom(id); + RContext.envs.set(instanceId, frame); return createQuery(instanceId); } @TruffleBoundary - private final DynamicObject createQuery(int instanceId) { - final DynamicObject res = null; - res.define("queryId", Long.valueOf(instanceId)); + private static final REnvironment createQuery(int instanceId) { + final REnvironment res = RDataFactory.createNewEnv(null); + try { + res.put("queryId", instanceId); + } catch (PutException e) { + e.printStackTrace(); + return null; + } return res; } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQueryVisitor.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQueryVisitor.java index 3f2f859189c8dfef9d72470a87a8d5d46a634cf2..5056b2be04fa1e14fe38912048962fd5cabec470 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQueryVisitor.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQueryVisitor.java @@ -22,12 +22,9 @@ import qir.ast.QIRNode; * them into {@link QIRNode}. */ public final class RQueryVisitor implements RSyntaxNodeVisitor<RSyntaxNode> { - private final RContext context; - private final QIRTranslateVisitor qirVisitor; + public static final RQueryVisitor instance = new RQueryVisitor(); - public RQueryVisitor(final RContext context) { - this.context = context; - this.qirVisitor = new QIRTranslateVisitor(context); + private RQueryVisitor() { } @Override @@ -85,7 +82,8 @@ public final class RQueryVisitor implements RSyntaxNodeVisitor<RSyntaxNode> { @Override public final RSyntaxNode visit(final ReplacementDispatchNode repl) { - return repl; + return new ReplacementDispatchNode(repl.getSourceSection(), repl.getSyntaxLHS(), repl.lhs.asRSyntaxNode().accept(this), repl.rhs.asRSyntaxNode().accept(this), repl.isSuper, + repl.tempNamesStartIndex); } @Override @@ -95,64 +93,64 @@ public final class RQueryVisitor implements RSyntaxNodeVisitor<RSyntaxNode> { @Override public final RSyntaxNode visit(final RSelectNode select) { - final RQIRWrapperNode res = new RQIRWrapperNode(select.getSourceSection(), context); - context.queries.set(res.id, select.accept(qirVisitor)); + final RQIRWrapperNode res = new RQIRWrapperNode(select.getSourceSection()); + RContext.queries.set(res.id, select.accept(QIRTranslateVisitor.instance)); return res; } @Override public final RSyntaxNode visit(final RFromNode from) { - final RQIRWrapperNode res = new RQIRWrapperNode(from.getSourceSection(), context); - context.queries.set(res.id, from.accept(qirVisitor)); + final RQIRWrapperNode res = new RQIRWrapperNode(from.getSourceSection()); + RContext.queries.set(res.id, from.accept(QIRTranslateVisitor.instance)); return res; } @Override public final RSyntaxNode visit(final RWhereNode where) { - final RQIRWrapperNode res = new RQIRWrapperNode(where.getSourceSection(), context); - context.queries.set(res.id, where.accept(qirVisitor)); + final RQIRWrapperNode res = new RQIRWrapperNode(where.getSourceSection()); + RContext.queries.set(res.id, where.accept(QIRTranslateVisitor.instance)); return res; } @Override public final RSyntaxNode visit(final RGroupNode group) { - final RQIRWrapperNode res = new RQIRWrapperNode(group.getSourceSection(), context); - context.queries.set(res.id, group.accept(qirVisitor)); + final RQIRWrapperNode res = new RQIRWrapperNode(group.getSourceSection()); + RContext.queries.set(res.id, group.accept(QIRTranslateVisitor.instance)); return res; } @Override public final RSyntaxNode visit(final ROrderNode order) { - final RQIRWrapperNode res = new RQIRWrapperNode(order.getSourceSection(), context); - context.queries.set(res.id, order.accept(qirVisitor)); + final RQIRWrapperNode res = new RQIRWrapperNode(order.getSourceSection()); + RContext.queries.set(res.id, order.accept(QIRTranslateVisitor.instance)); return res; } @Override public final RSyntaxNode visit(final RJoinNode join) { - final RQIRWrapperNode res = new RQIRWrapperNode(join.getSourceSection(), context); - context.queries.set(res.id, join.accept(qirVisitor)); + final RQIRWrapperNode res = new RQIRWrapperNode(join.getSourceSection()); + RContext.queries.set(res.id, join.accept(QIRTranslateVisitor.instance)); return res; } @Override public final RSyntaxNode visit(final RLeftJoinNode join) { - final RQIRWrapperNode res = new RQIRWrapperNode(join.getSourceSection(), context); - context.queries.set(res.id, join.accept(qirVisitor)); + final RQIRWrapperNode res = new RQIRWrapperNode(join.getSourceSection()); + RContext.queries.set(res.id, join.accept(QIRTranslateVisitor.instance)); return res; } @Override public final RSyntaxNode visit(final RRightJoinNode join) { - final RQIRWrapperNode res = new RQIRWrapperNode(join.getSourceSection(), context); - context.queries.set(res.id, join.accept(qirVisitor)); + final RQIRWrapperNode res = new RQIRWrapperNode(join.getSourceSection()); + RContext.queries.set(res.id, join.accept(QIRTranslateVisitor.instance)); return res; } @Override public final RSyntaxNode visit(final RLimitNode limit) { - final RQIRWrapperNode res = new RQIRWrapperNode(limit.getSourceSection(), context); - context.queries.set(res.id, limit.accept(qirVisitor)); + final RQIRWrapperNode res = new RQIRWrapperNode(limit.getSourceSection()); + RContext.queries.set(res.id, limit.accept(QIRTranslateVisitor.instance)); return res; } diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g index 78c92fcb0f7257ea1525b48384da9a7573b3ba7e..f89b658919646eaab8318991a9f8a16748524953 100644 --- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g +++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g @@ -173,7 +173,7 @@ script returns [List<T> v] throw new RecognitionException(input); } } - : n_ ( s=statement { $v.add($s.v); })* + : n_ ( s=statement { $v.add(builder.handleQueries($s.v)); })* ; root_function [String name] returns [RootCallTarget v] @@ -409,7 +409,14 @@ simple_expr returns [T v] | op=LPAR n_ ea=expr_or_assign n_ y=RPAR { $v = builder.call(src($op, $y), operator($op), $ea.v); } | s=sequence { $v = $s.v; } | e=expr_wo_assign { $v = $e.v; } + | q=query { $v = $q.v; } ; + +query returns [T v] + : op=SELECT n_ LPAR n_ formatter=expr n_ COMMA n_ child=expr end=RPAR { $v = builder.select(src($op, $end), $formatter.v, $child.v); } + | op=FROM n_ LPAR n_ child=expr end=RPAR { $v = builder.from(src($op, $end), $child.v); } + | op=WHERE n_ LPAR n_ filter=expr n_ COMMA n_ child=expr end=RPAR { $v = builder.where(src($op, $end), $filter.v, $child.v); } + ; number returns [T v] : i=INTEGER { @@ -562,6 +569,9 @@ IF : 'if' ; ELSE : 'else' ; NEXT : 'next' ; BREAK : 'break' ; +SELECT : 'select' ; +FROM : 'from' ; +WHERE : 'where' ; WS : ('\u0009'|'\u0020'|'\u00A0') { $channel=HIDDEN; } ; NEWLINE : LINE_BREAK { if(incompleteNesting > 0) $channel=HIDDEN; } ; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java index e94080f7e1009cd1ea21a3e6e1ecdc399b4fb434..ee4a98fe34d52fe214e9782ea9bbce56594ea2f5 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java @@ -103,20 +103,20 @@ import qir.ast.QIRNode; * Contexts can be destroyed */ public final class RContext extends ExecutionContext implements TruffleObject { - private int queryId = 0; + private static int queryId = 0; public static final int INVALID_QUERY_ID = -1; // Static representation of queries. - public final List<QIRNode> queries = new ArrayList<>(); - public final List<VirtualFrame> envs = new ArrayList<>(); + public static final List<QIRNode> queries = new ArrayList<>(); + public static final List<VirtualFrame> envs = new ArrayList<>(); // A query returns a vector of tuples. A tuple is a map from a column name to a value. - public final List<ArrayList<Map<String, Object>>> results = new ArrayList<>(); + public static final List<RList> results = new ArrayList<>(); /** * Returns a fresh identifier for a query. * * @return A unique query identifier */ - public int createFreshQuery() { + public static int createFreshQuery() { queries.add(null); envs.add(null); results.add(null); @@ -129,7 +129,7 @@ public final class RContext extends ExecutionContext implements TruffleObject { * @param id The identifier of the query. * @return A unique query identifier */ - public int createFreshQueryFrom(int id) { + public static int createFreshQueryFrom(int id) { queries.add(queries.get(id)); envs.add(null); results.add(null); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java index 45eb98dceacf4427936a8021a8802062e44c5a97..45d89f4abd67d72f830de7d19e640eb30fb53735 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java @@ -94,6 +94,26 @@ public interface RCodeBuilder<T> { */ T call(SourceSection source, T lhs, List<Argument<T>> arguments); + /** + * Processes queries in an expression to make them ready for evaluation. + */ + T handleQueries(final T expression); + + /** + * Creates a select query. + */ + T select(final SourceSection source, final T formatter, final T child); + + /** + * Creates a from query. + */ + T from(final SourceSection source, final T child); + + /** + * Creates a where query. + */ + T where(final SourceSection source, final T filter, final T child); + /** * Creates a constant, the value is expected to be one of FastR's scalar types (byte, int, * double, RComplex, String, RNull).