Пример #1
0
 private void checkSlotAssign(VirtualFrame frame, Object object, String name, Object value) {
   // TODO: optimize using a mechanism similar to overrides?
   if (checkSlotAssignFunction == null) {
     CompilerDirectives.transferToInterpreterAndInvalidate();
     checkSlotAssignFunction = (RFunction) checkAtAssignmentFind.execute(frame);
     checkAtAssignmentCall = insert(CallRFunctionNode.create(checkSlotAssignFunction.getTarget()));
     assert objClassHierarchy == null && valClassHierarchy == null;
     objClassHierarchy = insert(ClassHierarchyNodeGen.create(true, false));
     valClassHierarchy = insert(ClassHierarchyNodeGen.create(true, false));
   }
   RStringVector objClass = objClassHierarchy.execute(object);
   RStringVector valClass = objClassHierarchy.execute(value);
   RFunction currentFunction = (RFunction) checkAtAssignmentFind.execute(frame);
   if (cached.profile(currentFunction == checkSlotAssignFunction)) {
     // TODO: technically, someone could override checkAtAssignment function and access the
     // caller, but it's rather unlikely
     checkAtAssignmentCall.execute(
         frame,
         checkSlotAssignFunction,
         RCaller.create(frame, getOriginalCall()),
         null,
         new Object[] {objClass, name, valClass},
         SIGNATURE,
         checkSlotAssignFunction.getEnclosingFrame(),
         null);
   } else {
     // slow path
     RContext.getEngine()
         .evalFunction(
             currentFunction,
             frame.materialize(),
             RCaller.create(frame, getOriginalCall()),
             null,
             objClass,
             name,
             valClass);
   }
 }
Пример #2
0
@RBuiltin(
    name = "@<-",
    kind = PRIMITIVE,
    parameterNames = {"", "", "value"},
    nonEvalArgs = 1,
    behavior = COMPLEX)
public abstract class UpdateSlot extends RBuiltinNode {

  private static final ArgumentsSignature SIGNATURE =
      ArgumentsSignature.get("cl", "name", "valueClass");

  @CompilationFinal private RFunction checkSlotAssignFunction;
  @Child private ClassHierarchyNode objClassHierarchy;
  @Child private ClassHierarchyNode valClassHierarchy;

  @Child
  private UpdateSlotNode updateSlotNode =
      com.oracle.truffle.r.nodes.access.UpdateSlotNodeGen.create(null, null, null);

  @Child
  private ReadVariableNode checkAtAssignmentFind =
      ReadVariableNode.createFunctionLookup(RSyntaxNode.INTERNAL, "checkAtAssignment");

  @Child private CallRFunctionNode checkAtAssignmentCall;
  private final ConditionProfile cached = ConditionProfile.createBinaryProfile();

  @Override
  protected void createCasts(CastBuilder casts) {
    casts.arg(0).allowNull().asAttributable(true, true, true);
  }

  protected String getName(Object nameObj) {
    assert nameObj instanceof RPromise;
    Object rep = ((RPromise) nameObj).getRep();
    if (rep instanceof WrapArgumentNode) {
      rep = ((WrapArgumentNode) rep).getOperand();
    }
    if (rep instanceof ConstantNode) {
      Object val = ((ConstantNode) rep).getValue();
      if (val instanceof String) {
        return (String) val;
      }
      if (val instanceof RSymbol) {
        return ((RSymbol) val).getName();
      }
    } else if (rep instanceof ReadVariableNode) {
      return ((ReadVariableNode) rep).getIdentifier();
    } else if (rep instanceof RCallNode) {
      throw RError.error(this, RError.Message.SLOT_INVALID_TYPE, "language");
    }
    // TODO: this is not quite correct, but I wonder if we even reach here (can also be
    // augmented on demand)
    throw RError.error(this, RError.Message.SLOT_INVALID_TYPE, nameObj.getClass().toString());
  }

  private void checkSlotAssign(VirtualFrame frame, Object object, String name, Object value) {
    // TODO: optimize using a mechanism similar to overrides?
    if (checkSlotAssignFunction == null) {
      CompilerDirectives.transferToInterpreterAndInvalidate();
      checkSlotAssignFunction = (RFunction) checkAtAssignmentFind.execute(frame);
      checkAtAssignmentCall = insert(CallRFunctionNode.create(checkSlotAssignFunction.getTarget()));
      assert objClassHierarchy == null && valClassHierarchy == null;
      objClassHierarchy = insert(ClassHierarchyNodeGen.create(true, false));
      valClassHierarchy = insert(ClassHierarchyNodeGen.create(true, false));
    }
    RStringVector objClass = objClassHierarchy.execute(object);
    RStringVector valClass = objClassHierarchy.execute(value);
    RFunction currentFunction = (RFunction) checkAtAssignmentFind.execute(frame);
    if (cached.profile(currentFunction == checkSlotAssignFunction)) {
      // TODO: technically, someone could override checkAtAssignment function and access the
      // caller, but it's rather unlikely
      checkAtAssignmentCall.execute(
          frame,
          checkSlotAssignFunction,
          RCaller.create(frame, getOriginalCall()),
          null,
          new Object[] {objClass, name, valClass},
          SIGNATURE,
          checkSlotAssignFunction.getEnclosingFrame(),
          null);
    } else {
      // slow path
      RContext.getEngine()
          .evalFunction(
              currentFunction,
              frame.materialize(),
              RCaller.create(frame, getOriginalCall()),
              null,
              objClass,
              name,
              valClass);
    }
  }

