001package jmri.jmrit.logixng.util.parser.functions;
002
003import java.util.HashSet;
004import java.util.List;
005import java.util.Set;
006
007import jmri.JmriException;
008import jmri.jmrit.logixng.SymbolTable;
009import jmri.jmrit.logixng.util.parser.*;
010import jmri.util.TypeConversionUtil;
011
012import org.openide.util.lookup.ServiceProvider;
013
014/**
015 * Implementation of conversion functions.
016 *
017 * @author Daniel Bergqvist 2020
018 */
019@ServiceProvider(service = FunctionFactory.class)
020public class ConvertFunctions implements FunctionFactory {
021
022    @Override
023    public String getModule() {
024        return "Convert";
025    }
026
027    @Override
028    public Set<Function> getFunctions() {
029        Set<Function> functionClasses = new HashSet<>();
030
031        addIsIntFunction(functionClasses);
032        addIsFloatFunction(functionClasses);
033        addBoolFunction(functionClasses);
034        addBoolJythonFunction(functionClasses);
035        addIntFunction(functionClasses);
036        addFloatFunction(functionClasses);
037        addStrFunction(functionClasses);
038        addHex2DecFunction(functionClasses);
039
040        return functionClasses;
041    }
042
043    @Override
044    public Set<Constant> getConstants() {
045        return new HashSet<>();
046    }
047
048    @Override
049    public String getConstantDescription() {
050        // This module doesn't define any constants
051        return null;
052    }
053
054    private void addIsIntFunction(Set<Function> functionClasses) {
055        functionClasses.add(new AbstractFunction(this, "isInt", Bundle.getMessage("Convert.isInt")) {
056            @Override
057            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
058                    throws JmriException {
059
060                if (parameterList.size() != 1) {
061                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
062                }
063                try {
064                    TypeConversionUtil.convertToLong(
065                            parameterList.get(0).calculate(symbolTable),
066                            true, true);
067                    return true;
068                } catch (NumberFormatException e) {
069                    return false;
070                }
071            }
072        });
073    }
074
075    private void addIsFloatFunction(Set<Function> functionClasses) {
076        functionClasses.add(new AbstractFunction(this, "isFloat", Bundle.getMessage("Convert.isFloat")) {
077            @Override
078            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
079                    throws JmriException {
080
081                try {
082                    switch (parameterList.size()) {
083                        case 1:
084                            TypeConversionUtil.convertToDouble(parameterList.get(0).calculate(symbolTable), false, true, true);
085                            break;
086                        case 2:
087                            boolean do_i18n = TypeConversionUtil.convertToBoolean(
088                                    parameterList.get(0).calculate(symbolTable), false);
089                            TypeConversionUtil.convertToDouble(
090                                    parameterList.get(0).calculate(symbolTable), do_i18n, true, true);
091                            break;
092                        default:
093                            throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
094                    }
095                    return true;
096                } catch (NumberFormatException e) {
097                    return false;
098                }
099            }
100        });
101    }
102
103    private void addBoolFunction(Set<Function> functionClasses) {
104        functionClasses.add(new AbstractFunction(this, "bool", Bundle.getMessage("Convert.bool")) {
105            @Override
106            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
107                    throws JmriException {
108
109                switch (parameterList.size()) {
110                    case 1:
111                        return TypeConversionUtil.convertToBoolean(parameterList.get(0).calculate(symbolTable), false);
112                    case 2:
113                        boolean do_i18n = TypeConversionUtil.convertToBoolean(
114                                parameterList.get(0).calculate(symbolTable), false);
115                        return TypeConversionUtil.convertToBoolean(
116                                parameterList.get(0).calculate(symbolTable), do_i18n);
117                    default:
118                        throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
119                }
120            }
121        });
122    }
123
124    private void addBoolJythonFunction(Set<Function> functionClasses) {
125        functionClasses.add(new AbstractFunction(this, "boolJython", Bundle.getMessage("Convert.boolJython")) {
126            @Override
127            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
128                    throws JmriException {
129
130                switch (parameterList.size()) {
131                    case 1:
132                        return TypeConversionUtil.convertToBoolean_JythonRules(parameterList.get(0).calculate(symbolTable), false);
133                    case 2:
134                        boolean do_i18n = TypeConversionUtil.convertToBoolean_JythonRules(
135                                parameterList.get(0).calculate(symbolTable), false);
136                        return TypeConversionUtil.convertToBoolean(
137                                parameterList.get(0).calculate(symbolTable), do_i18n);
138                    default:
139                        throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
140                }
141            }
142        });
143    }
144
145    private void addIntFunction(Set<Function> functionClasses) {
146        functionClasses.add(new AbstractFunction(this, "int", Bundle.getMessage("Convert.int")) {
147            @Override
148            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
149                    throws JmriException {
150
151                if (parameterList.size() != 1) {
152                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
153                }
154                return TypeConversionUtil.convertToLong(
155                        parameterList.get(0).calculate(symbolTable));
156            }
157        });
158    }
159
160    private void addFloatFunction(Set<Function> functionClasses) {
161        functionClasses.add(new AbstractFunction(this, "float", Bundle.getMessage("Convert.float")) {
162            @Override
163            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
164                    throws JmriException {
165
166                switch (parameterList.size()) {
167                    case 1:
168                        return TypeConversionUtil.convertToDouble(parameterList.get(0).calculate(symbolTable), false);
169                    case 2:
170                        boolean do_i18n = TypeConversionUtil.convertToBoolean(
171                                parameterList.get(0).calculate(symbolTable), false);
172                        return TypeConversionUtil.convertToDouble(
173                                parameterList.get(0).calculate(symbolTable), do_i18n);
174                    default:
175                        throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
176                }
177            }
178        });
179    }
180
181    private void addStrFunction(Set<Function> functionClasses) {
182        functionClasses.add(new AbstractFunction(this, "str", Bundle.getMessage("Convert.str_Descr")) {
183            @Override
184            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
185                    throws JmriException {
186
187                switch (parameterList.size()) {
188                    case 1:
189                        return TypeConversionUtil.convertToString(parameterList.get(0).calculate(symbolTable), false);
190                    case 2:
191                        boolean do_i18n = TypeConversionUtil.convertToBoolean(
192                                parameterList.get(0).calculate(symbolTable), false);
193                        return TypeConversionUtil.convertToString(
194                                parameterList.get(0).calculate(symbolTable), do_i18n);
195                    default:
196                        throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
197                }
198            }
199        });
200    }
201
202    private void addHex2DecFunction(Set<Function> functionClasses) {
203        functionClasses.add(new AbstractFunction(this, "hex2dec", Bundle.getMessage("Convert.hex2dec")) {
204            @Override
205            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
206                    throws JmriException {
207
208                if (parameterList.size() != 1) {
209                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
210                }
211                Object o = parameterList.get(0).calculate(symbolTable);
212                if (o != null) {
213                    return Long.parseLong(o.toString(), 16);
214                } else {
215                    throw new NullPointerException("value is null");
216                }
217            }
218        });
219    }
220
221}