Class SymbolTable

java.lang.Object
org.ek9lang.compiler.symbols.SymbolTable
All Implemented Interfaces:
Serializable, IScope
Direct Known Subclasses:
LocalScope, ModuleScope

public class SymbolTable extends Object implements IScope
We need to support simple things like classes which are unique per symbol table Or the fully qualified class names like 'com.some.A and com.other.A' so they won't collide. But we don't want to define constants/variables like 'int A and float A' this is a duplicate We do want method overloading like int A() and int A(String some param) But not int A() and float A() as that is not good.
So for the most part this is straight forward, but this issue is operators and type matching.
i.e support for
1. int A()
2. int A(String v1)
3. int A(String v1, int someItem)
4. int A(int item, String other)
5. int A(List of String list1)
6. int A(List of Integer list2)
7. float A(List of Integer list3, String other)
8. int A(List of Double list4, String other)
9. int A(SomeClass sc)
10. int A(ClassThatExtendsSomeClass supersc)
When we define these we want them all to be defined and available in the appropriate scope. The issue is doing the resolve! We can't just say hey I'm trying to resolve 'A' that's just not enough We need to know:
1. Are we looking for a class(type), function/method or variable/constant in this context.
2. What is it's name - in this case 'A'
3. What type (or return type) are we expecting - but here we should accept a super class match
with some cost match value
4. What is the order and type of parameters - again we need to try and match with some weight
using super class matches.
So what sort of algorithm can we use for this?
The Symbol has a type already when we define it - we know if it is an AggregateSymbol,
MethodSymbol etc. We also know its name!
We know the Symbol we will use for it's return type or what it is i.e the Symbol of Integer as
the return type or what it is.
For methods (which are Scoped Symbols) we also have the parameters (in order).
So while parameters can be used when making the call this is just sugar - the order still has
to match.

Well we could have separate internal tables for methods/functions, classes/types and variables.
So we can quickly and simply resolve obvious ones like variables and types.
Then use more expensive operations for methods.