  /*
   * Motivation for cached version is that in the operator form (foo@bar<-baz), the name is an
   * interned string which allows us to avoid longer lookup
   */
  @Specialization(guards = "sameName(nameObj, nameObjCached)")
  protected Object updateSlotCached(
      VirtualFrame frame,
      Object object,
      @SuppressWarnings("unused") Object nameObj,
      Object value,
      @SuppressWarnings("unused") @Cached("nameObj") Object nameObjCached,
      @Cached("getName(nameObjCached)") String name) {
    checkSlotAssign(frame, object, name, value);
    return updateSlotNode.executeUpdate(object, name, value);
  }

  @Specialization(contains = "updateSlotCached")
  protected Object updateSlot(VirtualFrame frame, Object object, Object nameObj, Object value) {
    String name = getName(nameObj);
    checkSlotAssign(frame, object, name, value);
    return updateSlotNode.executeUpdate(object, name, value);
  }

  protected boolean sameName(Object nameObj, Object nameObjCached) {
    assert nameObj instanceof RPromise;
    assert nameObjCached instanceof RPromise;
    return ((RPromise) nameObj).getRep() == ((RPromise) nameObjCached).getRep();
  }
}
Пример #3
0
  @TruffleBoundary
  static void printNoDimList(RAbstractContainer s, PrintContext printCtx) throws IOException {
    final PrintParameters pp = printCtx.parameters();
    final PrintWriter out = printCtx.output();

    final StringBuilder tagbuf = printCtx.getOrCreateTagBuffer();
    // save the original length so that we can restore the original value
    int taglen = tagbuf.length();

    int ns = s.getLength();

    RAbstractStringVector names;
    names = Utils.castTo(RRuntime.asAbstractVector(s.getNames(dummyAttrProfiles)));

    if (ns > 0) {
      int npr = (ns <= pp.getMax() + 1) ? ns : pp.getMax();
      /* '...max +1' ==> will omit at least 2 ==> plural in msg below */
      for (int i = 0; i < npr; i++) {
        if (i > 0) {
          out.println();
        }
        String ss = names == null ? null : Utils.<String>getDataAt(names, i);
        if (ss != null && !ss.isEmpty()) {
          /*
           * Bug for L <- list(`a\\b` = 1, `a\\c` = 2) : const char *ss =
           * translateChar(STRING_ELT(names, i));
           */
          if (taglen + ss.length() > TAGBUFLEN) {
            if (taglen <= TAGBUFLEN) {
              tagbuf.append("$...");
            }
          } else {
            /*
             * we need to distinguish character NA from "NA", which is a valid (if
             * non-syntactic) name
             */
            if (ss == RRuntime.STRING_NA) {
              tagbuf.append("$<NA>");
            } else if (RDeparse.isValidName(ss)) {
              tagbuf.append(String.format("$%s", ss));
            } else {
              tagbuf.append(String.format("$`%s`", ss));
            }
          }

        } else {
          if (taglen + indexWidth(i) > TAGBUFLEN) {
            if (taglen <= TAGBUFLEN) {
              tagbuf.append("$...");
            }
          } else {
            tagbuf.append(String.format("[[%d]]", i + 1));
          }
        }

        out.println(tagbuf);
        Object si = s.getDataAtAsObject(i);
        if (si instanceof RAttributable && ((RAttributable) si).isObject()) {
          RContext.getEngine().printResult(si);
        } else {
          ValuePrinters.INSTANCE.print(si, printCtx);
          ValuePrinters.printNewLine(printCtx);
        }
        tagbuf.setLength(taglen); // reset tag buffer to the original value
      }

      if (npr < ns) {
        out.printf("\n [ reached getOption(\"max.print\") -- omitted %d entries ]", ns - npr);
      }

    } else {
      /* ns = length(s) == 0 */

      /* Formal classes are represented as empty lists */
      String className = null;
      if (printCtx.printerNode().isObject(s) && printCtx.printerNode().isMethodDispatchOn()) {
        RAbstractStringVector klass =
            Utils.castTo(RRuntime.asAbstractVector(s.getAttr(RRuntime.CLASS_ATTR_KEY)));
        if (klass != null && klass.getLength() == 1) {
          String ss = klass.getDataAt(0);
          String str = snprintf(200, ".__C__%s", ss);
          Frame frame = com.oracle.truffle.r.runtime.Utils.getActualCurrentFrame();
          if (ReadVariableNode.lookupAny(str, frame, false) != null) {
            className = ss;
          }
        }
      }
      if (className != null) {
        out.printf("An object of class \"%s\"", className);
      } else {
        if (names != null) {
          out.print("named ");
        }
        out.print("list()");
      }
    }
  }