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