Now for methods we can store in a hash map of method names - so in a simple case with just one
method of name A we're done!
But in that hashmap we store and List of all methods of that name - now we have the costly
activity of going through each and getting the cost of each to find a match. in local scopes
which ever is the best match we return - but clearly it is possible there is no match then we
resort to moving back up the scope tree (as we do now).
See Also:
  • Constructor Details

    • SymbolTable

      public SymbolTable(String scopeName)
    • SymbolTable

      public SymbolTable()
  • Method Details

    • getEnclosingScope

      public IScope getEnclosingScope()
      Specified by:
      getEnclosingScope in interface IScope
    • getFriendlyScopeName

      public String getFriendlyScopeName()
      Description copied from interface: IScope
      Useful for printing out errors and information. The scope name might be a complex generated name used internally a bit like symbol names are. So some items are both scopes and symbols - so ideally we'd want to use a friendly name where possible.
      Specified by:
      getFriendlyScopeName in interface IScope
      Returns:
      The friendly name to be used for the developer.
    • getScopeName

      public String getScopeName()
      Specified by:
      getScopeName in interface IScope
    • getScopeType

      public IScope.ScopeType getScopeType()
      Specified by:
      getScopeType in interface IScope
    • isTerminatedNormally

      public boolean isTerminatedNormally()
      Description copied from interface: IScope
      Typically in a scoped block we can encounter situations (like exceptions) that cause the block to end (terminate) early.
      Specified by:
      isTerminatedNormally in interface IScope
    • getEncounteredExceptionToken

      public IToken getEncounteredExceptionToken()
      Specified by:
      getEncounteredExceptionToken in interface IScope
    • setEncounteredExceptionToken

      public void setEncounteredExceptionToken(IToken encounteredExceptionToken)
      Specified by:
      setEncounteredExceptionToken in interface IScope
    • clone

      public SymbolTable clone(IScope withParentAsAppropriate)
      Specified by:
      clone in interface IScope
    • cloneIntoSymbolTable

      protected SymbolTable cloneIntoSymbolTable(SymbolTable rtn, IScope withParentAsAppropriate)
    • isMarkedPure

      public boolean isMarkedPure()
      Description copied from interface: IScope
      Typically used with functions. Something that is pure cannot have 'side effects'. To enforce this a bit of logic can have no references to other variables, methods and functions else how can no side effects be guaranteed. Hence, a function that just tests a value or calculates a result is deemed pure. Anything else is questionable.
      Specified by:
      isMarkedPure in interface IScope
      Returns:
      true if marked as pure, false otherwise.
    • setMarkedPure

      public void setMarkedPure(boolean markedPure)
    • define

      public void define(ISymbol symbol)
      Description copied from interface: IScope
      Define a Symbol in this scope.
      Specified by:
      define in interface IScope
    • equals

      public boolean equals(Object o)
      Overrides:
      equals in class Object
    • hashCode

      public int hashCode()
      Overrides:
      hashCode in class Object
    • getSymbolsForThisScopeOfCategory

      public List<ISymbol> getSymbolsForThisScopeOfCategory(SymbolCategory category)
      Find symbols in a specific category.
    • getSymbolsForThisScope

      public List<ISymbol> getSymbolsForThisScope()
      Get all the symbols in this table.

      Returns a List.copyOf(Collection) snapshot rather than Collections.unmodifiableList(List): callers may iterate this list during multi-threaded phases (e.g. IR generation reads aggregate scopes in parallel) while another thread legitimately mutates the backing orderedSymbols. An unmodifiable VIEW shares the backing list, so a concurrent define(...) surfaces as a ConcurrentModificationException in the earlier caller's iteration; a snapshot taken at the call site is consistent and insulates the caller. Mirrors Modules.getModules().

      Specified by:
      getSymbolsForThisScope in interface IScope
    • getAllSymbolsMatchingName

      public List<ISymbol> getAllSymbolsMatchingName(String symbolName)
      Description copied from interface: IScope
      Return a list of all the symbols that match the name. So for class and traits this must include supers and traits.
      Specified by:
      getAllSymbolsMatchingName in interface IScope
    • resolve

      public Optional<ISymbol> resolve(SymbolSearch search)
      Search and resolve from a symbol search.
      Specified by:
      resolve in interface IScope
    • resolveMatchingMethods

      public MethodSymbolSearchResult resolveMatchingMethods(MethodSymbolSearch search, MethodSymbolSearchResult result)
      Add all matching methods for a method search.
      Specified by:
      resolveMatchingMethods in interface IScope
    • resolveMatchingMethodsInThisScopeOnly

      public MethodSymbolSearchResult resolveMatchingMethodsInThisScopeOnly(MethodSymbolSearch search, MethodSymbolSearchResult result)
      Add all matching methods for a method search but only in this scope.
      Specified by:
      resolveMatchingMethodsInThisScopeOnly in interface IScope
    • resolveMatchingMethodsInEnclosingScope

      protected MethodSymbolSearchResult resolveMatchingMethodsInEnclosingScope(MethodSymbolSearch search, MethodSymbolSearchResult result)
      There are no supers so this will not add any methods.
    • resolveMember

      public Optional<ISymbol> resolveMember(SymbolSearch search)
      Description copied from interface: IScope
      Just resolve on this or supers/traits - but not anything outside of the class hierarchy.
      Specified by:
      resolveMember in interface IScope
    • searchIsNotInThisScope

      protected boolean searchIsNotInThisScope(SymbolSearch search)
      If search is unqualified (i.e. just a name then yes we look in this scope). If the search is a fully qualified name then the scope name in the search has to match this scope.
    • resolveInThisScopeOnly

      public Optional<ISymbol> resolveInThisScopeOnly(SymbolSearch search)
      Resolve a symbol in this symbol table only.
      Specified by:
      resolveInThisScopeOnly in interface IScope
    • resolveWithEnclosingScope

      public Optional<ISymbol> resolveWithEnclosingScope(SymbolSearch search)
      This class is the root and so there is no enclosing scope. subclasses will override to provide the scope that encloses them
    • isScopeAMatchForEnclosingScope

      public boolean isScopeAMatchForEnclosingScope(IScope toCheck)
      Specified by:
      isScopeAMatchForEnclosingScope in interface IScope
    • findNearestNonBlockScopeInEnclosingScopes

      public Optional<ScopedSymbol> findNearestNonBlockScopeInEnclosingScopes()
      Specified by:
      findNearestNonBlockScopeInEnclosingScopes in interface IScope
    • findNearestDynamicBlockScopeInEnclosingScopes

      public Optional<ScopedSymbol> findNearestDynamicBlockScopeInEnclosingScopes()
      Specified by:
      findNearestDynamicBlockScopeInEnclosingScopes in interface IScope
    • toString

      public String toString()
      Overrides:
      toString in class Object