// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.plugins.roadsigns; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.openstreetmap.josm.plugins.roadsigns.javacc.ParamStringScanner; import org.openstreetmap.josm.plugins.roadsigns.javacc.ParseException; import org.openstreetmap.josm.plugins.roadsigns.javacc.TokenMgrError; /** * A parametrized string is a string that contains identifiers that can * be substituted when the values of the parameters are known. * The syntax is in perl style, e.g. * "Up to $val% in ${num}th row costs 12 \$.". * * This class represent a parsed string (parameters are identified). * It can be constructed from a String. Given a parameter environment, * the String value can be determined. * */ public class ParametrizedString { final List<StringOrParameter> token = new ArrayList<>(); /** * Describes the union of String and Parameter type. Both * types have a single String object as their backing data. */ public interface StringOrParameter { } public static class Prm implements StringOrParameter { public final String ident; public Prm(String ident) { this.ident = ident; } @Override public String toString() { return "<Prm="+ident+">"; } } public static class Str implements StringOrParameter { String value; public Str(String stringValue) { this.value = stringValue; } @Override public String toString() { return "<Str="+value+">"; } } protected ParametrizedString(String input) throws ParseException, TokenMgrError { scan(input); } /** * Constructor that returns a null value for null value input. * Once it is created, the list of token is immutable. */ public static ParametrizedString create(String input) throws ParseException, TokenMgrError { if (input == null) return null; return new ParametrizedString(input); } /** * The tokenizer. Creates the list of tokens * from the input string. */ protected void scan(String input) throws ParseException, TokenMgrError { List<StringOrParameter> tmp = null; tmp = ParamStringScanner.parseIt(input); StringBuffer curString = new StringBuffer(); for (StringOrParameter sp : tmp) { if (sp instanceof Prm) { if (curString.length() > 0) { token.add(new Str(curString.toString())); curString = new StringBuffer(); } token.add(sp); } else if (sp instanceof Str) { curString.append(((Str) sp).value); } } if (curString.length() > 0) { token.add(new Str(curString.toString())); } } /** * Evaluates the string value, given an environment of * parameter mappings. */ public String evaluate(Map<String, String> env) { StringBuilder sb = new StringBuilder(); for (StringOrParameter t : token) { if (t instanceof Str) { sb.append(((Str) t).value); } else if (t instanceof Prm) { String val = env.get(((Prm) t).ident); if (val == null) { System.err.println("Warning: Parameter not in environment: "+((Prm) t).ident+" ("+this.toString()+")"); Thread.dumpStack(); val = "<?>"; } sb.append(val); } else throw new AssertionError(); } return sb.toString(); } /** * Converts to a string that could be parsed again to an equal object. */ @Override public String toString() { StringBuilder sb = new StringBuilder(); for (StringOrParameter t : token) { if (t instanceof Str) { sb.append(((Str) t).value); } else if (t instanceof Prm) { sb.append("${"+((Prm) t).ident+"}"); } else throw new AssertionError(); } return sb.toString(); } /** * Creates a debug string for this object */ public String toDebugString() { StringBuilder res = new StringBuilder(); for (StringOrParameter sop : token) { res.append(sop); } return res.toString(); } }