diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index 3300be54fd584fcc6f016fdae4818ef2cdbfeeb4..c39ea95a71b90e52551afad66dc6f8bb36019e5b 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -88,6 +88,7 @@ public class BasePackage extends RPackage { load(Exists.class); load(Floor.class); load(Get.class); + load(GetClass.class); load(Getwd.class); load(GlobalEnv.class); load(Gregexpr.class); @@ -172,12 +173,14 @@ public class BasePackage extends RPackage { load(Unlist.class); load(UpdateAttr.class); load(UpdateAttributes.class); + load(UpdateClass.class); load(UpdateDiag.class); load(UpdateDim.class); load(UpdateDimNames.class); load(UpdateLength.class); load(UpdateNames.class); load(UpperTri.class); + load(UseMethod.class); load(Which.class); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java new file mode 100644 index 0000000000000000000000000000000000000000..edb10882611cd2c0a0d25c5018dc077609e03c65 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java @@ -0,0 +1,29 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 2014, Purdue University + * Copyright (c) 2014, Oracle and/or its affiliates + * + * All rights reserved. + */ + +package com.oracle.truffle.r.nodes.builtin.base; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.r.nodes.builtin.*; +import com.oracle.truffle.r.runtime.*; +import com.oracle.truffle.r.runtime.data.model.*; + +@RBuiltin(value = "class") +public abstract class GetClass extends RBuiltinNode { + @Specialization + public Object getClass(VirtualFrame frame, RAbstractVector arg) { + if (arg.isObject()) { + return arg.getAttributes().get(RRuntime.CLASS_ATTR_KEY); + } + return arg.getClassHierarchy().get(0); + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/IsObject.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/IsObject.java index ce5226b885232ce5999263b61b2f976441bba05f..33e2ac4c34aff5d6c39fb7464c22269902c9db82 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/IsObject.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/IsObject.java @@ -22,6 +22,8 @@ */ package com.oracle.truffle.r.nodes.builtin.base; +import java.util.*; + import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.r.nodes.builtin.*; import com.oracle.truffle.r.runtime.*; @@ -38,10 +40,8 @@ public abstract class IsObject extends RBuiltinNode { } @Specialization - @SuppressWarnings("unused") public byte isObject(RAbstractVector arg) { - // FIXME return the result of class attribute presence check (once supported) - return RRuntime.LOGICAL_FALSE; + Map<String, Object> attributes = arg.getAttributes(); + return arg.isObject() ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE; } - } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java index ce0694b5123ffb08e781bfde5e04869b1aca7922..f55139c0bb3d6fe2766fede9aea4d43a0c3270b1 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java @@ -120,6 +120,9 @@ public abstract class UpdateAttr extends RBuiltinNode { } else if (name.equals(RRuntime.DIMNAMES_ATTR_KEY)) { return updateDimNames(frame, resultVector, value); } else { + if (name.equals(RRuntime.CLASS_ATTR_KEY) && !(value instanceof RString && value instanceof RStringVector)) { + RError.getInvalidClassAttr(getEncapsulatingSourceSection()); + } if (resultVector.getAttributes() == null) { resultVector.setAttributes(new LinkedHashMap<String, Object>()); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java new file mode 100644 index 0000000000000000000000000000000000000000..9d51e8beef0fc92c2bc4b647bbe7df0225f97b6e --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java @@ -0,0 +1,217 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 2014, Purdue University + * Copyright (c) 2014, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.nodes.builtin.base; + +import java.util.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.r.nodes.builtin.*; +import com.oracle.truffle.r.nodes.unary.*; +import com.oracle.truffle.r.runtime.*; +import com.oracle.truffle.r.runtime.data.*; +import com.oracle.truffle.r.runtime.data.model.*; + +@RBuiltin(value = "class<-") +public abstract class UpdateClass extends RBuiltinNode { + + private RVector resultVector; + @Child private CastStringNode castStringNode; + @Child private CastComplexNode castComplexNode; + @Child private CastDoubleNode castDoubleNode; + @Child private CastIntegerNode castIntegerNode; + @Child private CastLogicalNode castLogicalNode; + @Child private CastRawNode castRawNode; + + private void initCastString() { + if (castStringNode == null) { + CompilerDirectives.transferToInterpreter(); + castStringNode = adoptChild(CastStringNodeFactory.create(null, false, false, false)); + } + } + + private void initCastComplex() { + if (castComplexNode == null) { + CompilerDirectives.transferToInterpreter(); + castComplexNode = adoptChild(CastComplexNodeFactory.create(null, false, false)); + } + } + + private void initCastDouble() { + if (castDoubleNode == null) { + CompilerDirectives.transferToInterpreter(); + castDoubleNode = adoptChild(CastDoubleNodeFactory.create(null, false, false)); + } + } + + private void initCastInteger() { + if (castIntegerNode == null) { + CompilerDirectives.transferToInterpreter(); + castIntegerNode = adoptChild(CastIntegerNodeFactory.create(null, false, false)); + } + } + + private void initCastLogical() { + if (castLogicalNode == null) { + CompilerDirectives.transferToInterpreter(); + castLogicalNode = adoptChild(CastLogicalNodeFactory.create(null, false, false)); + } + } + + private void initCastRaw() { + if (castRawNode == null) { + CompilerDirectives.transferToInterpreter(); + castRawNode = adoptChild(CastRawNodeFactory.create(null, false, false)); + } + } + + private RStringVector castStringVector(VirtualFrame frame, RAbstractVector o) { + initCastString(); + return (RStringVector) castStringNode.executeStringVector(frame, o); + } + + @Specialization + public Object setClass(VirtualFrame frame, RAbstractVector arg, RAbstractVector className) { + if (className.getLength() == 0) { + return setClass(frame, arg, RNull.instance); + } + return setClass(frame, arg, castStringVector(frame, className)); + } + + @Specialization + public Object setClass(VirtualFrame frame, RAbstractVector arg, RStringVector className) { + if (className.getLength() > 1) { + Map<String, Object> attrb = getAttributes(arg); + attrb.put(RRuntime.CLASS_ATTR_KEY, className); + return resultVector; + } + return setClassHelper(frame, arg, className.getDataAt(0)); + } + + @Specialization + public Object setClass(VirtualFrame frame, RAbstractVector arg, RNull className) { + Map<String, Object> attrb = getAttributes(arg); + if (attrb != null) { + attrb.remove(RRuntime.CLASS_ATTR_KEY); + } + return resultVector; + } + + @Specialization + public Object setClass(VirtualFrame frame, RAbstractLogicalVector arg, String className) { + if (className.equals(RRuntime.TYPE_LOGICAL)) { + return arg; + } + return setClassHelper(frame, arg, className); + } + + @Specialization + public Object setClass(VirtualFrame frame, RAbstractStringVector arg, String className) { + if (className.equals(RRuntime.TYPE_CHARACTER)) { + return arg; + } + return setClassHelper(frame, arg, className); + } + + @Specialization + public Object setClass(VirtualFrame frame, RAbstractComplexVector arg, String className) { + if (className.equals(RRuntime.TYPE_COMPLEX)) { + return arg; + } + return setClassHelper(frame, arg, className); + } + + @Specialization + public Object setClass(VirtualFrame frame, RAbstractDoubleVector arg, String className) { + if (className.equals(RRuntime.TYPE_DOUBLE) || className.equals(RRuntime.TYPE_NUMERIC)) { + return arg; + } + return setClassHelper(frame, arg, className); + } + + @Specialization + public Object setClass(VirtualFrame frame, RAbstractIntVector arg, String className) { + if (className.equals(RRuntime.TYPE_INTEGER) || className.equals(RRuntime.TYPE_NUMERIC)) { + return arg; + } + return setClassHelper(frame, arg, className); + } + + @Specialization + public Object setClass(VirtualFrame frame, RAbstractRawVector arg, String className) { + if (className.equals(RRuntime.TYPE_RAW)) { + return arg; + } + return setClassHelper(frame, arg, className); + } + + @Specialization + public Object setClassHelper(VirtualFrame frame, RAbstractVector arg, String className) { + if (className.equals(RRuntime.TYPE_CHARACTER)) { + initCastString(); + return castStringNode.executeString(frame, arg); + } + if (className.equals(RRuntime.TYPE_COMPLEX)) { + initCastComplex(); + return castComplexNode.executeComplex(frame, arg); + } + if (className.equals(RRuntime.TYPE_DOUBLE)) { + initCastDouble(); + return castDoubleNode.executeDouble(frame, arg); + } + if (className.equals(RRuntime.TYPE_INTEGER)) { + initCastInteger(); + return castIntegerNode.executeInt(frame, arg); + } + if (className.equals(RRuntime.TYPE_LOGICAL)) { + initCastLogical(); + return castLogicalNode.executeCast(frame, arg); + } + if (className.equals(RRuntime.TYPE_RAW)) { + initCastRaw(); + return castRawNode.executeRaw(frame, arg); + } + if (className.equals(RRuntime.TYPE_NUMERIC)) { + initCastDouble(); + return castDoubleNode.executeDouble(frame, arg); + } + if (className.equals(RRuntime.TYPE_MATRIX)) { + if (RRuntime.isMatrix(arg)) { + return setClass(frame, arg, RNull.instance); + } + throw RError.getNotMatixUpdateClass(getEncapsulatingSourceSection(), arg.getDimensions().length); + + } + if (className.equals(RRuntime.TYPE_ARRAY)) { + if (arg.getDimensions().length > 0) { + return setClass(frame, arg, RNull.instance); + } + throw RError.getNotArrayUpdateClass(getEncapsulatingSourceSection()); + } + Map<String, Object> attrb = getAttributes(arg); + attrb.put(RRuntime.CLASS_ATTR_KEY, className); + return resultVector; + } + + private Map<String, Object> getAttributes(RAbstractVector arg) { + resultVector = arg.materialize(); + if (resultVector.isShared()) { + resultVector = resultVector.copy(); + } + Map<String, Object> attrb = resultVector.getAttributes(); + if (attrb == null) { + attrb = new LinkedHashMap<>(); + resultVector.setAttributes((LinkedHashMap<String, Object>) attrb); + } + return attrb; + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UseMethod.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UseMethod.java new file mode 100644 index 0000000000000000000000000000000000000000..79fb89a1be0d6d6f5e06aa91aae471e974303581 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UseMethod.java @@ -0,0 +1,230 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 2014, Purdue University + * Copyright (c) 2014, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.nodes.builtin.base; + +import java.util.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.impl.*; +import com.oracle.truffle.r.nodes.*; +import com.oracle.truffle.r.nodes.access.*; +import com.oracle.truffle.r.nodes.builtin.*; +import com.oracle.truffle.r.nodes.function.*; +import com.oracle.truffle.r.runtime.*; +import com.oracle.truffle.r.runtime.data.*; +import com.oracle.truffle.r.runtime.data.model.*; + +@RBuiltin(value = "UseMethod") +public abstract class UseMethod extends RBuiltinNode { + + /* + * TODO: If more than two parameters are passed to UseMethod the extra parameters are ignored + * and a warning is generated. + */ + private static final Object[] PARAMETER_NAMES = new Object[]{"generic", "object"}; + + @Child protected ReadVariableNode lookup; + @CompilationFinal protected String lastFun; + + private FunctionDefinitionNode funcDefnNode; + + @Override + public Object[] getParameterNames() { + return PARAMETER_NAMES; + } + + @Override + public RNode[] getArguments() { + return new RNode[]{ConstantNode.create(RMissing.instance), ConstantNode.create(RMissing.instance)}; + } + + @Specialization + public Object useMethod(VirtualFrame frame, String generic, RAbstractVector arg) { + if (arg.isObject()) { + final Object classAttrb = arg.getAttributes().get(RRuntime.CLASS_ATTR_KEY); + if (classAttrb instanceof RStringVector) { + RStringVector classNames = (RStringVector) classAttrb; + return useMethodHelper(frame, generic, classNames); + } + return useMethodHelper(frame, generic, (String) classAttrb); + } else { + return useMethodHelper(frame, generic, arg.getClassHierarchy()); + } + } + + /* + * If only one argument is passed to UseMethod, the first argument of enclosing function is used + * to resolve the generic. + */ + @Specialization + public Object useMethod(VirtualFrame frame, String generic, @SuppressWarnings("unused") RMissing arg) { + RArguments args = frame.getArguments(RArguments.class); + if (args == null || args.getLength() == 0 || args.getArgument(0) == null) { + throw RError.getUnknownFunctionUseMethod(getEncapsulatingSourceSection(), generic, RNull.instance.toString()); + } + Object enclosingArg = args.getArgument(0); + if (enclosingArg instanceof Byte) { + return useMethod(frame, generic, (byte) enclosingArg); + } + if (enclosingArg instanceof String) { + return useMethod(frame, generic, (String) enclosingArg); + } + if (enclosingArg instanceof Integer) { + return useMethod(frame, generic, (int) enclosingArg); + } + if (enclosingArg instanceof Double) { + return useMethod(frame, generic, (double) enclosingArg); + } + return useMethod(frame, generic, (RAbstractVector) enclosingArg); + } + + @Specialization + public Object useMethod(VirtualFrame frame, String generic, byte arg) { + return useMethodHelper(frame, generic, RRuntime.TYPE_LOGICAL); + } + + @Specialization + public Object useMethod(VirtualFrame frame, String generic, String arg) { + return useMethodHelper(frame, generic, RRuntime.TYPE_CHARACTER); + } + + @Specialization + public Object useMethod(VirtualFrame frame, String generic, int arg) { + return useMethodHelper(frame, generic, RRuntime.CLASS_INTEGER); + } + + @Specialization + public Object useMethod(VirtualFrame frame, String generic, double arg) { + return useMethodHelper(frame, generic, RRuntime.CLASS_DOUBLE); + } + + private Object useMethodHelper(VirtualFrame frame, String generic, String className) { + VirtualFrame newFrame = findFunction(className, generic, frame); + if (newFrame == null) { + newFrame = findFunction(RRuntime.DEFAULT, generic, frame); + if (newFrame == null) { + throw RError.getUnknownFunctionUseMethod(getEncapsulatingSourceSection(), generic, className); + } + } + return dispatchMethod(frame, newFrame); + } + + private Object useMethodHelper(VirtualFrame frame, String generic, String[] classNames) { + VirtualFrame newFrame = null; + for (final String className : classNames) { + newFrame = findFunction(className, generic, frame); + if (newFrame != null) { + break; + } + } + if (newFrame == null) { + newFrame = findFunction(RRuntime.DEFAULT, generic, frame); + if (newFrame == null) { + throw RError.getUnknownFunctionUseMethod(getEncapsulatingSourceSection(), generic, Arrays.toString(classNames)); + } + } + return dispatchMethod(frame, newFrame); + } + + private Object useMethodHelper(VirtualFrame frame, String generic, List<String> classNames) { + VirtualFrame newFrame = null; + for (final String className : classNames) { + newFrame = findFunction(className, generic, frame); + if (newFrame != null) { + break; + } + } + if (newFrame == null) { + newFrame = findFunction(RRuntime.DEFAULT, generic, frame); + if (newFrame == null) { + throw RError.getUnknownFunctionUseMethod(getEncapsulatingSourceSection(), generic, classNames.toString()); + } + } + return dispatchMethod(frame, newFrame); + } + + private Object useMethodHelper(VirtualFrame frame, String generic, RStringVector classNames) { + VirtualFrame newFrame = null; + for (int i = 0; i < classNames.getLength() && newFrame == null; ++i) { + newFrame = findFunction(classNames.getDataAt(i), generic, frame); + } + if (newFrame == null) { + newFrame = findFunction(RRuntime.DEFAULT, generic, frame); + if (newFrame == null) { + throw RError.getUnknownFunctionUseMethod(getEncapsulatingSourceSection(), generic, classNames.toString()); + } + } + return dispatchMethod(frame, newFrame); + } + + private VirtualFrame findFunction(final String className, final String generic, VirtualFrame frame) { + StringBuilder sbFuncName = new StringBuilder(generic); + sbFuncName.append("."); + sbFuncName.append(className); + final String funcName = RRuntime.toString(sbFuncName); + if (lookup == null || !funcName.equals(lastFun)) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + lastFun = funcName; + ReadVariableNode rvn = ReadVariableNode.create(funcName, true, false); + lookup = lookup == null ? adoptChild(rvn) : lookup.replace(rvn); + } + Object func = null; + try { + func = lookup.execute((VirtualFrame) frame.getCaller().unpack()); + } catch (RError r) { + return null; + } + if (func != null && func instanceof RFunction) { + final RFunction targetFunction = (RFunction) func; + funcDefnNode = (FunctionDefinitionNode) (((DefaultCallTarget) targetFunction.getTarget()).getRootNode()); + final RArguments currentArguments = frame.getArguments(RArguments.class); + final RArguments newArguments = RArguments.create(targetFunction, targetFunction.getEnclosingFrame(), currentArguments.getArgumentsArray(), currentArguments.getNames()); + return Truffle.getRuntime().createVirtualFrame(frame.getCaller(), newArguments, frame.getFrameDescriptor().copy()); + } + return null; + } + + private Object dispatchMethod(VirtualFrame frame, VirtualFrame newFrame) { + + // Copy the variables defined(prior to call to UseMethod) in the current frame to the new + // frame + for (FrameSlot fs : frame.getFrameDescriptor().getSlots()) { + switch (fs.getKind()) { + case Object: + newFrame.setObject(fs, FrameUtil.getObjectSafe(frame, fs)); + break; + case Int: + newFrame.setInt(fs, FrameUtil.getIntSafe(frame, fs)); + break; + case Byte: + newFrame.setByte(fs, FrameUtil.getByteSafe(frame, fs)); + break; + case Long: + newFrame.setLong(fs, FrameUtil.getLongSafe(frame, fs)); + break; + case Double: + newFrame.setDouble(fs, FrameUtil.getDoubleSafe(frame, fs)); + break; + case Float: + newFrame.setFloat(fs, FrameUtil.getFloatSafe(frame, fs)); + break; + case Boolean: + newFrame.setBoolean(fs, FrameUtil.getBooleanSafe(frame, fs)); + break; + } + } + return funcDefnNode.execute(newFrame); + } + +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java index 241f302a1e2d67a4cd99d2090a3e856bfb058e2a..e9aebeae9f75f9438550720ef9425079786fa3cb 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java @@ -161,6 +161,7 @@ public abstract class RError extends RuntimeException { public static final String ARGUMENT_NOT_MATCH = "supplied argument name '%s' does not match '%s'"; public static final String ARGUMENT_MISSING = "argument '%s' is missing, with no default"; public static final String UNKNOWN_FUNCTION = "could not find function '%s'"; + public static final String UNKNOWN_FUNCTION_USE_METHOD = "Error in UseMethod('%s') : \n no applicable method for '%s' applied to an object of class '%s'"; public static final String UNKNOWN_OBJECT = "object '%s' not found"; public static final String INVALID_ARGUMENT = "invalid '%s' argument"; public static final String INVALID_SUBSCRIPT_TYPE = "invalid subscript type '%s'"; @@ -209,7 +210,11 @@ public abstract class RError extends RuntimeException { public static final String FORMAL_MATCHED_MULTIPLE = "formal argument \"%s\" matched by multiple actual arguments"; public static final String ARGUMENT_MATCHES_MULTIPLE = "argument %d matches multiple formal arguments"; public static final String ARGUMENT_EMPTY = "argument %d is empty"; - public static final String REPEATED_FORMAL = "repeated formal argument '%s'"; // not exactly + public static final String REPEATED_FORMAL = "repeated formal argument '%s'"; + public static final String NOT_A_MATRIX_UPDATE_CLASS = "invalid to set the class to matrix unless the dimension attribute is of length 2 (was '%d')"; + public static final String NOT_ARRAY_UPDATE_CLASS = "cannot set class to \"array\" unless the dimension attribute has length > 0"; + public static final String SET_INVALID_CLASS_ATTR = "attempt to set invalid 'class' attribute"; + // not exactly // GNU-R message public static final String DOTS_BOUNDS = "The ... list does not contain %s elements"; public static final String REFERENCE_NONEXISTENT = "reference to non-existent argument %d"; @@ -1674,6 +1679,10 @@ public abstract class RError extends RuntimeException { return getGenericError(ast, stringFormat(RError.UNKNOWN_FUNCTION, variable)); } + public static RError getUnknownFunctionUseMethod(SourceSection ast, String function, String classVector) { + return getGenericError(ast, stringFormat(RError.UNKNOWN_FUNCTION_USE_METHOD, function, function, classVector)); + } + public static RError getInvalidArgument(SourceSection ast, String str) { return getGenericError(ast, stringFormat(RError.INVALID_ARGUMENT, str)); } @@ -1939,6 +1948,18 @@ public abstract class RError extends RuntimeException { return getGenericError(ast, stringFormat(RError.RECURSIVE_INDEXING_FAILED, level)); } + public static RError getNotMatixUpdateClass(SourceSection ast, int dim) { + return getGenericError(ast, stringFormat(RError.NOT_A_MATRIX_UPDATE_CLASS, dim)); + } + + public static RError getNotArrayUpdateClass(SourceSection ast) { + return getGenericError(ast, RError.NOT_ARRAY_UPDATE_CLASS); + } + + public static RError getInvalidClassAttr(SourceSection ast) { + return getGenericError(ast, RError.SET_INVALID_CLASS_ATTR); + } + @SlowPath private static String stringFormat(String format, Object... args) { return String.format(format, args); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java index c40baa7802d70d3754e8dcbd0dbafcfdd6858784..685610d05fe06d300a5356c0fd9578891f8f6b00 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java @@ -86,6 +86,9 @@ public class RRuntime { public static final String TYPE_CHARACTER = new String("character"); public static final String TYPE_LOGICAL = new String("logical"); public static final String TYPE_RAW = new String("raw"); + public static final String TYPE_MATRIX = new String("matrix"); + public static final String TYPE_ARRAY = new String("array"); + public static final String TYPE_LIST = new String("list"); public static final String TYPE_NUMERIC_CAP = new String("Numeric"); public static final String TYPE_INTEGER_CAP = new String("Integer"); @@ -98,6 +101,7 @@ public class RRuntime { public static final REnvironment GLOBAL_ENV = RGlobalEnvironment.instance; public static final String[] STRING_ARRAY_SENTINEL = new String[0]; + public static final String DEFAULT = "default"; public static final String NAMES_ATTR_KEY = new String("names"); public static final String NAMES_ATTR_EMPTY_VALUE = ""; @@ -107,6 +111,11 @@ public class RRuntime { public static final String DIMNAMES_ATTR_KEY = "dimnames"; public static final String DIMNAMES_LIST_ELEMENT_NAME_PREFIX = "$dimnames"; + public static final String CLASS_ATTR_KEY = "class"; + + public static final String[] CLASS_INTEGER = new String[]{TYPE_INTEGER, TYPE_NUMERIC}; + public static final String[] CLASS_DOUBLE = new String[]{TYPE_DOUBLE, TYPE_NUMERIC}; + public static RComplex createComplexNA() { return RDataFactory.createComplex(COMPLEX_NA_REAL_PART, COMPLEX_NA_IMAGINARY_PART); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java index 1995e5406cb74e161aaa7539903877a9209e27ef..ef2f71108edb4ba3419081b265e58c12561ee4e6 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java @@ -164,4 +164,10 @@ public final class RComplexVector extends RVector implements RAbstractComplexVec return getDataAt(index); } + @Override + public List<String> getClassHierarchy() { + List<String> klass = super.getClassHierarchy(); + klass.add(RRuntime.TYPE_COMPLEX); + return klass; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java index e94b2c9a537722a6702fa7f250b2f8c659275366..11bf2ab6908fa1357528ba03674d2c388f9faf3a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java @@ -22,7 +22,10 @@ */ package com.oracle.truffle.r.runtime.data; +import java.util.*; + import com.oracle.truffle.api.CompilerDirectives.SlowPath; +import com.oracle.truffle.r.runtime.*; import com.oracle.truffle.r.runtime.data.model.*; public final class RDoubleSequence extends RSequence implements RAbstractDoubleVector { @@ -30,6 +33,13 @@ public final class RDoubleSequence extends RSequence implements RAbstractDoubleV private final double start; private final double stride; + private static final List<String> klass; + static { + klass = new ArrayList<>(); + klass.add(RRuntime.TYPE_DOUBLE); + klass.add(RRuntime.TYPE_NUMERIC); + } + RDoubleSequence(double start, double stride, int length) { super(length); assert length > 0; @@ -91,4 +101,9 @@ public final class RDoubleSequence extends RSequence implements RAbstractDoubleV public Object getDataAtAsObject(int index) { return getDataAt(index); } + + @Override + public List<String> getClassHierarchy() { + return klass; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java index 3c42287a008ca84ff1108101b5f1cd71557e717c..1cfe02a8d361a525b0b0288bdcc6f095b6f16ef3 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java @@ -174,4 +174,10 @@ public final class RDoubleVector extends RVector implements RAbstractDoubleVecto this.data = newData; } + @Override + public List<String> getClassHierarchy() { + final List<String> classHr = super.getClassHierarchy(); + classHr.addAll(Arrays.asList(RRuntime.CLASS_DOUBLE)); + return classHr; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java index 6ed1b9f30f36c23837d94909a76d40117dcfa5c1..02e5c74d3e1d6771659321981cdbe70fed23eae8 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java @@ -22,7 +22,10 @@ */ package com.oracle.truffle.r.runtime.data; +import java.util.*; + import com.oracle.truffle.api.CompilerDirectives.SlowPath; +import com.oracle.truffle.r.runtime.*; import com.oracle.truffle.r.runtime.data.model.*; public final class RIntSequence extends RSequence implements RAbstractIntVector { @@ -30,6 +33,13 @@ public final class RIntSequence extends RSequence implements RAbstractIntVector private final int start; private final int stride; + private static final List<String> klass; + static { + klass = new ArrayList<>(); + klass.add(RRuntime.TYPE_INTEGER); + klass.add(RRuntime.TYPE_NUMERIC); + } + RIntSequence(int start, int stride, int length) { super(length); assert length > 0; @@ -93,4 +103,8 @@ public final class RIntSequence extends RSequence implements RAbstractIntVector public Object getDataAtAsObject(int index) { return getDataAt(index); } + + public List<String> getClassHierarchy() { + return klass; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java index 523fcedcc1ea3890675cbfa788b2af1f11840840..3168c7ae7132eece9beebf83f28c6d44b73cf02c 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java @@ -157,4 +157,11 @@ public final class RIntVector extends RVector implements RAbstractIntVector { public Object getDataAtAsObject(int index) { return getDataAt(index); } + + @Override + public List<String> getClassHierarchy() { + final List<String> classHr = super.getClassHierarchy(); + classHr.addAll(Arrays.asList(RRuntime.CLASS_INTEGER)); + return classHr; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java index 12c0c8ec94d62b1568a3eb74ccf38c1ae5223e7d..98442acf93b003003a56fd561b2c943897fcf77e 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java @@ -163,4 +163,11 @@ public final class RList extends RVector implements RAbstractVector { protected void resizeInternal(int size) { this.data = createResizedData(size, true); } + + @Override + public List<String> getClassHierarchy() { + List<String> klass = super.getClassHierarchy(); + klass.add(RRuntime.TYPE_LIST); + return klass; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java index 9ebd72632af08b1a3c30001f4ded789ba75ce430..12f69444e41f8450e6fadd0fbdf5db71fc6c03db 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java @@ -148,4 +148,11 @@ public final class RLogicalVector extends RVector implements RAbstractLogicalVec public Object getDataAtAsObject(int index) { return getDataAt(index); } + + @Override + public List<String> getClassHierarchy() { + final List<String> classHr = super.getClassHierarchy(); + classHr.add(RRuntime.TYPE_LOGICAL); + return classHr; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java index 6cce99315acd84533603b4611aa4b56807b3eb2a..12781ebf97aa61acdb1f44a978af613e30e99204 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java @@ -143,4 +143,11 @@ public final class RRawVector extends RVector implements RAbstractRawVector { public Object getDataAtAsObject(int index) { return getDataAt(index); } + + @Override + public List<String> getClassHierarchy() { + final List<String> classHr = super.getClassHierarchy(); + classHr.add(RRuntime.TYPE_RAW); + return classHr; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java index 410fbb261dfbb4bff91440ebb178c177f18d2485..5d786a08b2cf1ebf707f26c161bcaf457d89312a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java @@ -84,4 +84,12 @@ public abstract class RSequence extends RBounded implements RAbstractVector { public boolean isMatrix() { return false; } + + public boolean isArray() { + return false; + } + + public boolean isObject() { + return false; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java index a5bb3b63400845268a5c648d055c7bb3d8eb5865..b8f903dcc1e13eb160601b2652a972473ca1fe99 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java @@ -148,4 +148,11 @@ public final class RStringVector extends RVector implements RAbstractStringVecto public Object getDataAtAsObject(int index) { return getDataAt(index); } + + @Override + public List<String> getClassHierarchy() { + final List<String> classHr = super.getClassHierarchy(); + classHr.add(RRuntime.TYPE_CHARACTER); + return classHr; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java index 6a3df393d40fdcad710bc20a313a5b59a7ea64f7..9100d2d0639cb6b9ce0d1f3b4e81837235c5cbc3 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java @@ -212,6 +212,10 @@ public abstract class RVector extends RBounded implements RAbstractVector { return matrixDimension != 0; } + public final boolean isArray() { + return dimensions != null && dimensions.length > 0; + } + public final int[] getDimensions() { if (hasDimensions()) { return Arrays.copyOf(dimensions, dimensions.length); @@ -382,4 +386,20 @@ public abstract class RVector extends RBounded implements RAbstractVector { } } } + + public boolean isObject() { + return (this.attributes != null && this.attributes.get(RRuntime.CLASS_ATTR_KEY) != null) ? true : false; + } + + // As shape of the vector may change at run-time we need to compute + // class hierarchy on the fly. + public List<String> getClassHierarchy() { + List<String> klass = new ArrayList<>(); + if (this.isMatrix()) { + klass.add(RRuntime.TYPE_MATRIX); + } else if (this.isArray()) { + klass.add(RRuntime.TYPE_ARRAY); + } + return klass; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java index f505beffb58f4e9690e2739df2ddd33f1396024e..049b8db2ed129c9b0f8095c64fa6a9490295f52d 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java @@ -80,4 +80,15 @@ public abstract class RToVectorClosure implements RAbstractVector { return vector.isMatrix(); } + public boolean isArray() { + return vector.isArray(); + } + + public List<String> getClassHierarchy() { + return vector.getClassHierarchy(); + } + + public boolean isObject() { + return vector.isObject(); + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java index 4b59ab5cc0864ad13231b461180337fd2d168e2a..5c72de906b6d5d734d0c003ca4ba0028c6780a3d 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java @@ -56,4 +56,10 @@ public interface RAbstractVector { RList getDimNames(); boolean isMatrix(); + + boolean isArray(); + + boolean isObject(); + + List<String> getClassHierarchy(); } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index e49132203186ea6bcfedf18ecb0089a50e43394c..7fa74d0b081e25d3dea54076205fead80abcb4f8 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -6721,6 +6721,21 @@ $<NA> #{ z <- c(a=1, b=2) ; names(z) <- NULL ; z } [1] 1 2 +##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testUseMethodEnclFuncArgs +#{f <- function(x,y,z){ UseMethod("f"); }; f.second <- function(x,y,z){cat("f second",x,y,z)}; obj <-1; attr(obj,"class") <- "second"; arg2=2; arg3=3; f(obj,arg2,arg3);} +f second 1 2 3 +##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testUseMethodLocalVars +#{f <- function(x){ y<-2;locFun <- function(){cat("local")}; UseMethod("f"); }; f.second <- function(x){cat("f second",x);locFun();}; obj <-1; attr(obj,"class") <- "second"; f(obj);} +f second 1local +##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testUseMethodNested +#{f <- function(x){g<- function(x){ h<- function(x){ UseMethod("f");}; h(x)}; g(x) }; f.second <- function(x){cat("f second",x);}; obj <-1; attr(obj,"class") <- "second"; f(obj);} +f second 1 +##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testUseMethodOneArg +#{f <- function(x){ UseMethod("f"); };f.first <- function(x){cat("f first",x)}; f.second <- function(x){cat("f second",x)}; obj <-1; attr(obj,"class") <- "first"; f(obj); attr(obj,"class") <- "second"; f(obj);} +f first 1f second 1 +##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testUseMethodSimple +#{f <- function(x){ UseMethod("f",x); };f.first <- function(x){cat("f first",x)};f.second <- function(x){cat("f second",x)};obj <-1;attr(obj,"class") <- "first";f(obj);attr(obj,"class") <- "second";f(obj)} +f first 1f second 1 ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testWhich #{ which(c(TRUE, FALSE, NA, TRUE)) } [1] 1 4 diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java index 838ee2b842438683403cd064997efaa8d2e844de..61d08dd0d6ef5a4b8542f5594fad134dbb1099b9 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java @@ -10438,6 +10438,36 @@ public class AllTests extends TestBase { assertEval("{ upper.tri(1:3, diag=FALSE) }"); } + @Test + public void TestSimpleBuiltins_testUseMethodEnclFuncArgs_c699286a5e7dd6ca4c46b1245a1f633e() { + assertEval("{f <- function(x,y,z){ UseMethod(\"f\"); }; f.second <- function(x,y,z){cat(\"f second\",x,y,z)}; obj <-1; attr(obj,\"class\") <- \"second\"; arg2=2; arg3=3; f(obj,arg2,arg3);}"); + } + + @Test + public void TestSimpleBuiltins_testUseMethodIgnore_1af23cb23456744d7e6a4cb93888e9a3() { + assertEval("{f <- function(x){ UseMethod(\"f\");cat(\"This should not be executed\"); }; f.second <- function(x){cat(\"f second\",x);}; obj <-1; attr(obj,\"class\") <- \"second\"; f(obj);}"); + } + + @Test + public void TestSimpleBuiltins_testUseMethodLocalVars_cd724107886a7c9d25ae3b6aad713cb6() { + assertEval("{f <- function(x){ y<-2;locFun <- function(){cat(\"local\")}; UseMethod(\"f\"); }; f.second <- function(x){cat(\"f second\",x);locFun();}; obj <-1; attr(obj,\"class\") <- \"second\"; f(obj);}"); + } + + @Test + public void TestSimpleBuiltins_testUseMethodNested_d689820491ffcbc9ddb83012801bd243() { + assertEval("{f <- function(x){g<- function(x){ h<- function(x){ UseMethod(\"f\");}; h(x)}; g(x) }; f.second <- function(x){cat(\"f second\",x);}; obj <-1; attr(obj,\"class\") <- \"second\"; f(obj);}"); + } + + @Test + public void TestSimpleBuiltins_testUseMethodOneArg_fce364ef2dfa8e366da5615934951253() { + assertEval("{f <- function(x){ UseMethod(\"f\"); };f.first <- function(x){cat(\"f first\",x)}; f.second <- function(x){cat(\"f second\",x)}; obj <-1; attr(obj,\"class\") <- \"first\"; f(obj); attr(obj,\"class\") <- \"second\"; f(obj);}"); + } + + @Test + public void TestSimpleBuiltins_testUseMethodSimple_f4ab882034aa9d9c9d106566155c9a1d() { + assertEval("{f <- function(x){ UseMethod(\"f\",x); };f.first <- function(x){cat(\"f first\",x)};f.second <- function(x){cat(\"f second\",x)};obj <-1;attr(obj,\"class\") <- \"first\";f(obj);attr(obj,\"class\") <- \"second\";f(obj)}"); + } + @Test public void TestSimpleBuiltins_testWhich_abb40fde89cc0dfbb69ec73c399e9ee0() { assertEval("{ which(c(TRUE, FALSE, NA, TRUE)) }"); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/failing/FailingTests.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/failing/FailingTests.java index d151e57105de2f60cbe69df8dd331dc7aa2aee7f..4480a0c746a9834c664d31f1af15b345bdfddb5d 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/failing/FailingTests.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/failing/FailingTests.java @@ -3438,6 +3438,11 @@ public class FailingTests extends TestBase { assertEval("{ upper.tri(1:3, diag=FALSE) }"); } + @Ignore + public void TestSimpleBuiltins_testUseMethodIgnore_1af23cb23456744d7e6a4cb93888e9a3() { + assertEval("{f <- function(x){ UseMethod(\"f\");cat(\"This should not be executed\"); }; f.second <- function(x){cat(\"f second\",x);}; obj <-1; attr(obj,\"class\") <- \"second\"; f(obj);}"); + } + @Ignore public void TestSimpleBuiltins_testWhichIgnore_6d01b8ef11e5cdf979ca7122cd3de717() { assertEval("{ which(c(a=TRUE,b=FALSE,c=TRUE)) }"); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java index 17cc3b441f0c95ede4bed04d082ad2bc94b53965..45256c9accfb0cbf98896407dd926b5a55ac1a54 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java @@ -2348,4 +2348,48 @@ public class TestSimpleBuiltins extends TestBase { assertEvalWarning("{ rm(\"ieps\") }"); assertEval("{ x <- 200 ; rm(\"x\") }"); } + + @Test + public void testUseMethodSimple() { + // Basic UseMethod + assertEval("{f <- function(x){ UseMethod(\"f\",x); };" + "f.first <- function(x){cat(\"f first\",x)};" + "f.second <- function(x){cat(\"f second\",x)};" + "obj <-1;" + + "attr(obj,\"class\") <- \"first\";" + "f(obj);" + "attr(obj,\"class\") <- \"second\";" + "f(obj)}"); + } + + @Test + public void testUseMethodOneArg() { + // If only one argument is passed to UseMethod(), the call should + // be resolved based on first argument to enclosing function. + assertEval("{f <- function(x){ UseMethod(\"f\"); };f.first <- function(x){cat(\"f first\",x)}; f.second <- function(x){cat(\"f second\",x)}; obj <-1; attr(obj,\"class\") <- \"first\"; f(obj); attr(obj,\"class\") <- \"second\"; f(obj);}"); + } + + @Test + public void testUseMethodLocalVars() { + // The variables defined before call to UseMethod should be + // accessible to target function. + assertEval("{f <- function(x){ y<-2;locFun <- function(){cat(\"local\")}; UseMethod(\"f\"); }; f.second <- function(x){cat(\"f second\",x);locFun();}; obj <-1; attr(obj,\"class\") <- \"second\"; f(obj);}"); + } + + @Test + public void testUseMethodNested() { + // The UseMethod call can be nested deep compared to where target is + // defined. + assertEval("{f <- function(x){g<- function(x){ h<- function(x){ UseMethod(\"f\");}; h(x)}; g(x) }; f.second <- function(x){cat(\"f second\",x);}; obj <-1; attr(obj,\"class\") <- \"second\"; f(obj);}"); + } + + @Test + public void testUseMethodEnclFuncArgs() { + // All the argument passed to the caller of UseMethod() should be + // accessible to the target method. + assertEval("{f <- function(x,y,z){ UseMethod(\"f\"); }; f.second <- function(x,y,z){cat(\"f second\",x,y,z)}; obj <-1; attr(obj,\"class\") <- \"second\"; arg2=2; arg3=3; f(obj,arg2,arg3);}"); + + } + + @Test + @Ignore + public void testUseMethodIgnore() { + // TODO + // All the statements after UseMethod() call should get ignored. + assertEval("{f <- function(x){ UseMethod(\"f\");cat(\"This should not be executed\"); }; f.second <- function(x){cat(\"f second\",x);}; obj <-1; attr(obj,\"class\") <- \"second\"; f(obj);}"); + } } diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides index 74cec1009b97151591c602cca2d8ce2e18465d33..59914d2e24de2e70437bc981e62fa5e89bce792f 100644 --- a/mx.fastr/copyrights/overrides +++ b/mx.fastr/copyrights/overrides @@ -1,6 +1,9 @@ com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/Base.r,gnu_r.copyright com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/Covcor.java,gnu_r.copyright +com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java,purdue.copyright com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/Rnorm.java,gnu_r.copyright +com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java,purdue.copyright +com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UseMethod.java,purdue.copyright com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParseException.java,purdue.copyright com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParseUtil.java,purdue.copyright com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g,purdue.copyright