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 for (Symbol symbol : _symbols.values()) { 057 _stack.setValueAndTypeAtIndex(symbol.getIndex(), 058 prevSymbolTable.getValueAndType(symbol.getName())); 059 060 } 061 _firstSymbolIndex = _stack.getCount(); 062 } 063 064 /** 065 * Get the previous symbol table 066 * @return the symbol table 067 */ 068 public SymbolTable getPrevSymbolTable() { 069 return _prevSymbolTable; 070 } 071 072 /** {@inheritDoc} */ 073 @Override 074 public Map<String, Symbol> getSymbols() { 075 return Collections.unmodifiableMap(_symbols); 076 } 077 078 /** {@inheritDoc} */ 079 @Override 080 public Map<String, Object> getSymbolValues() { 081 Map<String, Object> symbolValues = new HashMap<>(); 082 for (Symbol symbol : _symbols.values()) { 083 Object value = _stack.getValueAtIndex(_firstSymbolIndex + symbol.getIndex()); 084 symbolValues.put(symbol.getName(), value); 085 } 086 return Collections.unmodifiableMap(symbolValues); 087 } 088 089 /** {@inheritDoc} */ 090 @Override 091 public Object getValue(String name) { 092 Symbol symbol = _symbols.get(name); 093 if (symbol != null) { 094 return _stack.getValueAtIndex(_firstSymbolIndex + symbol.getIndex()); 095 } 096 GlobalVariable globalVariable = InstanceManager.getDefault(GlobalVariableManager.class).getByUserName(name); 097 if (globalVariable != null) { 098 return globalVariable.getValue(); 099 } 100 throw new SymbolNotFound(String.format("Symbol '%s' does not exist in symbol table", name)); 101 } 102 103 /** {@inheritDoc} */ 104 @Override 105 public ValueAndType getValueAndType(String name) { 106 Symbol symbol = _symbols.get(name); 107 if (symbol != null) { 108 return _stack.getValueAndTypeAtIndex(_firstSymbolIndex + symbol.getIndex()); 109 } 110 throw new SymbolNotFound(String.format("Symbol '%s' does not exist in symbol table", name)); 111 } 112 113 /** {@inheritDoc} */ 114 @Override 115 public boolean hasValue(String name) { 116 if (_symbols.containsKey(name)) return true; 117 GlobalVariable globalVariable = InstanceManager.getDefault(GlobalVariableManager.class).getByUserName(name); 118 return globalVariable != null; 119 } 120 121 /** {@inheritDoc} */ 122 @Override 123 public void setValue(String name, Object value) { 124 if (_symbols.get(name) != null) { 125 _stack.setValueAtIndex(_firstSymbolIndex + _symbols.get(name).getIndex(), value); 126 } else { 127 GlobalVariable globalVariable = InstanceManager.getDefault(GlobalVariableManager.class).getByUserName(name); 128 if (globalVariable != null) { 129 globalVariable.setValue(value); 130 } else { 131 throw new IllegalArgumentException(Bundle.getMessage("ExceptionSymbolNotInSymbolTable", name)); 132 } 133 } 134 } 135 136 /** {@inheritDoc} */ 137 @Override 138 public void printSymbolTable(java.io.PrintWriter stream) { 139 stream.format("printSymbolTable:%n"); 140 for (Map.Entry<String, Symbol> entry : _symbols.entrySet()) { 141 stream.format("Key: %s, Name: %s, Index: %d, Value: %s%n", 142 entry.getKey(), 143 entry.getValue().getName(), 144 entry.getValue().getIndex(), 145 _stack.getValueAtIndex(_firstSymbolIndex + entry.getValue().getIndex())); 146 } 147 stream.format("printSymbolTable done%n"); 148 } 149 150 /** {@inheritDoc} */ 151 @Override 152 public void createSymbols(Collection<? extends SymbolTable.VariableData> symbolDefinitions) throws JmriException { 153 createSymbols(this, symbolDefinitions); 154 } 155 156 /** {@inheritDoc} */ 157 @Override 158 public void createSymbols(SymbolTable symbolTable, 159 Collection<? extends SymbolTable.VariableData> symbolDefinitions) 160 throws JmriException { 161 162 for (SymbolTable.VariableData variable : symbolDefinitions) { 163 Symbol symbol = new DefaultSymbol(variable.getName(), _stack.getCount() - _firstSymbolIndex); 164 165 if (_symbols.containsKey(symbol.getName())) { 166 throw new IllegalArgumentException("Symbol table already contains the variable " + symbol.getName()); 167 } 168 169 InitialValueType initialValueType = variable.getInitialValueType(); 170 Object initialValue = SymbolTable.getInitialValue( 171 SymbolTable.Type.Local, 172 symbol.getName(), 173 initialValueType, 174 variable.getInitialValueData(), 175 symbolTable, 176 _symbols); 177 178// System.out.format("Add symbol: %s = %s%n", symbol.getName(), initialValue); 179 180 _stack.push(new ValueAndType(initialValueType, initialValue)); 181 _symbols.put(symbol.getName(), symbol); 182 } 183 } 184 185 /** {@inheritDoc} */ 186 @Override 187 public void removeSymbols(Collection<? extends SymbolTable.VariableData> symbolDefinitions) throws JmriException { 188 symbolDefinitions.forEach((parameter) -> { 189 _symbols.remove(parameter.getName()); 190 }); 191 } 192 193 /** {@inheritDoc} */ 194 @Override 195 public Stack getStack() { 196 return _stack; 197 } 198 199 200 public static class DefaultSymbol implements Symbol { 201 202 private final String _name; 203 private final int _index; 204 205 public DefaultSymbol(String name, int index) { 206 _name = name; 207 _index = index; 208 } 209 210 /** {@inheritDoc} */ 211 @Override 212 public String getName() { 213 return _name; 214 } 215 216 /** {@inheritDoc} */ 217 @Override 218 public int getIndex() { 219 return _index; 220 } 221 222 } 223 224 225 public static class DefaultParameter implements Parameter { 226 227 private String _name; 228 private boolean _isInput; 229 private boolean _isOutput; 230 231 public DefaultParameter(String name, boolean isInput, boolean isOutput) { 232 _name = name; 233 _isInput = isInput; 234 _isOutput = isOutput; 235 } 236 237 public DefaultParameter(Parameter parameter) { 238 _name = parameter.getName(); 239 _isInput = parameter.isInput(); 240 _isOutput = parameter.isOutput(); 241 } 242 243 /** {@inheritDoc} */ 244 @Override 245 public String getName() { 246 return _name; 247 } 248 249 public void setName(String name) { 250 _name = name; 251 } 252 253 /** {@inheritDoc} */ 254 @Override 255 public boolean isInput() { 256 return _isInput; 257 } 258 259 public void setIsInput(boolean value) { 260 _isInput = value; 261 } 262 263 /** {@inheritDoc} */ 264 @Override 265 public boolean isOutput() { 266 return _isOutput; 267 } 268 269 public void setIsOutput(boolean value) { 270 _isOutput = value; 271 } 272 273 } 274 275 276// private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultSymbolTable.class); 277 278}