/*=============================================================================# # Copyright (c) 2008-2016 Stephan Wahlbrink (WalWare.de) and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the GNU Lesser General Public License # v2.1 which accompanies this distribution, and is available at # http://www.gnu.org/licenses/lgpl.html # # Contributors: # Stephan Wahlbrink - initial API and implementation #=============================================================================*/ package de.walware.rj.server.jri; import static de.walware.rj.data.RObjectFactory.F_ONLY_STRUCT; import static de.walware.rj.server.jri.JRIServerErrors.CODE_DATA_ASSIGN_DATA; import static de.walware.rj.server.jri.JRIServerErrors.CODE_DATA_COMMON; import static de.walware.rj.server.jri.JRIServerErrors.CODE_DATA_EVAL_DATA; import static de.walware.rj.server.jri.JRIServerErrors.LOGGER; import java.lang.reflect.Field; import java.util.List; import java.util.concurrent.CancellationException; import java.util.logging.Level; import org.rosuda.JRI.REXP; import org.rosuda.JRI.Rengine; import de.walware.rj.data.RCharacterStore; import de.walware.rj.data.RComplexStore; import de.walware.rj.data.RDataFrame; import de.walware.rj.data.RDataUtil; import de.walware.rj.data.REnvironment; import de.walware.rj.data.RFactorStore; import de.walware.rj.data.RIntegerStore; import de.walware.rj.data.RLanguage; import de.walware.rj.data.RList; import de.walware.rj.data.RLogicalStore; import de.walware.rj.data.RNumericStore; import de.walware.rj.data.RObject; import de.walware.rj.data.RObjectFactory; import de.walware.rj.data.RRawStore; import de.walware.rj.data.RReference; import de.walware.rj.data.RS4Object; import de.walware.rj.data.RStore; import de.walware.rj.data.RVector; import de.walware.rj.data.defaultImpl.RCharacterDataImpl; import de.walware.rj.data.defaultImpl.RDataFrameImpl; import de.walware.rj.data.defaultImpl.RFactorDataImpl; import de.walware.rj.data.defaultImpl.RFactorDataStruct; import de.walware.rj.data.defaultImpl.RFunctionImpl; import de.walware.rj.data.defaultImpl.RMissing; import de.walware.rj.data.defaultImpl.RNull; import de.walware.rj.data.defaultImpl.RObjectFactoryImpl; import de.walware.rj.data.defaultImpl.ROtherImpl; import de.walware.rj.data.defaultImpl.RPromise; import de.walware.rj.data.defaultImpl.RReferenceImpl; import de.walware.rj.data.defaultImpl.RS4ObjectImpl; import de.walware.rj.data.defaultImpl.SimpleRListImpl; import de.walware.rj.server.RjsException; final class JRIServerRni { public static final byte EVAL_MODE_DEFAULT = 0; public static final byte EVAL_MODE_FORCE = 1; public static final byte EVAL_MODE_DATASLOT = 2; public static class RNullPointerException extends RjsException { private static final long serialVersionUID= 1L; public RNullPointerException() { super(0, "R engine returned unexpected null pointer (out of memory?)."); } } private static final String[] EMPTY_STRING_ARRAY = new String[0]; private static final RObject[] EMPTY_ROBJECT_ARRAY = new RObject[0]; private static final String[] DATA_NAME_ARRAY = new String[] { ".Data" }; //$NON-NLS-1$ private final Rengine rEngine; public final long NULL_P; public final long Unbound_P; public final long MissingArg_P; public final long Base_EnvP; public final long BaseNamespace_EnvP; public final long Global_EnvP; public final long Empty_EnvP; public final long Autoload_EnvP; public final long Assign_SymP; public final long Block_SymP; public final long Ellipsis_SymP; public final long at_SymP; public final long edit_SymP; public final long encoding_SymP; public final long env_SymP; public final long expr_SymP; public final long error_SymP; public final long imaginary_SymP; public final long id_SymP; public final long isGeneric_SymP; public final long fdef_SymP; public final long filename_SymP; public final long flags_SymP; public final long function_SymP; public final long from_SymP; public final long lengthOut_SymP; public final long name_SymP; public final long names_SymP; public final long ns_SymP; public final long on_SymP; public final long onExit_SymP; public final long original_SymP; public final long output_SymP; public final long real_SymP; public final long signature_SymP; public final long value_SymP; public final long what_SymP; public final long where_SymP; public final long which_SymP; public final long wd_SymP; public final long x_SymP; public final long z_SymP; public final long TRUE_BoolP; public final long FALSE_BoolP; public final long appFilePath_SymP; public final long appElementId_SymP; public final long dbgElementId_SymP; private final long classSymP; private final long dimnamesSymP; private final long rowNamesSymP; private final long levelsSymP; private final long newSymP; private final long newClassSymP; private final long parentSymP; private final long factorClassStringP; private final long orderedClassStringP; private final long dataframeClassStringP; private final long newEnvFunP; private final long complexFunP; private final long ReFunP; private final long ImFunP; private final long optionsSymP; private final long seqIntFunP; private final long getNamespaceFunP; private final long getNamespaceExportedNamesFunP; private final long getNamespaceExportedValueFunP; private final long tryCatchFunP; private final long slotNamesFunP; private final long getFHeaderFunP; private final long deparseLineXCallP; private final long deparseLinesXCallP; private final long evalErrorHandlerExprP; private final long rniTempEvalClassExprP; public final long rniSafeBaseExecEnvP; public final long rniSafeGlobalExecEnvP; private final long rniTempEnvP; private final long rjTmpEnvP; public final long evalDummy_ExprP; private int rniProtectedCounter; private int stackPos = 0; private int currentDepth; private final int[] currentDepthStack = new int[255]; private int maxDepth; private final int[] maxDepthStack = new int[255]; private int maxEnvsLength = 10000; private final int[] maxEnvsLengthStack = new int[255]; private int maxListsLength = 10000; private final int[] maxListsLengthStack = new int[255]; private boolean rniTempEvalAssigned; boolean rniInterrupted; public JRIServerRni(final Rengine rEngine) throws RjsException { this.rEngine = rEngine; final int savedProtected = saveProtected(); try { this.NULL_P= this.rEngine.rniSpecialObject(Rengine.SO_NilValue); this.Unbound_P= this.rEngine.rniSpecialObject(Rengine.SO_UnboundValue); this.MissingArg_P= this.rEngine.rniSpecialObject(Rengine.SO_MissingArg); this.Base_EnvP= this.rEngine.rniSpecialObject(Rengine.SO_BaseEnv); this.BaseNamespace_EnvP= this.rEngine.rniSpecialObject(Rengine.SO_BaseNamespaceEnv); this.Global_EnvP= this.rEngine.rniSpecialObject(Rengine.SO_GlobalEnv); this.Empty_EnvP= this.rEngine.rniSpecialObject(Rengine.SO_EmptyEnv); { final long p= this.rEngine.rniEval(this.rEngine.rniInstallSymbol(".AutoloadEnv"), //$NON-NLS-1$ this.Base_EnvP ); this.Autoload_EnvP= (p != 0 && this.rEngine.rniExpType(p) == REXP.ENVSXP) ? p : 0; } this.Assign_SymP= this.rEngine.rniInstallSymbol("<-"); //$NON-NLS-1$ this.Block_SymP= this.rEngine.rniInstallSymbol("{"); //$NON-NLS-1$ this.Ellipsis_SymP= this.rEngine.rniInstallSymbol("..."); //$NON-NLS-1$ this.at_SymP= this.rEngine.rniInstallSymbol("at"); //$NON-NLS-1$ this.newClassSymP= this.rEngine.rniInstallSymbol("Class"); //$NON-NLS-1$ this.classSymP= this.rEngine.rniInstallSymbol("class"); //$NON-NLS-1$ this.dimnamesSymP= this.rEngine.rniInstallSymbol("dimnames"); //$NON-NLS-1$ this.edit_SymP= this.rEngine.rniInstallSymbol("edit"); //$NON-NLS-1$ this.encoding_SymP= this.rEngine.rniInstallSymbol("encoding"); //$NON-NLS-1$ this.env_SymP= this.rEngine.rniInstallSymbol("env"); //$NON-NLS-1$ this.error_SymP= this.rEngine.rniInstallSymbol("error"); //$NON-NLS-1$ this.expr_SymP= this.rEngine.rniInstallSymbol("expr"); //$NON-NLS-1$ this.fdef_SymP= this.rEngine.rniInstallSymbol("fdef"); //$NON-NLS-1$ this.filename_SymP= this.rEngine.rniInstallSymbol("filename"); //$NON-NLS-1$ this.flags_SymP= this.rEngine.rniInstallSymbol("flags"); //$NON-NLS-1$ this.function_SymP= this.rEngine.rniInstallSymbol("function"); //$NON-NLS-1$ this.from_SymP= this.rEngine.rniInstallSymbol("from"); //$NON-NLS-1$ this.id_SymP= this.rEngine.rniInstallSymbol("id"); //$NON-NLS-1$ this.isGeneric_SymP= this.rEngine.rniInstallSymbol("isGeneric"); //$NON-NLS-1$ this.imaginary_SymP= this.rEngine.rniInstallSymbol("imaginary"); //$NON-NLS-1$ this.lengthOut_SymP= this.rEngine.rniInstallSymbol("length.out"); //$NON-NLS-1$ this.levelsSymP= this.rEngine.rniInstallSymbol("levels"); //$NON-NLS-1$ this.name_SymP= this.rEngine.rniInstallSymbol("name"); //$NON-NLS-1$ this.names_SymP= this.rEngine.rniInstallSymbol("names"); //$NON-NLS-1$ this.newSymP= this.rEngine.rniInstallSymbol("new"); //$NON-NLS-1$ this.ns_SymP= this.rEngine.rniInstallSymbol("ns"); //$NON-NLS-1$ this.on_SymP= this.rEngine.rniInstallSymbol("on"); //$NON-NLS-1$ this.onExit_SymP= this.rEngine.rniInstallSymbol("on.exit"); //$NON-NLS-1$ this.optionsSymP= this.rEngine.rniInstallSymbol("options"); //$NON-NLS-1$ this.original_SymP= this.rEngine.rniInstallSymbol("original"); //$NON-NLS-1$ this.output_SymP= this.rEngine.rniInstallSymbol("output"); //$NON-NLS-1$ this.parentSymP= this.rEngine.rniInstallSymbol("parent"); //$NON-NLS-1$ this.real_SymP= this.rEngine.rniInstallSymbol("real"); //$NON-NLS-1$ this.rowNamesSymP= this.rEngine.rniInstallSymbol("row.names"); //$NON-NLS-1$ this.signature_SymP= this.rEngine.rniInstallSymbol("signature"); //$NON-NLS-1$ this.value_SymP= this.rEngine.rniInstallSymbol("value"); //$NON-NLS-1$ this.what_SymP= this.rEngine.rniInstallSymbol("what"); //$NON-NLS-1$ this.where_SymP= this.rEngine.rniInstallSymbol("where"); //$NON-NLS-1$ this.which_SymP= this.rEngine.rniInstallSymbol("which"); //$NON-NLS-1$ this.wd_SymP= this.rEngine.rniInstallSymbol("wd"); //$NON-NLS-1$ this.x_SymP= this.rEngine.rniInstallSymbol("x"); //$NON-NLS-1$ this.z_SymP= this.rEngine.rniInstallSymbol("z"); //$NON-NLS-1$ this.appFilePath_SymP= this.rEngine.rniInstallSymbol("statet.Path"); this.appElementId_SymP= this.rEngine.rniInstallSymbol("statet.ElementId"); this.dbgElementId_SymP= this.rEngine.rniInstallSymbol("dbg.ElementId"); this.TRUE_BoolP= checkAndPreserve(this.rEngine.rniPutBoolArray( new boolean[] { true } )); this.FALSE_BoolP= checkAndPreserve(this.rEngine.rniPutBoolArray( new boolean[] { false } )); this.orderedClassStringP= checkAndPreserve(this.rEngine.rniPutStringArray( new String[] { "ordered", "factor" } )); //$NON-NLS-1$ //$NON-NLS-2$ this.factorClassStringP= checkAndPreserve(this.rEngine.rniPutString("factor")); //$NON-NLS-1$ this.dataframeClassStringP= checkAndPreserve(this.rEngine.rniPutString("data.frame")); //$NON-NLS-1$ this.newEnvFunP= checkAndPreserve(this.rEngine.rniEval( this.rEngine.rniInstallSymbol("new.env"), //$NON-NLS-1$ this.Base_EnvP )); this.complexFunP= checkAndPreserve(this.rEngine.rniEval( this.rEngine.rniInstallSymbol("complex"), //$NON-NLS-1$ this.Base_EnvP )); this.ReFunP= checkAndPreserve(this.rEngine.rniEval( this.rEngine.rniInstallSymbol("Re"), //$NON-NLS-1$ this.Base_EnvP )); this.ImFunP= checkAndPreserve(this.rEngine.rniEval( this.rEngine.rniInstallSymbol("Im"), //$NON-NLS-1$ this.Base_EnvP )); this.getNamespaceFunP= checkAndPreserve(this.rEngine.rniEval( this.rEngine.rniInstallSymbol("getNamespace"), //$NON-NLS-1$ this.Base_EnvP )); this.getNamespaceExportedNamesFunP= checkAndPreserve(this.rEngine.rniEval( this.rEngine.rniInstallSymbol("getNamespaceExports"), //$NON-NLS-1$ this.Base_EnvP )); this.getNamespaceExportedValueFunP= checkAndPreserve(this.rEngine.rniEval( this.rEngine.rniInstallSymbol("getExportedValue"), //$NON-NLS-1$ this.Base_EnvP )); this.seqIntFunP= checkAndPreserve(this.rEngine.rniEval( this.rEngine.rniInstallSymbol("seq.int"), //$NON-NLS-1$ this.Base_EnvP )); this.tryCatchFunP= checkAndPreserve(this.rEngine.rniEval( this.rEngine.rniInstallSymbol("tryCatch"), //$NON-NLS-1$ this.Base_EnvP )); this.slotNamesFunP= checkAndPreserve(this.rEngine.rniEval( this.rEngine.rniParse("methods::.slotNames", 1), //$NON-NLS-1$ this.Base_EnvP )); { final long pasteFunP= protect(this.rEngine.rniEval( this.rEngine.rniInstallSymbol("paste"), //$NON-NLS-1$ this.Base_EnvP )); final long deparseFunP= protect(this.rEngine.rniEval( this.rEngine.rniInstallSymbol("deparse"), //$NON-NLS-1$ this.Base_EnvP )); final long controlSymP= this.rEngine.rniInstallSymbol("control"); //$NON-NLS-1$ final long widthCutoffSymP= this.rEngine.rniInstallSymbol("width.cutoff"); //$NON-NLS-1$ final long collapseSymP= this.rEngine.rniInstallSymbol("collapse"); //$NON-NLS-1$ final long deparseControlValueP= protect(this.rEngine.rniPutStringArray( new String[] { "keepInteger", "keepNA" } )); //$NON-NLS-1$ //$NON-NLS-2$ final long collapseValueP= protect(this.rEngine.rniPutString("")); //$NON-NLS-1$ { // function(x)paste(deparse(expr=args(name=x),control=c("keepInteger", "keepNA"),width.cutoff=500L),collapse="") final long fArgsP= protect(this.rEngine.rniCons( this.MissingArg_P, this.NULL_P, this.x_SymP, false )); final long argsFunP= protect(this.rEngine.rniEval( this.rEngine.rniInstallSymbol("args"), //$NON-NLS-1$ this.Base_EnvP )); final long argsCallP= protect(this.rEngine.rniCons( argsFunP, this.rEngine.rniCons( this.x_SymP, this.NULL_P, this.name_SymP, false ), 0, true )); final long deparseCallP= protect(this.rEngine.rniCons( deparseFunP, this.rEngine.rniCons( argsCallP, this.rEngine.rniCons( deparseControlValueP, this.rEngine.rniCons( this.rEngine.rniPutIntArray(new int[] { 500 }), this.NULL_P, widthCutoffSymP, false ), controlSymP, false ), this.expr_SymP, false ), 0, true )); final long fBodyP= this.rEngine.rniCons( pasteFunP, this.rEngine.rniCons( deparseCallP, this.rEngine.rniCons( collapseValueP, this.NULL_P, collapseSymP, false ), 0, false ), 0, true ); this.getFHeaderFunP= checkAndPreserve(this.rEngine.rniEval(this.rEngine.rniCons( this.function_SymP, this.rEngine.rniCons( fArgsP, this.rEngine.rniCons( fBodyP, this.NULL_P, 0, false ), 0, false ), 0, true ), this.Base_EnvP )); } { // paste(deparse(expr=x,control=c("keepInteger", "keepNA"),width.cutoff=500L),collapse="") final long deparseCallP= protect(this.rEngine.rniCons( deparseFunP, this.rEngine.rniCons( this.x_SymP, this.rEngine.rniCons( deparseControlValueP, this.rEngine.rniCons( this.rEngine.rniPutIntArray(new int[] { 500 }), this.NULL_P, widthCutoffSymP, false ), controlSymP, false ), this.expr_SymP, false ), 0, true )); this.deparseLineXCallP= checkAndPreserve(this.rEngine.rniCons( pasteFunP, this.rEngine.rniCons( deparseCallP, this.rEngine.rniCons( collapseValueP, this.NULL_P, collapseSymP, false ), 0, false ), 0, true )); } { // deparse(expr=x,control=c("keepInteger", "keepNA"),width.cutoff=80L) this.deparseLinesXCallP= checkAndPreserve(this.rEngine.rniCons( deparseFunP, this.rEngine.rniCons( this.x_SymP, this.rEngine.rniCons( deparseControlValueP, this.rEngine.rniCons( this.rEngine.rniPutIntArray(new int[] { 80 }), this.NULL_P, widthCutoffSymP, false ), controlSymP, false ), this.expr_SymP, false ), 0, true )); } } this.evalErrorHandlerExprP= checkAndPreserve(this.rEngine.rniCons( this.rEngine.rniEval(this.rEngine.rniParse("function(e){" + "s<-raw(5);" + "class(s)<-\".rj.eval.error\";" + "attr(s,\"error\")<-e;" + "attr(s,\"output\")<-paste(capture.output(print(e)),collapse=\"\\n\");" + "invisible(s);}", 1 ), 0 ), this.NULL_P, this.error_SymP, false )); this.rniTempEvalClassExprP= checkAndPreserve(this.rEngine.rniParse("class(x);", 1)); this.evalDummy_ExprP= checkAndPreserve(this.rEngine.rniParse("1+1;", 1)); this.rniSafeBaseExecEnvP= checkAndPreserve(this.rEngine.rniEval(this.rEngine.rniCons( this.newEnvFunP, this.rEngine.rniCons( this.Base_EnvP, this.NULL_P, this.parentSymP, false ), 0, true ), this.Base_EnvP )); this.rniSafeGlobalExecEnvP= checkAndPreserve(createNewEnv(this.Global_EnvP)); this.rniTempEnvP= checkAndPreserve(createNewEnv(this.Global_EnvP)); this.rjTmpEnvP= this.rEngine.rniEval( this.rEngine.rniParse("rj:::.rj.tmp", 1), this.Base_EnvP ); if (LOGGER.isLoggable(Level.FINER)) { final StringBuilder sb= new StringBuilder("Rni Pointers:"); final Field[] fields= getClass().getDeclaredFields(); for (final Field field : fields) { final String name= field.getName(); if (name.endsWith("P") && Long.TYPE.equals(field.getType())) { sb.append("\n\t"); sb.append(name.substring(0, name.length() - 1)); sb.append("= "); try { final long p= field.getLong(this); sb.append("0x"); sb.append(Long.toHexString(p)); } catch (final Exception e) { sb.append(e.getMessage()); } } } LOGGER.log(Level.FINER, sb.toString()); } if (this.tryCatchFunP == 0) { throw new RjsException(0, "Base functions are missing (check 'Renviron')"); } } finally { looseProtected(savedProtected); } } public Rengine getREngine() { return this.rEngine; } public long protect(final long p) { this.rEngine.rniProtect(p); this.rniProtectedCounter++; return p; } public long checkAndProtect(final long p) throws RNullPointerException { if (p == 0) { throw new RNullPointerException(); } this.rEngine.rniProtect(p); this.rniProtectedCounter++; return p; } public int saveProtected() { return this.rniProtectedCounter; } public void looseProtected(final int saved) { if (this.rniProtectedCounter > saved) { this.rEngine.rniUnprotect(this.rniProtectedCounter - saved); this.rniProtectedCounter = saved; } } public long checkAndPreserve(final long p) throws RNullPointerException { if (p == 0) { throw new RNullPointerException(); } this.rEngine.rniPreserve(p); return p; } public void newDataLevel(final int maxDepth, final int maxEnvLength, final int maxListLength) { this.currentDepthStack[this.stackPos] = this.currentDepth; this.currentDepth = 0; this.maxDepthStack[this.stackPos] = this.maxDepth; this.maxDepth = maxDepth; this.maxEnvsLengthStack[this.stackPos] = this.maxEnvsLength; this.maxEnvsLength = maxEnvLength; this.maxListsLengthStack[this.stackPos] = this.maxListsLength; this.maxListsLength = maxListLength; this.stackPos++; } public void exitDataLevel() { this.stackPos--; this.currentDepth = this.currentDepthStack[this.stackPos]; this.maxDepth = this.maxDepthStack[this.stackPos]; this.maxEnvsLength = this.maxEnvsLengthStack[this.stackPos]; this.maxListsLength = this.maxListsLengthStack[this.stackPos]; if (this.rniTempEvalAssigned) { this.rEngine.rniAssignVarBySym(this.x_SymP, this.NULL_P, this.rniTempEnvP); this.rniTempEvalAssigned = false; } } public long createFCall(final String name, final RList args) throws RjsException { long argsP = this.NULL_P; for (int i = (int) args.getLength() - 1; i >= 0; i--) { final String argName = args.getName(i); final RObject argValue = args.get(i); final long argValueP; if (argValue != null) { argValueP = assignDataObject(argValue); } else { argValueP = this.MissingArg_P; } argsP = protect(this.rEngine.rniCons(argValueP, argsP, (argName != null) ? this.rEngine.rniInstallSymbol(argName) : 0, false )); } long funP; if (name.indexOf(':') > 0) { funP = this.rEngine.rniParse(name, 1); long[] list; if (funP != 0 && (list = this.rEngine.rniGetVector(funP)) != null && list.length == 1) { funP = list[0]; } else { throw new RjsException(CODE_DATA_COMMON | 0x4, "The reference to the function is invalid."); } } else { funP = this.rEngine.rniInstallSymbol(name); } return this.rEngine.rniCons(funP, argsP, 0, true); } public long resolveExpression(final String expression) throws RjsException { final long exprP = this.rEngine.rniParse(expression, -1); if (this.rEngine.rniExpType(exprP) != REXP.EXPRSXP) { throw new RjsException((CODE_DATA_COMMON | 0x3), "The specified expression is invalid (syntax error)." ); } final long[] expressionsP = this.rEngine.rniGetVector(exprP); if (expressionsP == null || expressionsP.length != 1) { throw new RjsException((CODE_DATA_COMMON | 0x3), "The specified expression is invalid (not a single expression)." ); } return expressionsP[0]; } public long resolveEnvironment(final RObject data) throws RjsException { if (data == null) { return this.Global_EnvP; } try { long envP = 0; switch (data.getRObjectType()) { case RObject.TYPE_REFERENCE: envP = ((RReference) data).getHandle(); break; case RObject.TYPE_LANGUAGE: envP = evalExpr(assignDataObject(data), 0, CODE_DATA_COMMON ); break; default: throw new RjsException(CODE_DATA_COMMON, "Unsupported specification."); } if (envP == 0 || this.rEngine.rniExpType(envP) != REXP.ENVSXP) { throw new RjsException(CODE_DATA_COMMON, "Not an environment."); } return envP; } catch (final RjsException e) { throw new RjsException(CODE_DATA_COMMON | 0xa, "Could not resolve the environment.", e); } } public long evalExpr(long exprP, final long envP, final int code) throws RjsException { exprP = this.rEngine.rniCons( this.tryCatchFunP, this.rEngine.rniCons( exprP, this.evalErrorHandlerExprP, this.expr_SymP, false ), 0, true ); final long objP = this.rEngine.rniEval(exprP, envP); if (objP == 0) { if (this.rniInterrupted) { throw new CancellationException(); } throw new IllegalStateException("JRI returned error code " + objP + " (pointer = 0x" + Long.toHexString(exprP) + ")"); } protect(objP); if (this.rEngine.rniExpType(objP) == REXP.RAWSXP) { final String className1 = this.rEngine.rniGetClassAttrString(objP); if (className1 != null && className1.equals(".rj.eval.error")) { String message = null; final long outputP = this.rEngine.rniGetAttrBySym(objP, this.output_SymP); if (outputP != 0) { message = this.rEngine.rniGetString(outputP); } if (message == null) { message = "<no information available>"; } switch (code) { case (CODE_DATA_EVAL_DATA | 0x3): message = "An error occurred when evaluation the specified expression in R " + message + "."; break; case (CODE_DATA_EVAL_DATA | 0x4): message = "An error occurred when evaluation the function in R " + message + "."; break; case (CODE_DATA_ASSIGN_DATA | 0x3): message = "An error occurred when assigning the value to the specified expression in R " + message + "."; break; case (CODE_DATA_ASSIGN_DATA | 0x8): message = "An error occurred when instancing an S4 object in R " + message + "."; break; default: message = message + "."; break; } throw new RjsException(code, message); } } return objP; } /** * Put an {@link RObject RJ R object} into JRI, and get back the pointer to the object * (Java to R). * * @param obj an R object * @return long protected R pointer * @throws RjsException */ public long assignDataObject(final RObject obj) throws RjsException { RStore<?> names; long objP; switch(obj.getRObjectType()) { case RObject.TYPE_NULL: case RObject.TYPE_MISSING: return this.NULL_P; case RObject.TYPE_VECTOR: { objP = assignDataStore(obj.getData()); names = ((RVector<?>) obj).getNames(); if (names != null) { this.rEngine.rniSetAttrBySym(objP, this.names_SymP, assignDataStore(names)); } return objP; } case RObject.TYPE_ARRAY: objP = assignDataStore(obj.getData()); this.rEngine.rniSetAttr(objP, "dim", this.rEngine.rniPutIntArray(((JRIArrayImpl<?>) obj).getJRIDimArray())); return objP; case RObject.TYPE_DATAFRAME: { final RDataFrame list = (RDataFrame) obj; final long length = list.getLength(); if (length > Integer.MAX_VALUE) { throw new UnsupportedOperationException("long list"); } final long[] itemPs = new long[(int) length]; for (int i = 0; i < length; i++) { itemPs[i] = assignDataStore(list.getColumn(i)); } objP= checkAndProtect(this.rEngine.rniPutVector(itemPs)); names = list.getNames(); if (names != null) { this.rEngine.rniSetAttrBySym(objP, this.names_SymP, assignDataStore(names)); } names = list.getRowNames(); this.rEngine.rniSetAttrBySym(objP, this.rowNamesSymP, (names != null) ? assignDataStore(names) : seqLength(list.getRowCount()) ); this.rEngine.rniSetAttrBySym(objP, this.classSymP, this.dataframeClassStringP); return objP; } case RObject.TYPE_LIST: { final RList list = (RList) obj; final long length = list.getLength(); if (length > Integer.MAX_VALUE) { throw new UnsupportedOperationException("long list"); } final long[] itemPs = new long[(int) length]; final int savedProtectedCounter = this.rniProtectedCounter; for (int i = 0; i < length; i++) { itemPs[i] = assignDataObject(list.get(i)); } if (this.rniProtectedCounter > savedProtectedCounter) { this.rEngine.rniUnprotect(this.rniProtectedCounter - savedProtectedCounter); this.rniProtectedCounter = savedProtectedCounter; } objP= checkAndProtect(this.rEngine.rniPutVector(itemPs)); names = list.getNames(); if (names != null) { this.rEngine.rniSetAttrBySym(objP, this.names_SymP, assignDataStore(names)); } return objP; } case RObject.TYPE_REFERENCE: return ((RReference) obj).getHandle(); case RObject.TYPE_S4OBJECT: { final RS4Object s4obj = (RS4Object) obj; objP = this.NULL_P; for (int i = (int) s4obj.getLength()-1; i >= 0; i--) { final RObject slotObj = s4obj.get(i); if (slotObj != null && slotObj.getRObjectType() != RObject.TYPE_MISSING) { objP= checkAndProtect(this.rEngine.rniCons( assignDataObject(slotObj), objP, this.rEngine.rniInstallSymbol(s4obj.getName(i)), false )); } } return protect(evalExpr(this.rEngine.rniCons( this.newSymP, this.rEngine.rniCons( this.rEngine.rniPutString(s4obj.getRClassName()), objP, this.newClassSymP, false ), 0, true ), this.rniSafeGlobalExecEnvP, (CODE_DATA_ASSIGN_DATA | 0x8) )); } case RObject.TYPE_LANGUAGE: { final RLanguage lang = (RLanguage) obj; if (lang.getLanguageType() == RLanguage.NAME) { return this.rEngine.rniInstallSymbol(lang.getSource()); } objP = this.rEngine.rniParse(lang.getSource(), -1); if (objP == 0) { throw new RjsException(CODE_DATA_ASSIGN_DATA | 0x9, "The language data is invalid."); } switch (lang.getLanguageType()) { case RLanguage.EXPRESSION: return protect(objP); case RLanguage.CALL: { final long[] list = this.rEngine.rniGetVector(objP); if (list != null && list.length == 1 && this.rEngine.rniExpType(list[0]) == REXP.LANGSXP ) { return protect(list[0]); } break; } case 0: // auto final long[] list = this.rEngine.rniGetVector(objP); if (list != null && list.length == 1) { return protect(list[0]); } //$FALL-THROUGH$ default: return protect(objP); } break; } default: break; } throw new RjsException((CODE_DATA_ASSIGN_DATA | 0x7), "The instantiation of R objects of type " + RDataUtil.getObjectTypeName(obj.getRObjectType()) + " in R is not yet supported." ); } public long assignDataStore(final RStore<?> data) throws RNullPointerException { switch (data.getStoreType()) { case RStore.LOGICAL: return checkAndProtect(this.rEngine.rniPutBoolArrayI( ((JRILogicalDataImpl) data).getJRIValueArray() )); case RStore.INTEGER: return checkAndProtect(this.rEngine.rniPutIntArray( ((JRIIntegerDataImpl) data).getJRIValueArray() )); case RStore.NUMERIC: return checkAndProtect(this.rEngine.rniPutDoubleArray( ((JRINumericDataImpl) data).getJRIValueArray() )); case RStore.COMPLEX: { final JRIComplexDataShortImpl complex = (JRIComplexDataShortImpl) data; final long realP= checkAndProtect(this.rEngine.rniPutDoubleArray( complex.getJRIRealValueArray() )); final long imaginaryP= checkAndProtect(this.rEngine.rniPutDoubleArray( complex.getJRIImaginaryValueArray() )); return checkAndProtect(this.rEngine.rniEval(this.rEngine.rniCons( this.complexFunP, this.rEngine.rniCons( realP, this.rEngine.rniCons( imaginaryP, this.NULL_P, this.imaginary_SymP, false ), this.real_SymP, false ), 0, true ), this.rniSafeBaseExecEnvP )); } case RStore.CHARACTER: return checkAndProtect(this.rEngine.rniPutStringArray( ((JRICharacterDataImpl) data).getJRIValueArray() )); case RStore.RAW: return checkAndProtect(this.rEngine.rniPutRawArray( ((JRIRawDataImpl) data).getJRIValueArray() )); case RStore.FACTOR: { final JRIFactorDataImpl factor = (JRIFactorDataImpl) data; final long objP= checkAndProtect(this.rEngine.rniPutIntArray( factor.getJRIValueArray() )); this.rEngine.rniSetAttrBySym(objP, this.levelsSymP, this.rEngine.rniPutStringArray(factor.getJRILevelsArray()) ); this.rEngine.rniSetAttrBySym(objP, this.classSymP, factor.isOrdered() ? this.orderedClassStringP : this.factorClassStringP ); return objP; } default: throw new UnsupportedOperationException("Data storage of type " + data.getStoreType() + " are not yet supported."); } } public RObject createDataObject(final long objP, final int flags) { if (objP == 0) { throw new IllegalArgumentException("objP: 0x0"); } if (this.maxDepth > 0) { return createDataObject(objP, flags, EVAL_MODE_FORCE); } else { final RObject rObject = createDataObject(objP, (flags | F_ONLY_STRUCT), EVAL_MODE_FORCE); return new RReferenceImpl(objP, rObject.getRObjectType(), rObject.getRClassName()); } } /** * Returns {@link RObject RJ/R object} for the given R pointer * (R to Java). * * @param objP a valid pointer to an object in R * @param objTmp an optional R expression pointing to the same object in R * @param flags to configure the data to create * @param force forces the creation of the object (ignoring the depth etc.) * @return new created R object */ public RObject createDataObject(long objP, final int flags, final byte mode) { if (mode == EVAL_MODE_DEFAULT && (this.currentDepth >= this.maxDepth)) { return null; } this.currentDepth++; try { int rType = this.rEngine.rniExpType(objP); if (rType == REXP.PROMSXP) { objP = this.rEngine.rniGetPromise(objP, ((flags & RObjectFactory.F_LOAD_PROMISE) != 0) ? 2 : 1); if (objP == 0) { return RPromise.INSTANCE; } rType = this.rEngine.rniExpType(objP); } switch (rType) { case REXP.NILSXP: return RNull.INSTANCE; case REXP.LGLSXP: { // logical vector / array final String className1; if (mode != EVAL_MODE_DATASLOT) { if (this.rEngine.rniIsS4(objP)) { return createS4Obj(objP, REXP.LGLSXP, flags); } className1 = this.rEngine.rniGetClassAttrString(objP); } else { className1 = null; } final int[] dim = this.rEngine.rniGetArrayDim(objP); if (dim != null) { return ((flags & F_ONLY_STRUCT) != 0) ? new JRIArrayImpl<RLogicalStore>( RObjectFactoryImpl.LOGI_STRUCT_DUMMY, className1, dim ) : new JRIArrayImpl<RLogicalStore>( new JRILogicalDataImpl(this.rEngine.rniGetBoolArrayI(objP)), className1, dim, getDimNames(objP, dim.length) ); } else { return ((flags & F_ONLY_STRUCT) != 0) ? new JRIVectorImpl<RLogicalStore>( RObjectFactoryImpl.LOGI_STRUCT_DUMMY, this.rEngine.rniGetVectorLength(objP), className1, null ) : new JRIVectorImpl<RLogicalStore>( new JRILogicalDataImpl(this.rEngine.rniGetBoolArrayI(objP)), className1, getNames(objP) ); } } case REXP.INTSXP: { // integer vector / array final String className1; if (mode != EVAL_MODE_DATASLOT) { if (this.rEngine.rniIsS4(objP)) { return createS4Obj(objP, REXP.INTSXP, flags); } className1 = this.rEngine.rniGetClassAttrString(objP); } else { className1 = null; } if (className1 != null && (className1.equals("factor") || className1.equals("ordered") || this.rEngine.rniInherits(objP, "factor")) ) { final String[] levels; { final long levelsP = this.rEngine.rniGetAttrBySym(objP, this.levelsSymP); levels = (levelsP != 0) ? this.rEngine.rniGetStringArray(levelsP) : null; } if (levels != null) { final boolean isOrdered = className1.equals("ordered") || this.rEngine.rniInherits(objP, "ordered"); final RFactorStore factorData = ((flags & F_ONLY_STRUCT) != 0) ? new RFactorDataStruct(isOrdered, levels.length) : new RFactorDataImpl(this.rEngine.rniGetIntArray(objP), isOrdered, levels); return ((flags & F_ONLY_STRUCT) != 0) ? new JRIVectorImpl<RIntegerStore>( factorData, this.rEngine.rniGetVectorLength(objP), className1, null ) : new JRIVectorImpl<RIntegerStore>( factorData, className1, getNames(objP) ); } } final int[] dim = this.rEngine.rniGetArrayDim(objP); if (dim != null) { return ((flags & F_ONLY_STRUCT) != 0) ? new JRIArrayImpl<RIntegerStore>( RObjectFactoryImpl.INT_STRUCT_DUMMY, className1, dim ) : new JRIArrayImpl<RIntegerStore>( new JRIIntegerDataImpl(this.rEngine.rniGetIntArray(objP)), className1, dim, getDimNames(objP, dim.length) ); } else { return ((flags & F_ONLY_STRUCT) != 0) ? new JRIVectorImpl<RIntegerStore>( RObjectFactoryImpl.INT_STRUCT_DUMMY, this.rEngine.rniGetVectorLength(objP), className1, null ) : new JRIVectorImpl<RIntegerStore>( new JRIIntegerDataImpl(this.rEngine.rniGetIntArray(objP)), className1, getNames(objP) ); } } case REXP.REALSXP: { // numeric vector / array final String className1; if (mode != EVAL_MODE_DATASLOT) { if (this.rEngine.rniIsS4(objP)) { return createS4Obj(objP, REXP.REALSXP, flags); } className1 = this.rEngine.rniGetClassAttrString(objP); } else { className1 = null; } final int[] dim = this.rEngine.rniGetArrayDim(objP); if (dim != null) { return ((flags & F_ONLY_STRUCT) != 0) ? new JRIArrayImpl<>( RObjectFactoryImpl.NUM_STRUCT_DUMMY, className1, dim ) : new JRIArrayImpl<RNumericStore>( new JRINumericDataImpl(this.rEngine.rniGetDoubleArray(objP)), className1, dim, getDimNames(objP, dim.length) ); } else { return ((flags & F_ONLY_STRUCT) != 0) ? new JRIVectorImpl<>( RObjectFactoryImpl.NUM_STRUCT_DUMMY, this.rEngine.rniGetVectorLength(objP), className1, null ) : new JRIVectorImpl<RNumericStore>( new JRINumericDataImpl(this.rEngine.rniGetDoubleArray(objP)), className1, getNames(objP) ); } } case REXP.CPLXSXP: { // complex vector / array final String className1; if (mode != EVAL_MODE_DATASLOT) { if (this.rEngine.rniIsS4(objP)) { return createS4Obj(objP, REXP.CPLXSXP, flags); } className1 = this.rEngine.rniGetClassAttrString(objP); } else { className1 = null; } final int[] dim = this.rEngine.rniGetArrayDim(objP); if (dim != null) { return ((flags & F_ONLY_STRUCT) != 0) ? new JRIArrayImpl<RComplexStore>( RObjectFactoryImpl.CPLX_STRUCT_DUMMY, className1, dim ) : new JRIArrayImpl<RComplexStore>( new JRIComplexDataShortImpl(getComplexRe(objP), getComplexIm(objP)), className1, dim, getDimNames(objP, dim.length) ); } else { return ((flags & F_ONLY_STRUCT) != 0) ? new JRIVectorImpl<RComplexStore>( RObjectFactoryImpl.CPLX_STRUCT_DUMMY, this.rEngine.rniGetVectorLength(objP), className1, null ) : new JRIVectorImpl<RComplexStore>( new JRIComplexDataShortImpl(getComplexRe(objP), getComplexIm(objP)), className1, getNames(objP) ); } } case REXP.STRSXP: { // character vector / array final String className1; if (mode != EVAL_MODE_DATASLOT) { if (this.rEngine.rniIsS4(objP)) { return createS4Obj(objP, REXP.STRSXP, flags); } className1 = this.rEngine.rniGetClassAttrString(objP); } else { className1 = null; } final int[] dim = this.rEngine.rniGetArrayDim(objP); if (dim != null) { return ((flags & F_ONLY_STRUCT) != 0) ? new JRIArrayImpl<RCharacterStore>( RObjectFactoryImpl.CHR_STRUCT_DUMMY, className1, dim ) : new JRIArrayImpl<RCharacterStore>( new JRICharacterDataImpl(this.rEngine.rniGetStringArray(objP)), className1, dim, getDimNames(objP, dim.length) ); } else { return ((flags & F_ONLY_STRUCT) != 0) ? new JRIVectorImpl<RCharacterStore>( RObjectFactoryImpl.CHR_STRUCT_DUMMY, this.rEngine.rniGetVectorLength(objP), className1, null ) : new JRIVectorImpl<RCharacterStore>( new JRICharacterDataImpl(this.rEngine.rniGetStringArray(objP)), className1, getNames(objP) ); } } case REXP.RAWSXP: { // raw/byte vector final String className1; if (mode != EVAL_MODE_DATASLOT) { if (this.rEngine.rniIsS4(objP)) { return createS4Obj(objP, REXP.RAWSXP, flags); } className1 = this.rEngine.rniGetClassAttrString(objP); } else { className1 = null; } final int[] dim = this.rEngine.rniGetArrayDim(objP); if (dim != null) { return ((flags & F_ONLY_STRUCT) != 0) ? new JRIArrayImpl<RRawStore>( RObjectFactoryImpl.RAW_STRUCT_DUMMY, className1, dim ) : new JRIArrayImpl<RRawStore>( new JRIRawDataImpl(this.rEngine.rniGetRawArray(objP)), className1, dim, getDimNames(objP, dim.length) ); } else { return ((flags & F_ONLY_STRUCT) != 0) ? new JRIVectorImpl<RRawStore>( RObjectFactoryImpl.RAW_STRUCT_DUMMY, this.rEngine.rniGetVectorLength(objP), className1, null ) : new JRIVectorImpl<RRawStore>( new JRIRawDataImpl(this.rEngine.rniGetRawArray(objP)), className1, getNames(objP) ); } } case REXP.VECSXP: { // generic vector / list final String className1; if (mode != EVAL_MODE_DATASLOT) { className1 = this.rEngine.rniGetClassAttrString(objP); } else { className1 = null; } final long length = this.rEngine.rniGetVectorLength(objP); if (length > Integer.MAX_VALUE) { if ((flags & F_ONLY_STRUCT) != 0) { return new JRIListLongImpl(length, className1); } throw new UnsupportedOperationException("long list"); } final long[] itemP = this.rEngine.rniGetVector(objP); DATA_FRAME: if (className1 != null && (className1.equals("data.frame") || this.rEngine.rniInherits(objP, "data.frame")) ) { final RObject[] itemObjects = new RObject[itemP.length]; long rowCount = -1; for (int i = 0; i < itemP.length; i++) { if (this.rniInterrupted) { throw new CancellationException(); } itemObjects[i] = createDataObject(itemP[i], flags, EVAL_MODE_FORCE); if (itemObjects[i] == null || itemObjects[i].getRObjectType() != RObject.TYPE_VECTOR) { break DATA_FRAME; } else if (rowCount == -1) { rowCount = itemObjects[i].getLength(); } else if (rowCount != itemObjects[i].getLength()){ break DATA_FRAME; } } final String[] rowNames = ((flags & F_ONLY_STRUCT) != 0) ? null : getRowNames(objP); if (rowNames != null && rowCount != -1 && rowNames.length != rowCount) { break DATA_FRAME; } return new RDataFrameImpl(itemObjects, className1, getNames(objP), rowNames); } if (((flags & F_ONLY_STRUCT) != 0 && length > this.maxListsLength) || this.currentDepth >= this.maxDepth ) { return new JRIListLongImpl(length, className1); } { final RObject[] itemObjects = new RObject[itemP.length]; for (int i = 0; i < itemP.length; i++) { if (this.rniInterrupted) { throw new CancellationException(); } itemObjects[i] = createDataObject(itemP[i], flags, EVAL_MODE_DEFAULT); } return new JRIListImpl(itemObjects, className1, getNames(objP)); } } case REXP.LISTSXP: // pairlist /*case REXP.LANGSXP: */{ String className1; if (mode == EVAL_MODE_DATASLOT || (className1 = this.rEngine.rniGetClassAttrString(objP)) == null ) { className1 = RObject.CLASSNAME_PAIRLIST; } long cdr = objP; final int length = this.rEngine.rniGetLength(objP); final String[] itemNames = new String[length]; final RObject[] itemObjects = new RObject[length]; for (int i = 0; i < length && cdr != 0; i++) { if (this.rniInterrupted) { throw new CancellationException(); } final long car = this.rEngine.rniCAR(cdr); final long tag = this.rEngine.rniTAG(cdr); itemNames[i] = (tag != 0) ? this.rEngine.rniGetSymbolName(tag) : null; itemObjects[i] = createDataObject(car, flags, EVAL_MODE_DEFAULT); cdr = this.rEngine.rniCDR(cdr); } return new JRIListImpl(itemObjects, className1, itemNames); } case REXP.ENVSXP: { if (this.currentDepth > 1 && (flags & RObjectFactory.F_LOAD_ENVIR) == 0) { return new RReferenceImpl(objP, RObject.TYPE_ENV, "environment"); } final long namesStrP= protect(this.rEngine.rniListEnv(objP, true)); final String[] names = this.rEngine.rniGetStringArray(namesStrP); if (names != null) { if (objP == this.Autoload_EnvP || objP == this.rjTmpEnvP || names.length > this.maxEnvsLength) { return createEnvObject(objP, null, null, names.length, (mode != EVAL_MODE_DATASLOT) ); } final RObject[] itemObjects = new RObject[names.length]; for (int i = 0; i < names.length; i++) { if (this.rniInterrupted) { throw new CancellationException(); } final long nameSymP= this.rEngine.rniInstallSymbolByStr(namesStrP, i); final long itemP= this.rEngine.rniGetVarBySym(nameSymP, objP, Rengine.FLAG_UNBOUND_P); if (itemP != 0) { protect(itemP); itemObjects[i] = createDataObject(itemP, flags, EVAL_MODE_DEFAULT); continue; } else { itemObjects[i] = RMissing.INSTANCE; continue; } } return createEnvObject(objP, itemObjects, names, names.length, (mode != EVAL_MODE_DATASLOT) ); } break; } case REXP.CLOSXP: { if (mode != EVAL_MODE_DATASLOT && this.rEngine.rniIsS4(objP)) { return createS4Obj(objP, REXP.CLOSXP, flags); } final String header = getFHeader(objP); return new RFunctionImpl(header); } case REXP.SPECIALSXP: case REXP.BUILTINSXP: { final String header = getFHeader(objP); return new RFunctionImpl(header); } case REXP.S4SXP: { if (mode != EVAL_MODE_DATASLOT) { return createS4Obj(objP, REXP.S4SXP, flags); } break; // invalid } case REXP.SYMSXP: { if (objP == this.MissingArg_P) { return RMissing.INSTANCE; } return ((flags & F_ONLY_STRUCT) != 0) ? new JRILanguageImpl(RLanguage.NAME, null) : new JRILanguageImpl(RLanguage.NAME, this.rEngine.rniGetSymbolName(objP), null); } case REXP.LANGSXP: { final String className1; if (mode != EVAL_MODE_DATASLOT) { className1 = this.rEngine.rniGetClassAttrString(objP); } else { className1 = null; } return ((flags & F_ONLY_STRUCT) != 0) ? new JRILanguageImpl(RLanguage.CALL, className1) : new JRILanguageImpl(RLanguage.CALL, getSourceLine(objP), className1); } case REXP.EXPRSXP: { String className1; if (mode == EVAL_MODE_DATASLOT || (className1 = this.rEngine.rniGetClassAttrString(objP)) == null ) { className1 = null; } return ((flags & F_ONLY_STRUCT) != 0) ? new JRILanguageImpl(RLanguage.EXPRESSION, className1) : new JRILanguageImpl(RLanguage.EXPRESSION, getSourceLine(objP), className1); } case REXP.EXTPTRSXP: { String className1; if (mode == EVAL_MODE_DATASLOT || (className1 = this.rEngine.rniGetClassAttrString(objP)) == null ) { className1 = "externalptr"; } return new ROtherImpl(className1); } } // final long classP = this.rEngine.rniEval(this.rEngine.rniCons(this.classFunP, // this.rEngine.rniCons(objP, this._NULL_P, , false), 0, true), // this._Base_EnvP); { // Other type and fallback final String className1 = getClassSave(objP); return new ROtherImpl(className1); } } finally { this.currentDepth--; } } private RObject createS4Obj(final long objP, final int rType, final int flags) { final long classP = this.rEngine.rniGetAttrBySym(objP, this.classSymP); String className = null; if (classP != 0 && classP != this.NULL_P) { className = this.rEngine.rniGetString(classP); final long slotNamesP = this.rEngine.rniEval(this.rEngine.rniCons( this.slotNamesFunP, this.rEngine.rniCons( classP, this.NULL_P, this.x_SymP, false ), 0, true ), this.rniSafeGlobalExecEnvP ); if (slotNamesP != 0) { final String[] slotNames = this.rEngine.rniGetStringArray(slotNamesP); if (slotNames != null && slotNames.length > 0) { final RObject[] slotValues = new RObject[slotNames.length]; for (int i = 0; i < slotNames.length; i++) { if (this.rniInterrupted) { throw new CancellationException(); } if (".Data".equals(slotNames[i])) { slotValues[i] = createDataObject(objP, flags, EVAL_MODE_DATASLOT); if (className == null && slotValues[i] != null) { className = slotValues[i].getRClassName(); } continue; } else { final long slotValueP; if ((slotValueP = this.rEngine.rniGetAttr(objP, slotNames[i])) != 0) { slotValues[i] = createDataObject(slotValueP, flags, EVAL_MODE_FORCE); continue; } else { slotValues[i] = RMissing.INSTANCE; continue; } } } if (className == null) { className = getClassSave(objP); } return new RS4ObjectImpl(className, slotNames, slotValues); } } } if (rType != REXP.S4SXP) { final RObject dataSlot = createDataObject(objP, flags, EVAL_MODE_DATASLOT); if (dataSlot != null) { if (className == null) { className = dataSlot.getRClassName(); if (className == null) { className = getClassSave(objP); } } return new RS4ObjectImpl(className, DATA_NAME_ARRAY, new RObject[] { dataSlot }); } if (className == null) { className = getClassSave(objP); } } else if (className == null) { className = "S4"; } return new RS4ObjectImpl(className, EMPTY_STRING_ARRAY, EMPTY_ROBJECT_ARRAY); } private String getClassSave(final long objP) { if (objP != 0) { final String className1; final long classP; this.rniTempEvalAssigned = true; if (this.rEngine.rniAssignVarBySym(this.x_SymP, objP, this.rniTempEnvP) && (classP = this.rEngine.rniEval(this.rniTempEvalClassExprP, this.rniTempEnvP)) != 0 && (className1 = this.rEngine.rniGetString(classP)) != null ) { return className1; } } return "<unknown>"; } private String[] getNames(final long objP) { final long namesP= this.rEngine.rniGetAttrBySym(objP, this.names_SymP); return (namesP != 0) ? this.rEngine.rniGetStringArray(namesP) : null; } private SimpleRListImpl<RCharacterStore> getDimNames(final long objP, final int length) { final long namesP= this.rEngine.rniGetAttrBySym(objP, this.dimnamesSymP); final long[] names1P; if (this.rEngine.rniExpType(namesP) == REXP.VECSXP && (names1P= this.rEngine.rniGetVector(namesP)) != null && names1P.length == length) { String[] s = getNames(namesP); final RCharacterDataImpl names0 = (s != null) ? new RCharacterDataImpl(s) : new RCharacterDataImpl(names1P.length); final RCharacterStore[] names1 = new RCharacterStore[names1P.length]; for (int i = 0; i < names1P.length; i++) { s = this.rEngine.rniGetStringArray(names1P[i]); if (s != null) { names1[i] = new RCharacterDataImpl(s); } } return new SimpleRListImpl<>(names1, names0); } return null; } private String[] getRowNames(final long objP) { final long namesP = this.rEngine.rniGetAttrBySym(objP, this.rowNamesSymP); return (namesP != 0) ? this.rEngine.rniGetStringArray(namesP) : null; } private double[] getComplexRe(final long objP) { final long numP = this.rEngine.rniEval(this.rEngine.rniCons( this.ReFunP, this.rEngine.rniCons( objP, this.NULL_P, this.z_SymP, false ), 0, true ), this.rniSafeBaseExecEnvP ); final double[] num; if (numP != 0 && ((num = this.rEngine.rniGetDoubleArray(numP)) != null) ) { return num; } if (this.rniInterrupted) { throw new CancellationException(); } throw new RuntimeException("Failed to load values of real part of complex."); } private double[] getComplexIm(final long objP) { final long numP = this.rEngine.rniEval(this.rEngine.rniCons( this.ImFunP, this.rEngine.rniCons( objP, this.NULL_P, this.z_SymP, false ), 0, true ), this.rniSafeBaseExecEnvP ); final double[] num; if (numP != 0 && ((num = this.rEngine.rniGetDoubleArray(numP)) != null) ) { return num; } if (this.rniInterrupted) { throw new CancellationException(); } throw new RuntimeException("Failed to load values of imaginary part of complex."); } private String getFHeader(final long cloP) { final long argsP= this.rEngine.rniEval(this.rEngine.rniCons( this.getFHeaderFunP, this.rEngine.rniCons( cloP, this.NULL_P, this.x_SymP, false ), 0, true ), this.rniSafeGlobalExecEnvP ); final String args; if (argsP != 0 && (args = this.rEngine.rniGetString(argsP)) != null && args.length() >= 11 ) { // "function ()".length // return args.substring(9,); return args; } return null; } long createNewEnv(final long parentP) { if (parentP == 0) { throw new IllegalArgumentException("Missing parent for new environment."); } return this.rEngine.rniEval(this.rEngine.rniCons( this.newEnvFunP, this.rEngine.rniCons( parentP, this.NULL_P, this.parentSymP, false ), 0, true ), this.rniSafeBaseExecEnvP ); } private long getNamespaceEnvP(final String nsName) throws RjsException { if (nsName == null) { throw new IllegalArgumentException("Missing name for namespace."); } final long p= this.rEngine.rniEval(this.rEngine.rniCons( this.getNamespaceFunP, this.rEngine.rniCons( this.rEngine.rniPutString(nsName), this.NULL_P, this.name_SymP, false ), 0, true ), this.rniSafeBaseExecEnvP ); if (p != 0) { return p; } throw new RjsException(0, "Namespace '" + nsName + "' not available."); } public RObject getNamespaceEnv(final String nsName, final int flags) throws RjsException { final long envP= getNamespaceEnvP(nsName); if (this.maxDepth == 0) { return new RReferenceImpl(envP, RObject.TYPE_ENV, RObject.CLASSNAME_ENV); } return createDataObject(envP, flags, EVAL_MODE_FORCE); } public RObject getNamespaceExportsEnv(final String nsName, final int flags) throws RjsException { final long envP= getNamespaceEnvP(nsName); if (this.maxDepth == 0) { final String className1= this.rEngine.rniGetClassAttrString(envP); return new RReferenceImpl(0, RObject.TYPE_ENV, (className1 != null) ? className1 : RObject.CLASSNAME_ENV ); } this.currentDepth++; try { final long namesStrP= this.rEngine.rniEval(this.rEngine.rniCons( this.getNamespaceExportedNamesFunP, this.rEngine.rniCons( envP, this.NULL_P, this.ns_SymP, false ), 0, true ), this.rniSafeBaseExecEnvP ); if (namesStrP != 0) { protect(namesStrP); final String[] names= this.rEngine.rniGetStringArray(namesStrP); if (names != null) { final RObject[] itemObjects= new RObject[names.length]; for (int i = 0; i < names.length; i++) { if (this.rniInterrupted) { throw new CancellationException(); } final long itemP= this.rEngine.rniEval(this.rEngine.rniCons( this.getNamespaceExportedValueFunP, this.rEngine.rniCons( envP, this.rEngine.rniCons( this.rEngine.rniPutStringByStr(namesStrP, i), this.NULL_P, this.name_SymP, false ), this.ns_SymP, false ), 0, true ), this.rniSafeBaseExecEnvP ); if (itemP != 0) { protect(itemP); itemObjects[i]= createDataObject(itemP, flags, EVAL_MODE_DEFAULT); continue; } else { itemObjects[i] = RMissing.INSTANCE; continue; } } return new JRIEnvironmentImpl(nsName, 0, itemObjects, names, names.length, REnvironment.ENVTYPE_NAMESPACE_EXPORTS, null ); } } return new JRIEnvironmentImpl(nsName, 0, EMPTY_ROBJECT_ARRAY, EMPTY_STRING_ARRAY, 0, REnvironment.ENVTYPE_NAMESPACE_EXPORTS, null ); } finally { this.currentDepth--; } } public boolean isInternEnv(final long envP) { return (envP == this.rjTmpEnvP || envP == this.rniSafeBaseExecEnvP || envP == this.rniSafeGlobalExecEnvP ); } public void addAllEnvs(final List<Long> envs, long envP) { while (envP != 0 && envP != this.Empty_EnvP) { final Long handler= Long.valueOf(envP); if (envs.contains(handler)) { return; } envs.add(handler); envP= this.rEngine.rniParentEnv(envP); } } public long seqLength(final double length) { return this.rEngine.rniEval(this.rEngine.rniCons( this.seqIntFunP, this.rEngine.rniCons( this.rEngine.rniPutDoubleArray(new double[] { length }), this.NULL_P, this.lengthOut_SymP, false ), 0, true ), this.rniSafeBaseExecEnvP ); } public String getSourceLine(final long objP) { this.rniTempEvalAssigned = true; if (this.rEngine.rniAssignVarBySym(this.x_SymP, objP, this.rniTempEnvP)) { final String line; final long lineP= this.rEngine.rniEval(this.deparseLineXCallP, this.rniTempEnvP); if (lineP != 0 && (line = this.rEngine.rniGetString(lineP)) != null && line.length() > 0 ) { // return args.substring(9,); return line; } } return null; } public String[] getSourceLines(final long objP) { this.rniTempEvalAssigned = true; if (this.rEngine.rniAssignVarBySym(this.x_SymP, objP, this.rniTempEnvP)) { final long linesP= this.rEngine.rniEval(this.deparseLinesXCallP, this.rniTempEnvP); if (linesP != 0) { return this.rEngine.rniGetStringArray(linesP); } } return null; } public boolean setOption(final long symP, final long valP) { final long p= this.rEngine.rniEval(this.rEngine.rniCons( this.optionsSymP, this.rEngine.rniCons( valP, this.NULL_P, symP, false), 0, true), this.rniSafeGlobalExecEnvP ); return (p != 0); } public JRIEnvironmentImpl createEnvObject(final long objP, final RObject[] itemObjects, final String[] names, final int length, final boolean loadClassName) { final byte type; String envName; if (objP == this.Base_EnvP) { type= REnvironment.ENVTYPE_BASE; envName= REnvironment.ENVNAME_BASE; } else if (objP == this.Global_EnvP) { type= REnvironment.ENVTYPE_GLOBAL; envName= REnvironment.ENVNAME_GLOBAL; } else if (objP == this.Empty_EnvP) { type= REnvironment.ENVTYPE_EMTPY; envName= REnvironment.ENVNAME_EMPTY; } else if (objP == this.BaseNamespace_EnvP) { type= REnvironment.ENVTYPE_NAMESPACE; envName= REnvironment.ENVNAME_BASE; } else if (objP == this.Autoload_EnvP) { type= REnvironment.ENVTYPE_AUTOLOADS; envName= REnvironment.ENVNAME_AUTOLOADS; } else { envName= this.rEngine.rniGetNamespaceEnvName(objP); if (envName != null) { type= REnvironment.ENVTYPE_NAMESPACE; } else { envName= this.rEngine.rniGetAttrStringBySym(objP, this.name_SymP); if (envName != null && envName.startsWith("package:")) { type= REnvironment.ENVTYPE_PACKAGE; } else { type= 0; } } } return new JRIEnvironmentImpl(envName, objP, itemObjects, names, length, type, (loadClassName) ? this.rEngine.rniGetClassAttrString(objP) : null ); } }