001package jmri.jmrit.logixng.util.parser.functions; 002 003import java.util.ArrayList; 004import java.util.HashSet; 005import java.util.List; 006import java.util.Set; 007import java.util.regex.Matcher; 008import java.util.regex.Pattern; 009 010import jmri.JmriException; 011import jmri.jmrit.logixng.SymbolTable; 012import jmri.jmrit.logixng.util.parser.*; 013import jmri.util.TypeConversionUtil; 014 015import org.openide.util.lookup.ServiceProvider; 016 017/** 018 * Implementation of string functions. 019 * 020 * @author Daniel Bergqvist 2020 021 */ 022@ServiceProvider(service = FunctionFactory.class) 023public class StringFunctions implements FunctionFactory { 024 025 @Override 026 public String getModule() { 027 return "String"; 028 } 029 030 @Override 031 public Set<Function> getFunctions() { 032 Set<Function> functionClasses = new HashSet<>(); 033 034 addFormatFunction(functionClasses); 035 addRegExFunction(functionClasses); 036 addStrlenFunction(functionClasses); 037 038 return functionClasses; 039 } 040 041 @Override 042 public Set<Constant> getConstants() { 043 return new HashSet<>(); 044 } 045 046 @Override 047 public String getConstantDescription() { 048 // This module doesn't define any constants 049 return null; 050 } 051 052 private void addFormatFunction(Set<Function> functionClasses) { 053 functionClasses.add(new AbstractFunction(this, "format", Bundle.getMessage("String.format_Descr")) { 054 @Override 055 public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList) 056 throws CalculateException, JmriException { 057 if (parameterList.isEmpty()) { 058 throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters1", getName(), 1)); 059 } 060 061 String formatStr = TypeConversionUtil.convertToString( 062 parameterList.get(0).calculate(symbolTable), false); 063 064 List<Object> list = new ArrayList<>(); 065 for (int i=1; i < parameterList.size(); i++) { 066 list.add(parameterList.get(i).calculate(symbolTable)); 067 } 068 069 return String.format(formatStr, list.toArray()); 070 } 071 }); 072 } 073 074 private void addRegExFunction(Set<Function> functionClasses) { 075 functionClasses.add(new AbstractFunction(this, "regex", Bundle.getMessage("String.regex_Descr")) { 076 @Override 077 public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList) 078 throws CalculateException, JmriException { 079 if (parameterList.size() != 2) { 080 throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters1", getName(), 1)); 081 } 082 083 Object regex = parameterList.get(0).calculate(symbolTable); 084 Object value = parameterList.get(1).calculate(symbolTable); 085 086 if (regex == null) { 087 throw new NullPointerException("Regular expression is null"); 088 } else if (value == null) { 089 throw new NullPointerException("Value is null"); 090 } else if (! (regex instanceof String)) { 091 throw new IllegalArgumentException("Parameter is not a String: "+regex.getClass().getName()); 092 } else if (! (value instanceof String)) { 093 throw new IllegalArgumentException("Value is not a String: "+value.getClass().getName()); 094 } 095 096 Pattern p = Pattern.compile((String) regex); 097 Matcher m = p.matcher((String) value); 098 099 if (!m.matches()) { 100 return null; 101 } 102 103 List<String> list = new ArrayList<>(); 104 for (int i=1; i <= m.groupCount(); i++) { 105 list.add(m.group(i)); 106 } 107 return list; 108 } 109 }); 110 } 111 112 private void addStrlenFunction(Set<Function> functionClasses) { 113 functionClasses.add(new AbstractFunction(this, "strlen", Bundle.getMessage("String.strlen_Descr")) { 114 @Override 115 public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList) 116 throws CalculateException, JmriException { 117 if (parameterList.size() != 1) { 118 throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters1", getName(), 1)); 119 } 120 121 Object parameter = parameterList.get(0).calculate(symbolTable); 122 123 if (parameter == null) { 124 throw new NullPointerException("Parameter is null"); 125 } else if (parameter instanceof String) { 126 return ((String)parameter).length(); 127 } 128 129 throw new IllegalArgumentException("Parameter is not a String: "+parameter.getClass().getName()); 130 } 131 }); 132 } 133 134}