DictionaryWorker.java
/*
** Module : DictionaryWorker.java
** Abstract : exports named and scoped dictionaries to pattern engine rules
**
** Copyright (c) 2005-2021, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- ----------------------------Description-----------------------------
** 001 GES 20050310 @20258 Created initial version supporting any
** number of user controlled scoped dictionaries
** that map names to any of the 4 supported
** pattern engine types (string, long, double
** and boolean).
** 002 GES 20050406 @20645 JavaDoc and coding standards improvements.
** 003 ECF 20050415 @20813 Changed addGeneric method's return value.
** Previously this method always returned true.
** It now returns the result of its internal
** call to ScopedSymbolDictionary's addSymbol
** method. This lets the caller know whether the
** entry was new or a replacement of an existing
** entry.
** 004 GES 20050428 @20923 Modified addScope() to create the dictionary
** if it doesn't already exist.
** 005 ECF 20050526 @21290 Changes to support new expression engine
** implementation. Changed library registration
** mechanism based on superclass' modifications
** to support single library per pattern worker
** limit.
** 006 GES 20050614 @21492 Added Object versions of add/lookup methods
** and added a dictionaryKeyDepth() method to
** report on the depth at which a key exists.
** 007 SIY 20050607 @21710 Added scope-based setting of the values.
** 008 SIY 20050919 @23091 Added scope-based lookup of the values.
** 009 GES 20051115 @23363 Added simple level oriented helpers and a
** new List helper.
** 010 GES 20061023 @30617 Made dictionaryValueDepth() more generic.
** 011 ECF 20070816 @34870 Added dumpDictionary() debug user function.
** 012 GES 20080621 @38911 Added integer variants of get/set methods.
** 013 ECF 20140830 Added methods to retrieve symbol sets for the entire dictionary, or
** for a single scope.
** 014 EVL 20160223 Javadoc fixes to make compatible with Oracle Java 8 for Solaris 10.
** 015 CA 20211214 The AST manager plugin must be context-local, for runtime conversion, as the
** InMemoryRegistryPlugin is not thread-safe.
** All worker's state must be context-local, for runtime conversion to work in
** multi-context mode, as the pattern workers are singletons.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.pattern;
import java.util.*;
import com.goldencode.p2j.security.*;
import com.goldencode.p2j.util.*;
/**
* Exports named and scoped dictionaries to pattern engine rules supporting
* any number of user controlled scoped dictionaries that map names to any of
* the 4 supported pattern engine types (string, long, double and boolean).
*/
public class DictionaryWorker
extends AbstractPatternWorker
{
/** Context local work area. */
private static final ContextLocal<WorkArea> context = new ContextLocal<WorkArea>()
{
protected WorkArea initialValue()
{
return new WorkArea();
}
};
/**
* Default constructor which defines the symbol libraries to be registered.
*/
DictionaryWorker()
{
super();
setLibrary(new Dictionary());
}
/**
* Provides generic scoped symbol dictionary services to pattern engine
* users.
*/
public class Dictionary
{
/** Default constructor which creates an instance and initializes. */
public Dictionary()
{
}
/**
* Adds a new named dictionary to the list of those available.
*
* @param dict
* The name of the new dictionary.
* @param sensitive
* If <code>true</code> the dictionary will match on a case-
* sensitive basis, <code>false</code> specifies
* case-insensitive matching.
*
* @return <code>true</code> if the dictionary was created or already
* exists, <code>false</code> on error.
*/
public boolean addDictionary(String dict, boolean sensitive)
{
if (dict == null)
{
return false;
}
WorkArea wa = context.get();
if (wa.dictList.get(dict) == null)
{
wa.dictList.put(dict, new ScopedSymbolDictionary<>(null, sensitive));
}
return true;
}
/**
* Deletes a named dictionary from the list of those available. All
* mapped data in that dictionary will be removed.
*
* @param dict
* The name of the new dictionary.
*
* @return Always returns <code>true</code>.
*/
public boolean deleteDictionary(String dict)
{
WorkArea wa = context.get();
wa.dictList.remove(dict);
return true;
}
/**
* Creates a new scope in the named dictionary. The new scope appears on
* top of the stack of scopes. All subsequent additions of new entries
* will be added to this scope, as long as it is at the top of the
* stack. Creates the dictionary if it doesn't exist yet.
*
* @param dict
* The name of the dictionary.
*
* @return Always returns <code>true</code>.
*/
public boolean addScope(String dict)
{
ScopedSymbolDictionary ssd = obtainDict(dict);
ssd.addScope(null);
return true;
}
/**
* Deletes the current top of stack scope in the named dictionary. All
* contained entries will be deleted.
*
* @param dict
* The name of the dictionary.
*
* @return Always returns <code>true</code>.
*/
public boolean deleteScope(String dict)
{
WorkArea wa = context.get();
ScopedSymbolDictionary ssd = wa.dictList.get(dict);
ssd.deleteScope();
return true;
}
/**
* Adds/replaces a key/value pair to a named dictionary, in the top
* scope. The value must be a string.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be made.
* @param value
* The value to be added.
*
* @return <code>true</code> if the entry has been added,
* <code>false</code> if its value has been replaced.
*/
public boolean addDictionaryString(String dict, String key, String value)
{
return addGeneric(dict, key, value);
}
/**
* Adds/replaces a key/value pair to a named dictionary, in the top
* scope. The value must a long.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be made.
* @param value
* The value to be added.
*
* @return <code>true</code> if the entry has been added,
* <code>false</code> if its value has been replaced.
*/
public boolean addDictionaryLong(String dict, String key, Long value)
{
return addGeneric(dict, key, value);
}
/**
* Adds/replaces a key/value pair to a named dictionary, in the top
* scope. The value must an integer.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be made.
* @param value
* The value to be added.
*
* @return <code>true</code> if the entry has been added,
* <code>false</code> if its value has been replaced.
*/
public boolean addDictionaryInteger(String dict, String key, Integer value)
{
return addGeneric(dict, key, value);
}
/**
* Adds/replaces a key/value pair to a named dictionary, in the top
* scope. The value must be a double.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be made.
* @param value
* The value to be added.
*
* @return <code>true</code> if the entry has been added,
* <code>false</code> if its value has been replaced.
*/
public boolean addDictionaryDouble(String dict, String key, Double value)
{
return addGeneric(dict, key, value);
}
/**
* Adds/replaces a key/value pair to a named dictionary, in the top
* scope. The value must be a boolean.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be made.
* @param value
* The value to be added.
*
* @return <code>true</code> if the entry has been added,
* <code>false</code> if its value has been replaced.
*/
public boolean addDictionaryBoolean(String dict, String key, Boolean value)
{
return addGeneric(dict, key, value);
}
/**
* Adds/replaces a key/value pair to a named dictionary, in the top
* scope.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be made.
* @param value
* The value to be added.
*
* @return <code>true</code> if the entry has been added,
* <code>false</code> if its value has been replaced.
*/
public boolean addDictionaryObject(String dict, String key, Object value)
{
return addGeneric(dict, key, value);
}
/**
* Replace value of the key/value pair in the specified scope depth.
* The scope depth is the 0-based index where 0 means current scope.
* The value must be a string.
*
* @param dict
* The name of the dictionary.
* @param scope
* The scope depth at which value must be set.
* @param key
* The name of the entry to be made.
* @param value
* The value to be returned from a lookup.
*
* @return <code>true</code> if the symbol has been replaced,
* <code>false</code> if no such dictionary/key or no such
* scope depth.
*/
public boolean setDictionaryStringAtScope(String dict, int scope, String key, String value)
{
return setGenericAtScope(dict, scope, key, value);
}
/**
* Replace value of the key/value pair in the specified scope depth.
* The scope depth is the 0-based index where 0 means current scope.
* The value must be a long.
*
* @param dict
* The name of the dictionary.
* @param scope
* The scope depth at which value must be set.
* @param key
* The name of the entry to be made.
* @param value
* The value to be returned from a lookup.
*
* @return <code>true</code> if the symbol has been replaced,
* <code>false</code> if no such dictionary/key or no such
* scope depth.
*/
public boolean setDictionaryLongAtScope(String dict, int scope, String key, Long value)
{
return setGenericAtScope(dict, scope, key, value);
}
/**
* Replace value of the key/value pair in the specified scope depth.
* The scope depth is the 0-based index where 0 means current scope.
* The value must be an integer.
*
* @param dict
* The name of the dictionary.
* @param scope
* The scope depth at which value must be set.
* @param key
* The name of the entry to be made.
* @param value
* The value to be returned from a lookup.
*
* @return <code>true</code> if the symbol has been replaced,
* <code>false</code> if no such dictionary/key or no such
* scope depth.
*/
public boolean setDictionaryIntegerAtScope(String dict,
int scope,
String key,
Integer value)
{
return setGenericAtScope(dict, scope, key, value);
}
/**
* Replace value of the key/value pair in the specified scope depth.
* The scope depth is the 0-based index where 0 means current scope.
* The value must be a boolean.
*
* @param dict
* The name of the dictionary.
* @param scope
* The scope depth at which value must be set.
* @param key
* The name of the entry to be made.
* @param value
* The value to be returned from a lookup.
*
* @return <code>true</code> if the symbol has been replaced,
* <code>false</code> if no such dictionary/key or no such
* scope depth.
*/
public boolean setDictionaryBooleanAtScope(String dict,
int scope,
String key,
Boolean value)
{
return setGenericAtScope(dict, scope, key, value);
}
/**
* Replace value of the key/value pair in the specified scope depth.
* The scope depth is the 0-based index where 0 means current scope.
* The value must be a double.
*
* @param dict
* The name of the dictionary.
* @param scope
* The scope depth at which value must be set.
* @param key
* The name of the entry to be made.
* @param value
* The value to be returned from a lookup.
*
* @return <code>true</code> if the symbol has been replaced,
* <code>false</code> if no such dictionary/key or no such
* scope depth.
*/
public boolean setDictionaryDoubleAtScope(String dict, int scope, String key, Double value)
{
return setGenericAtScope(dict, scope, key, value);
}
/**
* Replace value of the key/value pair in the specified scope depth.
* The scope depth is the 0-based index where 0 means current scope.
*
* @param dict
* The name of the dictionary.
* @param scope
* The scope depth at which value must be set.
* @param key
* The name of the entry to be made.
* @param value
* The value to be returned from a lookup.
*
* @return <code>true</code> if the symbol has been replaced,
* <code>false</code> if no such dictionary/key or no such
* scope depth.
*/
public boolean setDictionaryObjectAtScope(String dict, int scope, String key, Object value)
{
return setGenericAtScope(dict, scope, key, value);
}
/**
* Queries the total number of scopes in the dictionary (including a
* global scope if it exists).
*
* @param dict
* The name of the dictionary.
*
* @return The number of scopes in the dictionary (returns -1 if the
* dictionary does not exist).
*/
public int dictionaryMaxDepth(String dict)
{
WorkArea wa = context.get();
ScopedSymbolDictionary<Object> ssd = wa.dictList.get(dict);
if (ssd == null)
{
return -1;
}
return ssd.size();
}
/**
* Tests for the existence of a specified key in a named dictionary.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be found.
*
* @return <code>true</code> if the key exists.
*/
public boolean dictionaryContains(String dict, String key)
{
return lookupGeneric(dict, key) != null;
}
/**
* Returns the list of all matches of a specified key in a named dictionary.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be found.
*
* @return The list of all matches, may be an empty list.
*/
public List<Object> dictionaryListMatches(String dict, String key)
{
WorkArea wa = context.get();
ArrayList<Object> list = new ArrayList<>();
ScopedSymbolDictionary<Object> ssd = wa.dictList.get(dict);
if (ssd != null)
{
int size = ssd.size();
for (int i = 0; i < size; i++)
{
Object current = ssd.getValueAtScope(key, i);
if (current != null)
{
list.add(current);
}
}
}
return list;
}
/**
* Returns the number of matches of a specified key in a named
* dictionary.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be found.
*
* @return The number of levels in which a match was found.
*/
public int dictionaryNumMatches(String dict, String key)
{
return dictionaryListMatches(dict, key).size();
}
/**
* Tests for the existence of a specified key in a named dictionary
* and returns the 0-based depth at which the key is found or -1 if
* the key does not exist.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be found.
*
* @return The depth of the scope in which the specified key exists
* (0 if the key is found in the current scope, a value > 1
* if the key exists in a scope below the current scope) or
* -1 if the key is not found in any scope (or if the
* dictionary does not exist).
*/
public int dictionaryKeyDepth(String dict, String key)
{
WorkArea wa = context.get();
ScopedSymbolDictionary<Object> ssd = wa.dictList.get(dict);
if (ssd == null)
{
return -1;
}
return ssd.locateSymbol(key);
}
/**
* Locate the 0-based scope depth of the specified value of specified
* variable.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be found.
* @param value
* The value of the entry to compare with.
*
* @return The depth of the scope in which the specified value exists
* (0 if the value is found in the current scope, a value > 1
* if the key exists in a scope below the current scope) or
* -1 if the key is not found in any scope (or if the
* dictionary does not exist).
*/
public int dictionaryValueDepth(String dict, String key, Object value)
{
WorkArea wa = context.get();
ScopedSymbolDictionary<Object> ssd = wa.dictList.get(dict);
if (ssd == null)
{
return -1;
}
return ssd.locateSymbolValue(key, value);
}
/**
* Returns a set containing all defined symbol names as strings, for the given dictionary.
*
* @param dict
* The name of the dictionary.
*
* @return All symbols in the given dictionary (from all scopes).
*/
public Set<String> dictionarySymbolSet(String dict)
{
WorkArea wa = context.get();
ScopedSymbolDictionary<Object> ssd = wa.dictList.get(dict);
if (ssd == null)
{
return Collections.emptySet();
}
return ssd.symbolSet();
}
/**
* Returns a set containing all defined symbol names as strings, for the given scope in the
* given dictionary.
*
* @param dict
* The name of the dictionary.
* @param scope
* The depth (in number of scopes from the top of the stack) from which the
* symbols are collected. Use -1 to reference the global scope.
*
* @return All symbols in the given dictionary (from all scopes).
*/
public Set<String> dictionarySymbolSet(String dict, int scope)
{
WorkArea wa = context.get();
ScopedSymbolDictionary<Object> ssd = wa.dictList.get(dict);
if (ssd == null)
{
return Collections.emptySet();
}
return ssd.symbolSet(scope);
}
/**
* Searches the named dictionary for the value associated with a
* specified key or <code>null</code> if the key does not exist.
* The search is limited to specified scope.
* The value must be a string.
*
* @param dict
* The name of the dictionary.
* @param scope
* The scope at which value should be located.
* @param key
* The name of the entry to be found.
*
* @return The value found for the specified key or <code>null</code>
* if the key does not exist.
*/
public String lookupDictionaryStringAtScope(String dict, int scope, String key)
{
return (String) lookupGenericAtScope(dict, scope, key);
}
/**
* Searches the named dictionary for the value associated with a
* specified key or <code>null</code> if the key does not exist.
* The search is limited to specified scope.
* The value must be a long.
*
* @param dict
* The name of the dictionary.
* @param scope
* The scope at which value should be located.
* @param key
* The name of the entry to be found.
*
* @return The value found for the specified key or <code>null</code>
* if the key does not exist.
*/
public Long lookupDictionaryLongAtScope(String dict, int scope, String key)
{
return (Long) lookupGenericAtScope(dict, scope, key);
}
/**
* Searches the named dictionary for the value associated with a
* specified key or <code>null</code> if the key does not exist.
* The search is limited to specified scope.
* The value must be an integer.
*
* @param dict
* The name of the dictionary.
* @param scope
* The scope at which value should be located.
* @param key
* The name of the entry to be found.
*
* @return The value found for the specified key or <code>null</code>
* if the key does not exist.
*/
public Integer lookupDictionaryIntegerAtScope(String dict, int scope, String key)
{
return (Integer) lookupGenericAtScope(dict, scope, key);
}
/**
* Searches the named dictionary for the value associated with a
* specified key or <code>null</code> if the key does not exist.
* The search is limited to specified scope.
* The value must be a double.
*
* @param dict
* The name of the dictionary.
* @param scope
* The scope at which value should be located.
* @param key
* The name of the entry to be found.
*
* @return The value found for the specified key or <code>null</code>
* if the key does not exist.
*/
public Double lookupDictionaryDoubleAtScope(String dict, int scope, String key)
{
return (Double) lookupGenericAtScope(dict, scope, key);
}
/**
* Searches the named dictionary for the value associated with a
* specified key or <code>null</code> if the key does not exist.
* The search is limited to specified scope.
* The value must be a boolean.
*
* @param dict
* The name of the dictionary.
* @param scope
* The scope at which value should be located.
* @param key
* The name of the entry to be found.
*
* @return The value found for the specified key or <code>null</code>
* if the key does not exist.
*/
public Boolean lookupDictionaryBooleanAtScope(String dict, int scope, String key)
{
return (Boolean) lookupGenericAtScope(dict, scope, key);
}
/**
* Searches the named dictionary for the value associated with a
* specified key or <code>null</code> if the key does not exist.
* The search is limited to specified scope.
*
* @param dict
* The name of the dictionary.
* @param scope
* The scope at which value should be located.
* @param key
* The name of the entry to be found.
*
* @return The value found for the specified key or <code>null</code>
* if the key does not exist.
*/
public Object lookupDictionaryObjectAtScope(String dict, int scope, String key)
{
return lookupGenericAtScope(dict, scope, key);
}
/**
* Searches the named dictionary for the value associated with a
* specified key or <code>null</code> if the key does not exist.
* The value must be a string.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be found.
*
* @return The value found for the specified key or <code>null</code>
* if the key does not exist.
*/
public String lookupDictionaryString(String dict, String key)
{
return (String) lookupGeneric(dict, key);
}
/**
* Searches the named dictionary for the value associated with a
* specified key or <code>null</code> if the key does not exist.
* The value must be a long.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be found.
*
* @return The value found for the specified key or <code>null</code>
* if the key does not exist.
*/
public Long lookupDictionaryLong(String dict, String key)
{
return (Long) lookupGeneric(dict, key);
}
/**
* Searches the named dictionary for the value associated with a
* specified key or <code>null</code> if the key does not exist.
* The value must be an integer.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be found.
*
* @return The value found for the specified key or <code>null</code>
* if the key does not exist.
*/
public Integer lookupDictionaryInteger(String dict, String key)
{
return (Integer) lookupGeneric(dict, key);
}
/**
* Searches the named dictionary for the value associated with a
* specified key or <code>null</code> if the key does not exist.
* The value must be a double.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be found.
*
* @return The value found for the specified key or <code>null</code>
* if the key does not exist.
*/
public Double lookupDictionaryDouble(String dict, String key)
{
return (Double) lookupGeneric(dict, key);
}
/**
* Searches the named dictionary for the value associated with a
* specified key or <code>null</code> if the key does not exist.
* The value must be a boolean.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be found.
*
* @return The value found for the specified key or <code>null</code>
* if the key does not exist.
*/
public Boolean lookupDictionaryBoolean(String dict, String key)
{
return (Boolean) lookupGeneric(dict, key);
}
/**
* Searches the named dictionary for the value associated with a
* specified key or <code>null</code> if the key does not exist.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be found.
*
* @return The value found for the specified key or <code>null</code>
* if the key does not exist.
*/
public Object lookupDictionaryObject(String dict, String key)
{
return lookupGeneric(dict, key);
}
/**
* Dump the contents of the specifified dictionary to
* <code>stdout</code>. Prints an error message if the given dictionary
* is not found.
*
* @param dict
* The name of the dictionary.
*/
public void dumpDictionary(String dict)
{
WorkArea wa = context.get();
ScopedSymbolDictionary<Object> ssd = wa.dictList.get(dict);;
if (ssd == null)
{
System.out.println("Dictionary '" + dict + "' not found");
return;
}
ssd.dump(System.out);
}
/**
* Generic worker to add/replace a key/value pair in a named dictionary,
* in the top scope. Creates the dictionary if it doesn't exist yet.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be made.
* @param value
* The value to be returned from a lookup.
*
* @return <code>true</code> if the symbol has been added,
* <code>false</code> if its value has been replaced.
*/
private boolean addGeneric(String dict, String key, Object value)
{
ScopedSymbolDictionary<Object> ssd = obtainDict(dict);
return ssd.addSymbol(false, key, value);
}
/**
* Generic worker to replace a key/value pair in a named dictionary,
* in the specified scope depth. The scope depth is the 0-based index
* where 0 means current scope.
*
* @param dict
* The name of the dictionary.
* @param scope
* The scope depth at which value must be set.
* @param key
* The name of the entry to be made.
* @param value
* The value to be returned from a lookup.
*
* @return <code>true</code> if the symbol has been replaced,
* <code>false</code> if no such dictionary/key or no such
* scope depth.
*/
private boolean setGenericAtScope(String dict, int scope, String key, Object value)
{
WorkArea wa = context.get();
ScopedSymbolDictionary<Object> ssd = wa.dictList.get(dict);
if (ssd == null)
{
return false;
}
return ssd.setSymbolAtScope(key, scope, value);
}
/**
* Generic worker to search the named dictionary in all scopes from the
* top of the stack down for a given key.
*
* @param dict
* The name of the dictionary.
* @param key
* The name of the entry to be found.
*
* @return Value of the key or <code>null</code> if not found.
*/
private Object lookupGeneric(String dict, String key)
{
WorkArea wa = context.get();
ScopedSymbolDictionary<Object> ssd = wa.dictList.get(dict);
if (ssd == null)
{
return null;
}
return ssd.lookupSymbol(key);
}
/**
* Generic worker to search the named dictionary in all scopes from the
* top of the stack down for a given key.
*
* @param dict
* The name of the dictionary.
* @param scope
* The scope depth at which value must be retrieved.
* @param key
* The name of the entry to be found.
*
* @return Value of the key or <code>null</code> if not found.
*/
private Object lookupGenericAtScope(String dict, int scope, String key)
{
WorkArea wa = context.get();
ScopedSymbolDictionary<Object> ssd = wa.dictList.get(dict);
if (ssd == null)
return null;
return ssd.getSymbolAtScope(key, scope);
}
/**
* Returns the existing dictionary of the given name or if a dictionary
* does not exist, a case-insensitive dictionary will be created and
* then returned.
*
* @param dict
* The name of the dictionary.
*
* @return The dictionary or <code>null</code> if the input string
* is <code>null</code>.
*/
private ScopedSymbolDictionary<Object> obtainDict(String dict)
{
if (dict == null)
{
return null;
}
WorkArea wa = context.get();
ScopedSymbolDictionary<Object> d = wa.dictList.get(dict);
// add a new case-insensitive dictionary if it doesn't exist yet
if (d == null)
{
addDictionary(dict, false);
d = wa.dictList.get(dict);
}
return d;
}
}
/**
* Context local work area.
*/
private static class WorkArea
{
/** Stores all named dictionaries that are active. */
private Map<String, ScopedSymbolDictionary<Object>> dictList = new HashMap<>();
}
}