Class SymbolsAndScopes
java.lang.Object
org.ek9lang.compiler.common.SymbolsAndScopes
Used as external helper to record symbols and scopes across the parser.
They are held in the parsedModule against specific nodes in the parseTree.
This enables later phases to look up the symbols and scopes when it encounters
the same node in the parseTree. In this way the symbols get 'fleshed out'
with more details in each of the compiler phases.
This does push scopes on to the scope stack - that the listener uses.
IMPORTANT concepts here:
1. The ParsedModule keeps a record of a Symbol against a ParseTree node
2. The ParsedModule keeps a record of a Scope against a ParseTree node
3. The scopeStack keeps a dynamic position of the current scope stuff is being added to.
But the scopeStack is ephemeral - it grows and shrinks based on the language constructs the
listener encounters, as stuff is added in - that scope become richer. But when the end of the
scope is encountered - it is popped off the scopeStack.
All would be lost! - But for the fact that the symbols/scopes were registered against a ParseTree node in the
ParsedModule. Hence, it lives on - with all the sub scopes and symbols.
This information in the ParsedModule will be enriched further in additional and different passes.
Now also uses a transient CodeFlowAnalyzer to assess whether variables in instruction blocks have been initialised.
Now also uses a transient CodeFlowAnalyzer to assess whether variables in instruction blocks have been initialised.
-
Constructor Summary
ConstructorsConstructorDescriptionSymbolsAndScopes(ParsedModule parsedModule, ScopeStack scopeStack) Create a new instance for symbol and scope management. -
Method Summary
Modifier and TypeMethodDescriptionvoiddefineScopedSymbol(IScopedSymbol symbol, org.antlr.v4.runtime.tree.ParseTree node) Record a new scoped symbol in the current scope on the stack.voidenterModuleScopedSymbol(IScopedSymbol symbol, org.antlr.v4.runtime.tree.ParseTree node, SymbolChecker symbolChecker) To be used when defining a high level symbol at module scope.voidenterNewConstant(ISymbol symbol, org.antlr.v4.runtime.tree.ParseTree node, SymbolChecker symbolChecker) Create a new constant as declared in the constants section and records the symbol.voidenterNewLiteral(ISymbol symbol, org.antlr.v4.runtime.tree.ParseTree node) For literals, we only record in the parsedModule.voidenterNewScope(IScope scope, org.antlr.v4.runtime.tree.ParseTree node) Enter a new scope and record in both the parsed module and push on to the working scope stack.voidenterNewScopedSymbol(IScopedSymbol symbol, org.antlr.v4.runtime.tree.ParseTree node) Enter a new scoped symbol and record in parsed module as a symbol and as a scope.voidenterNewSymbol(ISymbol symbol, org.antlr.v4.runtime.tree.ParseTree node) A new symbol has been encountered and is defined within the current scope in the scope stack and recorded in the parsedModule against the appropriate node.enterScope(org.antlr.v4.runtime.tree.ParseTree ctx) Ensure that the correct scope is pushed on to the stack.voidenterScope(IScope scope) To be used to ensure that a scope has been pushed on to the scopeStack.voidNormally called at the point where the parser listener exits a scope.Provide access to the set of code flow analyzers being used for flow analysis.getRecordedScope(org.antlr.v4.runtime.tree.ParseTree node) getRecordedSymbol(org.antlr.v4.runtime.tree.ParseTree node) Provides access to the top of the scope stack.getUninitialisedVariables(IScope inScope) booleanisErrorResultAccessSafe(ISymbol identifierSymbol) booleanbooleanisGetOptionalAccessSafe(ISymbol identifierSymbol) booleanisNextIteratorAccessSafe(ISymbol identifierSymbol) booleanisOkResultAccessSafe(ISymbol identifierSymbol) booleanisSymbolAccessSafe(ISymbol identifierSymbol) true if identifier is safe to access.booleanisVariableInitialised(ISymbol identifierSymbol) booleanisVariableInitialised(ISymbol identifierSymbol, IScope inScope) voidmarkErrorResultAccessSafe(ISymbol identifierSymbol, IScope inScope) voidmarkGetOptionalAccessSafe(ISymbol identifierSymbol, IScope inScope) voidmarkNextIteratorAccessSafe(ISymbol identifierSymbol, IScope inScope) voidmarkOkResultAccessSafe(ISymbol identifierSymbol, IScope inScope) voidmarkSymbolAccessSafe(ISymbol identifierSymbol, IScope inScope) Record an identifier as being safe to access.voidmarkSymbolAsInitialised(ISymbol identifierSymbol, IScope inScope) Record an identifier was initialised.voidrecordDeclarationOfVariableUsingIterator(ISymbol identifierSymbol) voidrecordDeclarationOfVariableUsingOptional(ISymbol identifierSymbol) voidrecordDeclarationOfVariableUsingResult(ISymbol identifierSymbol) voidrecordScopeForStackConsistency(IScope scope, org.antlr.v4.runtime.tree.ParseTree node) There are times in parsing/listening when symbols are already defined (due to a developer error).voidrecordSymbol(ISymbol symbol, org.antlr.v4.runtime.tree.ParseTree node) Record a symbol against a specific node (so it can be looked up later).voidrecordSymbolAssignment(ISymbol identifierSymbol) Record an identifier was assigned and therefore initialised.voidrecordSymbolDeclaration(ISymbol identifierSymbol) Records a variable against the appropriate scope.voidrecordSymbolDeclaration(ISymbol identifierSymbol, IScope inScope) Record variable declaration against a specific scope.resolveOrDefine(PossibleGenericSymbol parameterisedSymbol, ErrorListener errorListener) traverseBackUpStack(IScope.ScopeType scopeType) Navigates back up the scope stack to find the first match of the scope type passed in.Traversed back up the scope stack to try and locate the enclosing method (if there is one).
-
Constructor Details
-
SymbolsAndScopes
Create a new instance for symbol and scope management. If these types are not resolved then OK with a big exception and stop processing (so suppress get warning).
-
-
Method Details
-
isExternallyImplemented
public boolean isExternallyImplemented() -
getModuleScope
-
getEk9Types
-
getCodeFlowAnalyzers
Provide access to the set of code flow analyzers being used for flow analysis. -
getUninitialisedVariables
-
isVariableInitialised
-
isVariableInitialised
-
recordSymbolDeclaration
Records a variable against the appropriate scope. -
recordSymbolDeclaration
-
recordDeclarationOfVariableUsingResult
-
recordDeclarationOfVariableUsingOptional
-
recordDeclarationOfVariableUsingIterator
-
recordSymbolAssignment
Record an identifier was assigned and therefore initialised. -
markSymbolAsInitialised
-
markSymbolAccessSafe
-
isSymbolAccessSafe
true if identifier is safe to access. -
markOkResultAccessSafe
-
isOkResultAccessSafe
-
markErrorResultAccessSafe
-
isErrorResultAccessSafe
-
markGetOptionalAccessSafe
-
isGetOptionalAccessSafe
-
markNextIteratorAccessSafe
-
isNextIteratorAccessSafe
-
enterScope
Ensure that the correct scope is pushed on to the stack. This method takes a context, retrieves the scope, checks for null and then pushes it.- Parameters:
ctx- The contact that must have a scope recorded.
-
enterScope
To be used to ensure that a scope has been pushed on to the scopeStack. -
exitScope
public void exitScope()Normally called at the point where the parser listener exits a scope. The scope will be popped off the scopeStack to reveal the parent scope. -
getTopScope
Provides access to the top of the scope stack. -
getParentOfTopScope
-
traverseBackUpStack
Navigates back up the scope stack to find the first match of the scope type passed in. -
traverseBackUpStackToEnclosingMethod
Traversed back up the scope stack to try and locate the enclosing method (if there is one). Clearly the scope might not be within a method and so Optional.empty will result.- Returns:
- The method and aggregate information if a method was located.
-
traverseBackUpStackToMethodOrFunction
-
resolveOrDefine
public Optional<ISymbol> resolveOrDefine(PossibleGenericSymbol parameterisedSymbol, ErrorListener errorListener) -
enterNewSymbol
A new symbol has been encountered and is defined within the current scope in the scope stack and recorded in the parsedModule against the appropriate node. -
getRecordedSymbol
-
getRecordedScope
-
recordSymbol
Record a symbol against a specific node (so it can be looked up later). -
enterNewLiteral
For literals, we only record in the parsedModule. -
enterNewConstant
public void enterNewConstant(ISymbol symbol, org.antlr.v4.runtime.tree.ParseTree node, SymbolChecker symbolChecker) Create a new constant as declared in the constants section and records the symbol. -
enterModuleScopedSymbol
public void enterModuleScopedSymbol(IScopedSymbol symbol, org.antlr.v4.runtime.tree.ParseTree node, SymbolChecker symbolChecker) To be used when defining a high level symbol at module scope. -
defineScopedSymbol
Record a new scoped symbol in the current scope on the stack. Also records the symbol as both a scope and a symbol in the parsedModule. -
enterNewScopedSymbol
Enter a new scoped symbol and record in parsed module as a symbol and as a scope. Then push the scope on to the working scope stack. -
enterNewScope
Enter a new scope and record in both the parsed module and push on to the working scope stack. -
recordScopeForStackConsistency
There are times in parsing/listening when symbols are already defined (due to a developer error). During this situation we cannot define a new node, but we can detect the duplicate (display errors). But so the scope stack does not get corrupted - it is important to still push the existing scope on to the stack. In this way when the stack is popped everything works out.
-