/** * Copyright (C) 2001-2017 by RapidMiner and the contributors * * Complete list of developers available at our web site: * * http://rapidminer.com * * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU Affero 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 * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with this program. * If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.tools.expression; import java.util.LinkedList; import java.util.List; import com.rapidminer.Process; import com.rapidminer.operator.OperatorVersion; import com.rapidminer.tools.expression.internal.ConstantResolver; import com.rapidminer.tools.expression.internal.SimpleExpressionContext; import com.rapidminer.tools.expression.internal.antlr.AntlrParser; import com.rapidminer.tools.expression.internal.function.eval.Evaluation; import com.rapidminer.tools.expression.internal.function.eval.TypeConstants; import com.rapidminer.tools.expression.internal.function.process.MacroValue; import com.rapidminer.tools.expression.internal.function.process.ParameterValue; import com.rapidminer.tools.expression.internal.function.statistical.Random; /** * Builder for an {@link ExpressionParser}. * * @author Gisa Schaefer * @since 6.5.0 */ public class ExpressionParserBuilder { /** * The last version which contained the old expression parser with different functions and * different Macro handling. */ public static final OperatorVersion OLD_EXPRESSION_PARSER_FUNCTIONS = new OperatorVersion(6, 4, 0); private Process process; private boolean compatibleWithOldParser; private List<Function> functions = new LinkedList<>(); private List<Resolver> scopeResolvers = new LinkedList<>(); private List<Resolver> dynamicsResolvers = new LinkedList<>(); private List<Resolver> constantResolvers = new LinkedList<>(); /** * Builds an {@link ExpressionParser} with the given data. * * @return an expression parser */ public ExpressionParser build() { // add functions with process information if (process != null) { functions.add(new Random(process)); functions.add(new ParameterValue(process)); if (compatibleWithOldParser) { functions.add(new MacroValue(process)); } } Evaluation evalFunction = null; if (!compatibleWithOldParser) { // add the eval function, always present except when in compatibility mode with old // parser evalFunction = new Evaluation(); functions.add(evalFunction); } // add eval constants constantResolvers.add(new ConstantResolver(TypeConstants.INSTANCE.getKey(), TypeConstants.INSTANCE.getConstants())); ExpressionContext context = new SimpleExpressionContext(functions, scopeResolvers, dynamicsResolvers, constantResolvers); AntlrParser parser = new AntlrParser(context); if (!compatibleWithOldParser) { // set parser for eval function evalFunction.setParser(parser); } return parser; } /** * Adds the process which enables process dependent functions. * * @param process * the process to add * @return the builder */ public ExpressionParserBuilder withProcess(Process process) { this.process = process; return this; } /** * Adds the resolver as a resolver for scope constants (%{scope_constant} in the expression). * * @param resolver * the resolver to add * @return the builder */ public ExpressionParserBuilder withScope(Resolver resolver) { scopeResolvers.add(resolver); return this; } /** * Adds the resolver as a resolver for dynamic variables ([variable_name] or variable_name in * the expression). * * @param resolver * the resolver to add * @return the builder */ public ExpressionParserBuilder withDynamics(Resolver resolver) { dynamicsResolvers.add(resolver); return this; } /** * Adds the given module that supplies functions and constant values. * * @param module * the module to add * @return the builder */ public ExpressionParserBuilder withModule(ExpressionParserModule module) { addModule(module); return this; } /** * Adds all functions of the module to the list of functions and adds a {@link ConstantResolver} * knowing all constants of the module to the list of constant resolver. * * @param module */ private void addModule(ExpressionParserModule module) { List<Constant> moduleConstants = module.getConstants(); if (moduleConstants != null && !moduleConstants.isEmpty()) { constantResolvers.add(new ConstantResolver(module.getKey(), moduleConstants)); } List<Function> moduleFunctions = module.getFunctions(); if (moduleFunctions != null) { functions.addAll(moduleFunctions); } } /** * Adds the given modules that supplies functions and constant values. * * @param modules * the modules to add * @return the builder */ public ExpressionParserBuilder withModules(List<ExpressionParserModule> modules) { for (ExpressionParserModule module : modules) { addModule(module); } return this; } /** * Adds the functions that are no longer used after version 6.4 if version is at most 6.4. * * @param version * the version of the associated operator * @return the builder */ public ExpressionParserBuilder withCompatibility(OperatorVersion version) { if (version.isAtMost(OLD_EXPRESSION_PARSER_FUNCTIONS)) { compatibleWithOldParser = true; } return this; } }