Skip to content

Commit

Permalink
Added support for null value resolution at runtime.
Browse files Browse the repository at this point in the history
  • Loading branch information
ylussaud committed Feb 2, 2024
1 parent afea280 commit 1a9c46c
Show file tree
Hide file tree
Showing 27 changed files with 699 additions and 240 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016, 2021 Obeo.
* Copyright (c) 2016, 2024 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand All @@ -11,11 +11,15 @@
package org.eclipse.acceleo.aql.evaluation;

import java.util.List;
import java.util.Set;

import org.eclipse.acceleo.ModuleElement;
import org.eclipse.acceleo.Variable;
import org.eclipse.acceleo.VisibilityKind;
import org.eclipse.acceleo.query.runtime.impl.NullValue;
import org.eclipse.acceleo.query.runtime.impl.namespace.AbstractQualifiedNameService;
import org.eclipse.acceleo.query.runtime.namespace.IQualifiedNameLookupEngine;
import org.eclipse.acceleo.query.services.EObjectServices;
import org.eclipse.acceleo.query.validation.type.IType;

/**
Expand Down Expand Up @@ -166,4 +170,27 @@ public int hashCode() {
return getOrigin().hashCode();
}

/**
* Gets the variable value for the given {@link Variable} and value.
*
* @param variable
* the {@link Variable}
* @param value
* the value
* @return the variable value for the given {@link Variable} and value
*/
protected Object getArgumentValue(Variable variable, Object value) {
final Object res;

if (value == null) {
final Set<IType> types = EObjectServices.getTypes(getLookupEngine().getQueryEnvironment(),
variable.getTypeAql());
res = new NullValue(types);
} else {
res = value;
}

return res;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
Expand Down Expand Up @@ -60,7 +61,9 @@
import org.eclipse.acceleo.query.runtime.IQueryEnvironment;
import org.eclipse.acceleo.query.runtime.IQueryEvaluationEngine;
import org.eclipse.acceleo.query.runtime.QueryEvaluation;
import org.eclipse.acceleo.query.runtime.impl.NullValue;
import org.eclipse.acceleo.query.runtime.namespace.IQualifiedNameLookupEngine;
import org.eclipse.acceleo.query.validation.type.IType;
import org.eclipse.acceleo.util.AcceleoSwitch;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
Expand Down Expand Up @@ -373,7 +376,16 @@ public Object caseExpression(Expression expression) {
generationResult.addDiagnostic(diagnostic);
}

return evalResult.getResult();
final Object res;
if (evalResult.getResult() == null) {
Set<IType> types = new LinkedHashSet<>();
types.add(evalResult.getNullType());
res = new NullValue(types);
} else {
res = evalResult.getResult();
}

return res;
}

/**
Expand Down Expand Up @@ -803,7 +815,7 @@ private Charset getCharset(FileStatement fileStatement) {
final Charset charset;
if (fileStatement.getCharset() != null) {
final Object charsetValue = doSwitch(fileStatement.getCharset());
if (charsetValue != null) {
if (charsetValue != null && charsetValue.getClass() != NullValue.class) {
final String charsetString = toString(charsetValue);
Charset defaultCharset = StandardCharsets.UTF_8;
try {
Expand Down Expand Up @@ -870,7 +882,7 @@ public String caseForStatement(ForStatement forStatement) {
final Object value = doSwitch(forStatement.getBinding().getInitExpression());
if (value instanceof Collection) {
iteration.addAll((Collection<?>)value);
} else if (value != null) {
} else if (value != null && value.getClass() != NullValue.class) {
iteration.add(value);
} else {
final BasicDiagnostic diagnostic = new BasicDiagnostic(Diagnostic.WARNING, ID, 0,
Expand Down Expand Up @@ -1045,7 +1057,7 @@ private String toString(Object object) {
while (childrenIterator.hasNext()) {
buffer.append(toString(childrenIterator.next()));
}
} else if (object != null) {
} else if (object != null && object.getClass() != NullValue.class) {
buffer.append(object.toString());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016, 2023 Obeo.
* Copyright (c) 2016, 2024 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -95,7 +95,7 @@ protected Object internalInvoke(Object[] arguments) throws Exception {
final Map<String, Object> variables = new HashMap<String, Object>();
for (int i = 0; i < arguments.length; i++) {
Variable var = getOrigin().getParameters().get(i);
variables.put(var.getName(), arguments[i]);
variables.put(var.getName(), getArgumentValue(var, arguments[i]));
}

final AcceleoEvaluator evaluator = getEvaluator();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016, 2023 Obeo.
* Copyright (c) 2016, 2024 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -94,7 +94,7 @@ protected Object internalInvoke(Object[] arguments) throws Exception {
final Map<String, Object> variables = new HashMap<String, Object>();
for (int i = 0; i < arguments.length; i++) {
Variable var = getOrigin().getParameters().get(i);
variables.put(var.getName(), arguments[i]);
variables.put(var.getName(), getArgumentValue(var, arguments[i]));
}

final AcceleoEvaluator evaluator = getEvaluator();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2015, 2023 Obeo.
* Copyright (c) 2015, 2024 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -47,6 +47,9 @@
import org.eclipse.acceleo.query.runtime.impl.EvaluationServices;
import org.eclipse.acceleo.query.runtime.impl.LambdaValue;
import org.eclipse.acceleo.query.runtime.impl.Nothing;
import org.eclipse.acceleo.query.runtime.impl.NullValue;
import org.eclipse.acceleo.query.validation.type.ClassType;
import org.eclipse.acceleo.query.validation.type.IType;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EClassifier;
Expand Down Expand Up @@ -136,12 +139,25 @@ protected Map<String, Object> popVariables() {
* @return the evaluation of the specified ast.
*/
public EvaluationResult eval(Map<String, Object> varDefinitions, Expression ast) {
final Object result;

pushVariables(varDefinitions);
diagnostic = new BasicDiagnostic();
final Object result = doSwitch(ast);
final Object value = doSwitch(ast);
final IType nullType;
if (value != null && value.getClass() == NullValue.class) {
result = null;
nullType = ((NullValue)value).getType();
} else if (value == null) {
result = value;
nullType = new ClassType(services.getQueryEnvironment(), null);
} else {
result = value;
nullType = null;
}
popVariables();

return new EvaluationResult(result, diagnostic);
return new EvaluationResult(result, nullType, diagnostic);
}

