001package jmri.jmrit.logixng.implementation; 002 003import java.util.*; 004 005import jmri.*; 006import jmri.jmrit.logixng.ConditionalNG; 007import jmri.jmrit.logixng.GlobalVariable; 008import jmri.jmrit.logixng.GlobalVariableManager; 009import jmri.jmrit.logixng.Module.Parameter; 010import jmri.jmrit.logixng.Stack; 011import jmri.jmrit.logixng.SymbolTable; 012 013/** 014 * The default implementation of a NamedTable 015 * 016 * @author Daniel Bergqvist 2020 017 */ 018public class DefaultSymbolTable implements SymbolTable { 019 020 private final SymbolTable _prevSymbolTable; 021 private final Stack _stack; 022 private final int _firstSymbolIndex; 023 private final Map<String, Symbol> _symbols = new HashMap<>(); 024 025 026 /** 027 * Create a new instance of DefaultSymbolTable with no previous symbol table. 028 */ 029 public DefaultSymbolTable() { 030 _prevSymbolTable = null; 031 _stack = new DefaultStack(); 032 _firstSymbolIndex = _stack.getCount(); 033 } 034 035 /** 036 * Create a new instance of DefaultSymbolTable with previous symbol table 037 * and the stack from a ConditionalNG. 038 * @param currentConditionalNG the ConditionalNG 039 */ 040 public DefaultSymbolTable(ConditionalNG currentConditionalNG) { 041 _prevSymbolTable = currentConditionalNG.getSymbolTable(); 042 _stack = currentConditionalNG.getStack(); 043 _firstSymbolIndex = _stack.getCount(); 044 } 045 046 /** 047 * Create a new instance of DefaultSymbolTable from a previous symbol table 048 * and a stack. 049 * @param prevSymbolTable the previous symbol table 050 */ 051 public DefaultSymbolTable(SymbolTable prevSymbolTable) { 052 _prevSymbolTable = null; 053 _symbols.putAll(prevSymbolTable.getSymbols()); 054 _stack = new DefaultStack(); 055 for (Symbol symbol : _symbols.values()) { 056 _stack.setValueAtIndex(symbol.getIndex(), 057 prevSymbolTable.getValue(symbol.getName())); 058 059 } 060 _firstSymbolIndex = _stack.getCount(); 061 } 062 063 /** 064 * Get the previous symbol table 065 * @return the symbol table 066 */ 067 public SymbolTable getPrevSymbolTable() { 068 return _prevSymbolTable; 069 } 070 071 /** {@inheritDoc} */ 072 @Override 073 public Map<String, Symbol> getSymbols() { 074 return Collections.unmodifiableMap(_symbols); 075 } 076 077 /** {@inheritDoc} */ 078 @Override 079 public Map<String, Object> getSymbolValues() { 080 Map<String, Object> symbolValues = new HashMap<>(); 081 for (Symbol symbol : _symbols.values()) { 082 Object value = _stack.getValueAtIndex(_firstSymbolIndex + symbol.getIndex()); 083 symbolValues.put(symbol.getName(), value); 084 } 085 return Collections.unmodifiableMap(symbolValues); 086 } 087 088 /** {@inheritDoc} */ 089 @Override 090 public Object getValue(String name) { 091 Symbol symbol = _symbols.get(name); 092 if (symbol != null) { 093 return _stack.getValueAtIndex(_firstSymbolIndex + symbol.getIndex()); 094 } 095 GlobalVariable globalVariable = InstanceManager.getDefault(GlobalVariableManager.class).getByUserName(name); 096 if (globalVariable != null) { 097 return globalVariable.getValue(); 098 } 099 throw new SymbolNotFound(String.format("Symbol '%s' does not exist in symbol table", name)); 100 } 101 102 /** {@inheritDoc} */ 103 @Override 104 public boolean hasValue(String name) { 105 if (_symbols.containsKey(name)) return true; 106 GlobalVariable globalVariable = InstanceManager.getDefault(GlobalVariableManager.class).getByUserName(name); 107 return globalVariable != null; 108 } 109 110 /** {@inheritDoc} */ 111 @Override 112 public void setValue(String name, Object value) { 113 if (_symbols.get(name) != null) { 114 _stack.setValueAtIndex(_firstSymbolIndex + _symbols.get(name).getIndex(), value); 115 } else { 116 GlobalVariable globalVariable = InstanceManager.getDefault(GlobalVariableManager.class).getByUserName(name); 117 if (globalVariable != null) { 118 globalVariable.setValue(value); 119 } else { 120 throw new IllegalArgumentException(Bundle.getMessage("ExceptionSymbolNotInSymbolTable", name)); 121 } 122 } 123 } 124 125 /** {@inheritDoc} */ 126 @Override 127 public void printSymbolTable(java.io.PrintWriter stream) { 128 stream.format("printSymbolTable:%n"); 129 for (Map.Entry<String, Symbol> entry : _symbols.entrySet()) { 130 stream.format("Key: %s, Name: %s, Index: %d, Value: %s%n", 131 entry.getKey(), 132 entry.getValue().getName(), 133 entry.getValue().getIndex(), 134 _stack.getValueAtIndex(_firstSymbolIndex + entry.getValue().getIndex())); 135 } 136 stream.format("printSymbolTable done%n"); 137 } 138 139 /** {@inheritDoc} */ 140 @Override 141 public void createSymbols(Collection<? extends SymbolTable.VariableData> symbolDefinitions) throws JmriException { 142 createSymbols(this, symbolDefinitions); 143 } 144 145 /** {@inheritDoc} */ 146 @Override 147 public void createSymbols(SymbolTable symbolTable, 148 Collection<? extends SymbolTable.VariableData> symbolDefinitions) 149 throws JmriException { 150 151 for (SymbolTable.VariableData variable : symbolDefinitions) { 152 Symbol symbol = new DefaultSymbol(variable.getName(), _stack.getCount() - _firstSymbolIndex); 153 154 if (_symbols.containsKey(symbol.getName())) { 155 throw new IllegalArgumentException("Symbol table already contains the variable " + symbol.getName()); 156 } 157 158 Object initialValue = SymbolTable.getInitialValue( 159 variable.getInitialValueType(), 160 variable.getInitialValueData(), 161 symbolTable, 162 _symbols); 163 164// System.out.format("Add symbol: %s = %s%n", symbol.getName(), initialValue); 165 166 _stack.push(initialValue); 167 _symbols.put(symbol.getName(), symbol); 168 } 169 } 170 171 /** {@inheritDoc} */ 172 @Override 173 public void removeSymbols(Collection<? extends SymbolTable.VariableData> symbolDefinitions) throws JmriException { 174 symbolDefinitions.forEach((parameter) -> { 175 _symbols.remove(parameter.getName()); 176 }); 177 } 178 179 /** {@inheritDoc} */ 180 @Override 181 public Stack getStack() { 182 return _stack; 183 } 184 185 186 public static class DefaultSymbol implements Symbol { 187 188 private final String _name; 189 private final int _index; 190 191 public DefaultSymbol(String name, int index) { 192 _name = name; 193 _index = index; 194 } 195 196 /** {@inheritDoc} */ 197 @Override 198 public String getName() { 199 return _name; 200 } 201 202 /** {@inheritDoc} */ 203 @Override 204 public int getIndex() { 205 return _index; 206 } 207 208 } 209 210 211 public static class DefaultParameter implements Parameter { 212 213 private String _name; 214 private boolean _isInput; 215 private boolean _isOutput; 216 217 public DefaultParameter(String name, boolean isInput, boolean isOutput) { 218 _name = name; 219 _isInput = isInput; 220 _isOutput = isOutput; 221 } 222 223 public DefaultParameter(Parameter parameter) { 224 _name = parameter.getName(); 225 _isInput = parameter.isInput(); 226 _isOutput = parameter.isOutput(); 227 } 228 229 /** {@inheritDoc} */ 230 @Override 231 public String getName() { 232 return _name; 233 } 234 235 public void setName(String name) { 236 _name = name; 237 } 238 239 /** {@inheritDoc} */ 240 @Override 241 public boolean isInput() { 242 return _isInput; 243 } 244 245 public void setIsInput(boolean value) { 246 _isInput = value; 247 } 248 249 /** {@inheritDoc} */ 250 @Override 251 public boolean isOutput() { 252 return _isOutput; 253 } 254 255 public void setIsOutput(boolean value) { 256 _isOutput = value; 257 } 258 259 } 260 261 262// private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultSymbolTable.class); 263 264}