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}