blob: 47077aa3a44b402d0bd2f502e86ddab801626f84 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2010, 2019 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.internal.r.debug.core.model;
import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IVariable;
import org.eclipse.statet.jcommons.lang.NonNull;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.lang.ObjectUtils;
import org.eclipse.statet.jcommons.status.ProgressMonitor;
import org.eclipse.statet.jcommons.status.StatusException;
import org.eclipse.statet.r.core.data.CombinedRElement;
import org.eclipse.statet.r.core.data.RValueFormatter;
import org.eclipse.statet.r.core.model.RElementName;
import org.eclipse.statet.r.debug.core.IRVariable;
import org.eclipse.statet.r.nico.ICombinedRDataAdapter;
import org.eclipse.statet.rj.data.RLanguage;
import org.eclipse.statet.rj.data.RObject;
import org.eclipse.statet.rj.data.UnexpectedRDataException;
import org.eclipse.statet.rj.data.impl.RPromiseImpl;
import org.eclipse.statet.rj.services.FQRObject;
import org.eclipse.statet.rj.services.FQRObjectRef;
import org.eclipse.statet.rj.services.RService;
import org.eclipse.statet.rj.services.util.dataaccess.LazyRStore;
import org.eclipse.statet.rj.services.util.dataaccess.LazyRStore.Fragment;
import org.eclipse.statet.rj.ts.core.RToolService;
@NonNullByDefault
public class RPromiseValue extends RElementVariableValue<CombinedRElement> {
private static final RObjectAdapter<RPromiseImpl> ADAPTER= new RObjectAdapter<RPromiseImpl>(RObject.TYPE_PROMISE) {
@Override
public RPromiseImpl loadObject(final FQRObjectRef ref, final RObject referenceObject,
final LazyRStore.Fragment<RPromiseImpl> fragment,
final RService r, final ProgressMonitor m) throws StatusException, UnexpectedRDataException {
final RObject object;
{ final FQRObject fqrObject= r.findData(((RLanguage) ref.getName()).getSource(),
ref.getEnv(), false,
null, getLoadOptions(), RService.DEPTH_INFINITE,
m );
object= (fqrObject != null) ? fqrObject.getObject() : null;
}
return validateObject(object, referenceObject, fragment);
}
};
private @Nullable LazyRStore<RPromiseImpl> detailObjectStore;
private boolean validationFailed;
private final RElementVariableCompactStore detailVariables;
public RPromiseValue(final RElementVariable variable) {
super(variable);
this.detailVariables= new RElementVariableCompactStore(2);
}
public final RObject getRObject() {
return this.element;
}
public final @Nullable RPromiseValue getVariablePreviousValue() {
return (RPromiseValue) this.variable.getPreviousValue();
}
@Override
public String getValueString() throws DebugException {
final LazyRStore.Fragment<RPromiseImpl> fragment;
synchronized (this) {
fragment= getDetailObjectFragment();
if (fragment == null || fragment.getRObject() == null) {
return ""; //$NON-NLS-1$
}
}
final RPromiseImpl rObject= fragment.getRObject();
if (rObject.getExpression() instanceof RLanguage) {
final @NonNull RLanguage exprObject= (RLanguage) rObject.getExpression();
if (exprObject.getSource() != null) {
final RValueFormatter valueFormatter= getDebugTarget().getValueFormatter();
synchronized (valueFormatter) {
valueFormatter.clear();
valueFormatter.append("= "); //$NON-NLS-1$
RLanguageValue.appendValue(valueFormatter, exprObject);
return valueFormatter.getString();
}
}
}
return ""; //$NON-NLS-1$
}
@Override
public String getDetailString() {
return (!this.validationFailed) ? "<not yet evaluated>" : "";
}
@Override
public boolean hasVariables() throws DebugException {
return true;
}
@Override
public IVariable[] getVariables() throws DebugException {
final RPromiseValue previousValue;
synchronized (this.variable) {
if (this != this.variable.getCurrentValue()) {
return NO_VARIABLES;
}
previousValue= getVariablePreviousValue();
}
final @Nullable IRVariable[] variables= new @Nullable IRVariable[2];
synchronized (this.detailVariables) {
this.detailVariables.toArray(variables, 0);
if (!ObjectUtils.isAnyNull(variables)) {
return (IRVariable[]) variables;
}
}
final LazyRStore.Fragment<RPromiseImpl> fragment;
synchronized (this) {
fragment= getDetailObjectFragment();
if (fragment == null || fragment.getRObject() == null) {
if (this.validationFailed) {
return NO_VARIABLES;
}
throw newRequestLoadDataFailed();
}
}
synchronized (this.detailVariables) {
for (int idx= 0; idx < 2; idx++) {
RElementVariable childVariable= this.detailVariables.get(idx);
if (childVariable == null) {
final RObject dataObject;
final String label;
switch (idx) {
case 0:
dataObject= nonNullAssert(fragment.getRObject().getExpression());
label= "expression"; //$NON-NLS-1$
break;
case 1:
dataObject= nonNullAssert(fragment.getRObject().getEnvironment());
label= "environment"; //$NON-NLS-1$
break;
default:
throw new IllegalStateException();
}
final CombinedRElement childElement= ICombinedRDataAdapter.create(dataObject,
RElementName.create(RElementName.MAIN_OTHER, label) );
if (previousValue != null) {
childVariable= checkPreviousVariable(previousValue, idx, childElement);
}
if (childVariable == null) {
childVariable= new RElementVariable(childElement,
this.variable.getThread(), this.stamp, this.variable );
if (dataObject instanceof RLanguage) {
final RLanguageValue childValue= ((RLanguageValue) childVariable.getValue());
childValue.setDataObject((RLanguage) dataObject);
}
}
this.detailVariables.set(idx, childVariable);
}
variables[idx]= childVariable;
}
return (IRVariable[]) variables;
}
}
protected @Nullable RElementVariable checkPreviousVariable(final RPromiseValue previousValue,
final int idx, final CombinedRElement element) {
if (idx >= 0 && idx < previousValue.element.getLength()) {
final RElementVariable previousVariable;
synchronized (previousValue) {
previousVariable= previousValue.detailVariables.clear(idx);
}
if (previousVariable != null
&& previousVariable.update(element, this.stamp) ) {
return previousVariable;
}
}
return null;
}
private @Nullable Fragment<RPromiseImpl> getDetailObjectFragment() {
if (this.detailObjectStore == null) {
this.detailObjectStore= new LazyRStore<>(1, 1, 1,
new RDataLoader<RPromiseImpl>() {
@Override
protected RPromiseImpl doLoad(final FQRObjectRef ref,
final Fragment<RPromiseImpl> fragment,
final RToolService r, final ProgressMonitor m) throws StatusException, UnexpectedRDataException {
try {
return ADAPTER.loadObject(ref, getRObject(), fragment, r, m);
}
catch (final UnexpectedRDataException e) {
RPromiseValue.this.validationFailed= true;
throw e;
}
}
});
}
return this.detailObjectStore.getFragment(0, 0, 0, null);
}
}