/**
Expand Down Expand Up @@ -225,22 +241,7 @@ public Object caseCall(Call object) {
args[i++] = doSwitch(arg);
}

// call the service.
switch (object.getType()) {
case CALLSERVICE:
result = services.call(object.getServiceName(), object.isSuperCall(), args, diagnostic);
break;
case CALLORAPPLY:
result = services.callOrApply(object.getServiceName(), object.isSuperCall(), args,
diagnostic);
break;
case COLLECTIONCALL:
result = services.collectionServiceCall(object.getServiceName(), object.isSuperCall(), args,
diagnostic);
break;
default:
throw new UnsupportedOperationException("should never happen");
}
result = services.call(object, args, diagnostic);

return result;
}
Expand All @@ -260,7 +261,7 @@ public Object caseAnd(And object) {
result = Boolean.FALSE;
} else {
args[1] = doSwitch(object.getArguments().get(1));
result = services.call(object.getServiceName(), object.isSuperCall(), args, diagnostic);
result = services.call(object, args, diagnostic);
}

return result;
Expand All @@ -281,7 +282,7 @@ public Object caseOr(Or object) {
result = Boolean.TRUE;
} else {
args[1] = doSwitch(object.getArguments().get(1));
result = services.call(object.getServiceName(), object.isSuperCall(), args, diagnostic);
result = services.call(object, args, diagnostic);
}

return result;
Expand All @@ -302,7 +303,7 @@ public Object caseImplies(Implies object) {
result = Boolean.TRUE;
} else {
args[1] = doSwitch(object.getArguments().get(1));
result = services.call(object.getServiceName(), object.isSuperCall(), args, diagnostic);
result = services.call(object, args, diagnostic);
}

return result;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2015 Obeo.
* Copyright (c) 2015, 2023 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand All @@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.acceleo.query.runtime;

import org.eclipse.acceleo.query.validation.type.IType;
import org.eclipse.emf.common.util.Diagnostic;

/**
Expand All @@ -24,17 +25,25 @@ public class EvaluationResult {
/** Diagnostic of the evaluation. */
private final Diagnostic diagnostic;

/**
* The <code>null</code> {@link IType} if any.
*/
private final IType nullType;

/**
* Creates an evaluation result given the actual Object result of said evaluation, and the diagnostic to
* associate to it.
*
* @param result
* The actual result of this evaluation.
* @param nullType
* the <code>null</code> {@link IType}
* @param diagnostic
* Diagnostic of the evaluation.
*/
public EvaluationResult(Object result, Diagnostic diagnostic) {
public EvaluationResult(Object result, IType nullType, Diagnostic diagnostic) {
this.result = result;
this.nullType = nullType;
this.diagnostic = diagnostic;
}

Expand All @@ -47,6 +56,15 @@ public Object getResult() {
return result;
}

/**
* Gets the <code>null</code> {@link IType}.
*
* @return the <code>null</code> {@link IType} if any, <code>null</code> otherwise
*/
public IType getNullType() {
return nullType;
}

/**
* Returns the status of this evaluation.
*
Expand Down
Loading

0 comments on commit 1a9c46c

Please sign in to comment.