Package org.ek9lang.compiler.phase1
This phase actually has a number of passes through the 'ANTLR' 'AST', in fact the EK9 Compiler uses both the 'ANTLR' Listener and Visitor models to process the 'AST'.
The reason for the multiple passes is to enable 'forward referencing', each successive pass tends to add more detail to the Symbols that are recorded.
The passes in phase 1 are:
These are configured in FrontEndSupplier
The SymbolDefinition mainly uses the
DefinitionListener with an 'ANTLR' - tree walker to traverse the 'AST'.
There are quite a few rules and checks - even at this early stage.
Most of these are simple Java 'Consumers' or 'BiConsumers' and do simple basic checks - issuing errors by calling
ErrorListener.semanticError(org.antlr.v4.runtime.Token, java.lang.String, org.ek9lang.compiler.common.ErrorListener.SemanticClassification)
with an appropriate ErrorListener.SemanticClassification.
In general many of the phases use the 'Listener' approach and 'walk the tree'. Sometimes they process
'ANTLR' contexts on entry and at other times on exit. The 'Listeners' use
SymbolsAndScopes and this uses a
ScopeStack to 'push and 'pop' scopes as the 'AST' is traversed.
In this way it is possible to add Symbols to the correct scope during AST traversal.
Most of the checks on symbols and constructs are very focussed and have a 'single responsibility'. They are then composed and applied. Initially most of these were just methods on classes. But this became quite complex, so it was refactored in to 'many' separate classes (Functions/Consumers). While there are many more classes it has helped enable more focus. This more functional approach does seem to work quite well and makes each of the rules and processing logic much more isolated and composable/reusable.
All three passes run single threaded. The latter two are cross source file and module checks; SymbolDefinition itself was multi-threaded once, but definition serialises on the CompilableProgram lock, so the parallel machinery was deliberately removed.
See org.ek9lang.compiler.phase2 for the next stage of compilation.
-
ClassDescriptionE01086: the members of an aggregate body (class, record, trait, component, dynamic class) out of the order EK9 requires - properties, then constructors and methods, then operators, then at most one bare
default operatoras the last item.Check that an application definition is configured in an acceptable form.Checks for the appropriate use of the APPLICATION of xyz on a method declaration.Checks if the body of a function is appropriate.THE reading of a binary or prefixexpressionalternative for the phase-1 operand-parentheses checks - E08269 (CoalescingOperandParenthesesOrError), E08273 (NotOperandParenthesesOrError) and E08274 (DoubleNegationOrError).Creates a suitable scope name for a token position.Just resolves a number of built-in types so that internal compiler code can be more explicit.E08269 (Steve, D6, 2026-10-07): a coalescing operator - the null coalescing??, the Elvis?:and the comparison coalescing family<? <=? >? >=?- may not be an UNPARENTHESISED operand of a DIFFERENT binary operator, nor take one as an operand.Designed to encapsulate the fact that two token are in conflict for a Symbol.Checks that either all parameters are named when making calls, or none are named at all.Checks constant organization within a multi-file module and emits errors if constants are scattered.Just go through and define the symbols and scopes putting into the ParsedModule against the appropriate context.E08274 (Steve, 2026-10-08, C1, Q8, Q9): a negation is never applied to a negation -not not b,~~b,- -x,not ~b,- ~x,~ -xand the same PARENTHESISED,not (not b),~(~b),-(-x),-(not b), are compile errors.A double-quoted String holding${is an error (E07901): a double-quoted String is never interpolated, so"${count} items"prints those characters rather than the count.Detects when a second 'defines package' block appears in a module and emits a dedicated error rather than a generic duplicate symbol message.Checks that a dynamic class does not used naming when used inside a generic type/function.Dynamic Variables when captured have to either be identifiers in their own right, but if they are some type of expression, method call, etc.Error if a construct and a reference conflict with each other.Error when a reference is made, but it cannot be resolved.To be called when an unreachable statement is encountered to emit an error.Detects when a 'defines' block (class, function, trait, etc.) is empty and emits a clear semantic error rather than letting it fail as a generic parse error.Detects excluded keywords and emits clear educational error messages.Typically used with programs.Just checks that named operator methods: mod, rem, abs, sqrt, close, contains, matches, empty, length are not being used as just method names.Goes through each module name and checks each of the parsedModules in that module name to check there is only a single copy of that symbol in the whole module name space.Detects multiple arrow usage and emits clear educational error messages.Typically used for Constructors, but could be used in other contexts where a method is not expected to return anything.Aimed at methods in services and a program (which is a method).Typically used in control expressions to check developer is not doing a while(true).Check not dispatcher methods.E08273 (Steve, 2026-10-07, P5; 2026-10-08, P6): wordnotis never an UNPARENTHESISED operand of another operator, exceptand,xorandor- so neither of any other binary operator (P5) nor of a prefix operator (P6:~not b,$ not b,#? not b, ...).Only use when code being checked prohibits use in outer generic context.Extracts capability data from a package block and stores as squirrelled data on the Package symbol.Reports a package property a package does not define, or one whose value is not of the shape it requires (E06260), using the same rule (PackageProperties) and message as the CLI's package pre-pass - which only the CLI runs, so without this the LSP and MCP tools acceptedname <- "myLib"andtags <- "x".Where EK9 needs a String it can read at compile time - a constant, a constraint, a text's language, a service parameter's name - only a plain"..."literal will do (E07902).If any of its OWN methods is marked as 'dispatcher' then mark this class as a 'dispatcher'.Checks what only a METHOD declaration can get wrong, in every method context: 'default' on a method that is not a constructor, the access modifier, and the constructor rules.Checks on whether the '?' can be used as a modifier then check the parent of this context.SINGLE THREADED - because we only want one reference shorthand for an item.Checks that references within a references block are in alphabetical order.Antlr listener for the references phase.Which pass this walk performs.Detects when a reserved keyword is used as an identifier and emits a clear error.SINGLE THREADED.Check an assignment again 'super' use and some operators against 'this' use.Checks that traits do not have properties/fields.A backslash-u in a String literal must be followed by exactly four hex digits (E07903).Checks that if the aggregate is a generic class that the appropriate public constructors are in place.Validates literal values at compile time to catch semantically invalid literals that the ANTLR lexer accepts structurally but that can never represent valid values.Checks methods from various contexts, typically this is delegated to other functions.Error when use of ParameterisedType has additional expression parameters in wrong context.Error when a reference is attempted by the syntax is incorrect.Checks that variable declarations is acceptable.