Class ScopeStack

java.lang.Object
org.ek9lang.compiler.common.ScopeStack

public class ScopeStack extends Object
This stack object is only designed to be used when first parsing. The idea is to actually associate the scope with the specific contexts by putting them in a ParseTreeProperty of Scope, this tree is held in the ParsedModule. So why do we need this stack? That is because as we listen/visit the parse tree we need to both create the scope and record it in the parsed module. But also put it on to a stack so that when we return for each level of the parse tree we can get back to the right scope. I don't want to use a 'getEnclosingScope' method on each scope as the very top level has to be thread safe. Plus it exposes information that should only be available to the scope itself - not any other bit of code. This class also has logic and code to be able to traverse back up the 'structure stack'.
  • Constructor Details

    • ScopeStack

      public ScopeStack(IScope base)
  • Method Details

    • getVeryBaseScope

      public IScope getVeryBaseScope()
    • push

      public IScope push(IScope scope)
      Push a scope on to this stack.
    • peek

      public IScope peek()
      Take a look at the top of the stack.
    • pop

      public IScope pop()
      Pop a scope of the stack (exception is empty.
    • isEmpty

      public boolean isEmpty()
      True if stack has no contents.
    • traverseBackUpStack

      public Optional<IScope> traverseBackUpStack(IScope.ScopeType scopeType)
      Navigates back up the scope stack to find the first match of the scope type passed in. This is useful because dynamic classes and functions do not use an enclosing scope of the scope they are in. They get pulled out to module level (by design).
    • traverseBackUpStackBeyond

      public Optional<IScope> traverseBackUpStackBeyond(IScope beyond, IScope.ScopeType scopeType)
      Like traverseBackUpStack(IScope.ScopeType), but only considers the scopes OUTSIDE beyond - the ones pushed before it. A null (or a scope not on the stack) means the whole stack, from the top.

      This is how code that is evaluated in the scope AROUND a construct is judged there: a dynamic function's or class's capture list is visited with the dynamic construct already on the stack, yet each capture expression is evaluated where the construct is created (the enclosing method, function or dynamic body).

    • traverseBackUpStackToMethodOrFunction

      public Optional<IScopedSymbol> traverseBackUpStackToMethodOrFunction()
      Locates the outer function or method (if possible, not always possible Applications for example).
    • traverseBackUpStackToEnclosingNamedMethodOrFunction

      public Optional<IScopedSymbol> traverseBackUpStackToEnclosingNamedMethodOrFunction()
      Like traverseBackUpStackToMethodOrFunction() but skips dynamic (anonymous) functions/classes — those introduced by dynamic function/class declarations such as MutexKey bodies and closures (marked IScope.ScopeType.DYNAMIC_BLOCK). Returns the nearest *named* enclosing method or function, so a construct lexically inside an anonymous body (e.g. a MutexLock.enter() call within a MutexKey lambda) is attributed to the enclosing named callable rather than to the anonymous body itself — the latter only has a synthetic name (e.g. _Function_<hash>, displayed as fn).
    • traverseBackUpStackToNearestAggregate

      public Optional<AggregateSymbol> traverseBackUpStackToNearestAggregate()
      The nearest enclosing aggregate - a dynamic class when the scope is inside one, otherwise the named class, component, service, trait, record or program around it. A method, a block and a dynamic function are passed through (none of them holds fields), so a dynamic function inside a class method answers the class. There is none inside a standalone function.
    • traverseBackUpStackToNearestAggregateBeyond

      public Optional<AggregateSymbol> traverseBackUpStackToNearestAggregateBeyond(IScope beyond)
      Like traverseBackUpStackToNearestAggregate(), but only considers the scopes OUTSIDE beyond - the ones pushed before it (a null, or a scope not on the stack, means the whole stack). A dynamic class's capture list is visited with that dynamic class already pushed, yet it is evaluated by the code around it.
    • traverseBackUpStackToNearestGeneric

      public Optional<PossibleGenericSymbol> traverseBackUpStackToNearestGeneric()
      The nearest enclosing GENERIC type or function - the one whose type parameters a body here can name. A method, a block, a dynamic function and a dynamic class are passed through (none of them is generic), so a dynamic function inside a generic class's method answers the generic class.
    • traverseBackUpStackToEnclosingMethod

      public Optional<MethodSymbol> traverseBackUpStackToEnclosingMethod()
      Navigate back up the scope stack to find the first enclosing method (there may not be one). So if this were called in a function or an application for example - there will not be an enclosing method.
      Returns:
      The Optional method located.
    • isWithinLoopScope

      public boolean isWithinLoopScope()
      Checks if the current scope is within a loop (for or while). This is useful for determining whether a variable assignment inside a loop should suppress the "not referenced after assignment" check.
      Returns:
      true if currently within a ForSymbol or WhileSymbol scope.