001package jmri.jmrit.logixng.util.parser;
002
003import java.lang.reflect.*;
004import java.util.*;
005
006import jmri.JmriException;
007import jmri.jmrit.logixng.SymbolTable;
008
009/**
010 * A parsed expression
011 * 
012 * @author Daniel Bergqvist 2021
013 */
014public class ExpressionNodeInstanceVariable implements ExpressionNodeWithParameter {
015
016    private final String _fieldName;
017    
018    public ExpressionNodeInstanceVariable(String fieldName, Map<String, Variable> variables) throws IdentifierNotExistsException {
019        _fieldName = fieldName;
020    }
021    
022    @Override
023    public Object calculate(Object parameter, SymbolTable symbolTable) throws JmriException {
024        if (parameter == null) throw new NullPointerException("Parameter is null");
025        
026        try {
027            Field field = parameter.getClass().getField(_fieldName);
028            return field.get(parameter);
029        } catch (NoSuchFieldException | IllegalAccessException ex) {
030            throw new ReflectionException("Reflection exception", ex);
031        }
032    }
033    
034    /** {@inheritDoc} */
035    @Override
036    public boolean canBeAssigned() {
037        // If the identifier is a local variable, assignment is possible. And
038        // we don't know if the identifier is a valid local variable until the
039        // expression is calculated. So we assume that it is.
040        return true;
041    }
042    
043    /** {@inheritDoc} */
044    @Override
045    public void assignValue(Object parameter, SymbolTable symbolTable, Object value) throws JmriException {
046        if (parameter == null) throw new NullPointerException("Parameter is null");
047        
048        try {
049            Field field = parameter.getClass().getField(_fieldName);
050            Class<?> type = field.getType();
051            Object newValue;
052            if (type.isAssignableFrom(value.getClass())) newValue = value;
053            else if ((type == Byte.TYPE) && (value instanceof Long)) newValue = (byte)(long)value;
054            else if ((type == Short.TYPE) && (value instanceof Long)) newValue = (short)(long)value;
055            else if ((type == Integer.TYPE) && (value instanceof Long)) newValue = (int)(long)value;
056            else if ((type == Float.TYPE) && (value instanceof Double)) newValue = (float)(double)value;
057            else throw new RuntimeException(String.format("%s cannot be assigned to %s", value.getClass().getName(), type.getName()));
058            field.set(parameter, newValue);
059        } catch (NoSuchFieldException | IllegalAccessException ex) {
060            throw new ReflectionException("Reflection exception", ex);
061        }
062    }
063    
064    /** {@inheritDoc} */
065    @Override
066    public String getDefinitionString() {
067        return "InstanceVariable:"+_fieldName;
068    }
069    
070}