@Override public SEXP apply(Context context, Environment rho, FunctionCall call, PairList args) { PairList matchedArguments = ClosureDispatcher.matchArguments(formals, args); SEXP exprArgument = matchedArguments.findByTag(EXPR_ARGUMENT); SEXP envArgument = matchedArguments.findByTag(ENV_ARGUMENT); // Substitute handles ... in an idiosyncratic way: // Only the first argument is used, and there is no attempt to // match subsequent arguments against the 'env' argument. SEXP expr; if (exprArgument == Symbols.ELLIPSES) { SEXP ellipses = rho.getVariable(Symbols.ELLIPSES); if (ellipses == Null.INSTANCE) { expr = Null.INSTANCE; } else { PromisePairList.Node promisePairList = (PromisePairList.Node) ellipses; Promise promisedArg = (Promise) promisePairList.getValue(); expr = promisedArg.getExpression(); } } else { expr = exprArgument; } return substitute(expr, buildContext(context, rho, envArgument)); }
private static SEXP R_loadMethod(Context context, SEXP def, String fname, Environment ev) { /* since this is called every time a method is dispatched with a definition that has a class, it should be as efficient as possible => we build in knowledge of the standard MethodDefinition and MethodWithNext slots. If these (+ the class slot) don't account for all the attributes, regular dispatch is done. */ int found = 1; /* we "know" the class attribute is there */ found++; // we also have our fake __S4_BIt for renjin PairList attrib = def.getAttributes().asPairList(); for (PairList.Node s : attrib.nodes()) { SEXP t = s.getTag(); if (t == R_target) { ev.setVariable(R_dot_target, s.getValue()); found++; } else if (t == R_defined) { ev.setVariable(R_dot_defined, s.getValue()); found++; } else if (t == R_nextMethod) { ev.setVariable(R_dot_nextMethod, s.getValue()); found++; } else if (t == Symbols.SOURCE) { /* ignore */ found++; } } ev.setVariable(R_dot_Method, def); /* this shouldn't be needed but check the generic being "loadMethod", which would produce a recursive loop */ if (fname.equals("loadMethod")) { return def; } if (found < attrib.length()) { FunctionCall call = FunctionCall.newCall(R_loadMethod_name, def, StringArrayVector.valueOf(fname), ev); return context.evaluate(call, ev); // SEXP e, val; // PROTECT(e = allocVector(LANGSXP, 4)); // SETCAR(e, R_loadMethod_name); val = CDR(e); // SETCAR(val, def); val = CDR(val); // SETCAR(val, fname); val = CDR(val); // SETCAR(val, ev); // val = eval(e, ev); // return val; } else { return def; } }
/** * Returns an iterator over the individual ListExp nodes in this list, or an empty iterator if * exp is the NilExp. * * @param exp A ListExp or null * @throws IllegalArgumentException if the exp is not of type ListExp or NillExp */ public static Iterable<Node> listNodes(PairList exp) { if (exp instanceof Node) { return exp.nodes(); } else { return Collections.emptySet(); } }
@Override public SEXP getVariable(Symbol name) { for (PairList.Node node : list.nodes()) { if (node.getTag() == name) { return node.getValue(); } } return Symbol.UNBOUND_VALUE; }
private PairList substituteArgumentList(PairList arguments) { PairList.Builder builder = PairList.Node.newBuilder(); for (PairList.Node node : arguments.nodes()) { if (node.getValue().equals(Symbols.ELLIPSES)) { SEXP extraArguments = context.getVariable(Symbols.ELLIPSES); if (extraArguments != Symbol.UNBOUND_VALUE) { builder.addAll(unpackPromiseList((PromisePairList) extraArguments)); } else { builder.add(Symbols.ELLIPSES); } } else { builder.add(node.getRawTag(), substitute(node.getValue())); } } return builder.build(); }
@Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Node node = (Node) o; if (nextNode != null ? !nextNode.equals(node.nextNode) : node.nextNode != null) { return false; } if (tag != null ? !tag.equals(node.tag) : node.tag != null) { return false; } if (value != null ? !value.equals(node.value) : node.value != null) { return false; } return true; }
public Builder addAll(PairList list) { for (Node node : list.nodes()) { add(node.getRawTag(), node.getValue()); } return this; }