/**
* Copyright (C) 2009 STMicroelectronics
*
* This file is part of "Mind Compiler" is free software: you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact: mind@ow2.org
*
* Authors: Matthieu Leclercq
* Contributors:
*/
package org.ow2.mind.value;
import static java.lang.reflect.Array.newInstance;
import static java.lang.reflect.Array.set;
import java.util.Map;
import org.ow2.mind.value.ast.Array;
import org.ow2.mind.value.ast.BooleanLiteral;
import org.ow2.mind.value.ast.NullLiteral;
import org.ow2.mind.value.ast.NumberLiteral;
import org.ow2.mind.value.ast.StringLiteral;
import org.ow2.mind.value.ast.Value;
import org.ow2.mind.value.ast.ValueASTHelper;
import com.google.inject.Inject;
public class BasicValueEvaluator implements ValueEvaluator {
@Inject
public ValueEvaluator recursiveEvaluatorItf;
// ---------------------------------------------------------------------------
// Implementation of the ValueEvaluator interface
// ---------------------------------------------------------------------------
public <T> T evaluate(final Value value, final Class<T> expectedType,
final Map<Object, Object> context) throws ValueEvaluationException {
if (value instanceof NumberLiteral) {
if (expectedType.isPrimitive()) {
return evaluatePrimitiveType((NumberLiteral) value, expectedType);
}
Number n;
final String v = ((NumberLiteral) value).getValue();
try {
if (expectedType == Byte.class) {
n = Byte.valueOf(v);
} else if (expectedType == Short.class) {
n = Short.valueOf(v);
} else if (expectedType == Long.class) {
n = Long.valueOf(v);
} else if (expectedType == Float.class) {
n = Float.valueOf(v);
} else if (expectedType == Double.class) {
n = Double.valueOf(v);
} else {
// default case
n = Integer.valueOf(v);
}
} catch (final NumberFormatException e) {
throw new ValueEvaluationException(
"Value of NumberLiteral node is not a number", value, e);
}
try {
return expectedType.cast(n);
} catch (final ClassCastException e) {
throw new ValueEvaluationException(
"Incompatible value type, found number where "
+ expectedType.getName() + " was expected", value, e);
}
} else if (value instanceof StringLiteral) {
String s = ((StringLiteral) value).getValue();
s = s.substring(1, s.length() - 1);
if (s.contains("\\")) {
// un-escape characters
String unescaped = "";
for (int i = 0; i < s.length(); i++) {
final char c = s.charAt(i);
if (c == '\\') {
final char c1 = s.charAt(++i);
if (c1 == 'n')
unescaped += '\n';
else if (c1 == 't')
unescaped += '\t';
else if (c1 == 'b')
unescaped += '\b';
else if (c1 == 'r')
unescaped += '\r';
else if (c1 == 'f')
unescaped += '\f';
else if (c1 == '\\')
unescaped += '\\';
else if (c1 == '\'')
unescaped += '\'';
else if (c1 == '\"')
unescaped += '\"';
else if (c1 == '\n')
unescaped += '\n';
else if (c1 == '\r') {
unescaped += '\r';
if (i < s.length() - 1 && s.charAt(i + 1) == '\n') {
unescaped += '\n';
i++;
}
} else if (c1 >= '0' && c1 <= '7') {
int charCode = c1 - '0';
// read second octal (if any)
if (i < s.length() - 1 && s.charAt(i + 1) >= '0'
&& s.charAt(i + 1) <= '7') {
charCode = (charCode * 8) + (s.charAt(i + 1) - '0');
i++;
}
// read third octal (if any)
if (i < s.length() - 1 && s.charAt(i + 1) >= '0'
&& s.charAt(i + 1) <= '7') {
charCode = (charCode * 8) + (s.charAt(i + 1) - '0');
i++;
}
unescaped += Character.toString((char) charCode);
} else {
unescaped += c1;
}
} else {
unescaped += c;
}
}
s = unescaped;
}
try {
return expectedType.cast(s);
} catch (final ClassCastException e) {
throw new ValueEvaluationException(
"Incompatible value type, found string where "
+ expectedType.getName() + " was expected", value, e);
}
} else if (value instanceof BooleanLiteral) {
if (expectedType.isPrimitive()) {
return evaluatePrimitiveType((BooleanLiteral) value, expectedType);
}
try {
return expectedType.cast(Boolean.valueOf(ValueASTHelper
.getValue((BooleanLiteral) value)));
} catch (final ClassCastException e) {
throw new ValueEvaluationException(
"Incompatible value type, found boolean where "
+ expectedType.getName() + " was expected", value, e);
}
} else if (value instanceof Array) {
if (!expectedType.isArray()) {
throw new ValueEvaluationException(
"Incompatible value type, found array where "
+ expectedType.getName() + " was expected", value);
}
final Class<?> arrayComponentType = expectedType.getComponentType();
final Value[] arrayValues = ((Array) value).getValues();
final Object result = newInstance(arrayComponentType, arrayValues.length);
for (int i = 0; i < arrayValues.length; i++) {
set(result, i, recursiveEvaluatorItf.evaluate(arrayValues[i],
arrayComponentType, context));
}
return expectedType.cast(result);
} else if (value instanceof NullLiteral) {
try {
return expectedType.cast(null);
} catch (final ClassCastException e) {
throw new ValueEvaluationException(
"Incompatible value type, found NULL where "
+ expectedType.getName() + " was expected", value, e);
}
} else {
throw new ValueEvaluationException("Unknow value type", value);
}
}
@SuppressWarnings("unchecked")
protected <T> T evaluatePrimitiveType(final NumberLiteral value,
final Class<T> expectedType) throws ValueEvaluationException {
final String v = value.getValue();
try {
if (expectedType == Byte.TYPE) {
return (T) Byte.valueOf(v);
} else if (expectedType == Short.TYPE) {
return (T) Short.valueOf(v);
} else if (expectedType == Integer.TYPE) {
return (T) Integer.valueOf(v);
} else if (expectedType == Long.TYPE) {
return (T) Long.valueOf(v);
} else if (expectedType == Float.TYPE) {
return (T) Float.valueOf(v);
} else if (expectedType == Double.TYPE) {
return (T) Double.valueOf(v);
} else {
throw new ValueEvaluationException(
"Incompatible value type, found number where "
+ expectedType.getName() + " was expected", value);
}
} catch (final NumberFormatException e) {
throw new ValueEvaluationException(
"Value of NumberLiteral node is not a number", value, e);
}
}
@SuppressWarnings("unchecked")
protected <T> T evaluatePrimitiveType(final BooleanLiteral value,
final Class<T> expectedType) throws ValueEvaluationException {
final String v = value.getValue();
try {
if (expectedType == Boolean.TYPE) {
return (T) Boolean.valueOf(v);
} else {
throw new ValueEvaluationException(
"Incompatible value type, found boolean where "
+ expectedType.getName() + " was expected", value);
}
} catch (final NumberFormatException e) {
throw new ValueEvaluationException(
"Value of NumberLiteral node is not a number", value, e);
}
}
}