Class AbstractGenerator
- Direct Known Subclasses:
AbstractShortCircuitGenerator, AbstractVariableDeclGenerator, AssertStmtGenerator, AssignExpressionToSymbol, AssignmentExprInstrGenerator, AssignmentStmtGenerator, BinaryOperationGenerator, BlockStmtInstrGenerator, CallInstrGenerator, ConstructorCallProcessor, ControlFlowChainGenerator, ExprInstrGenerator, ForInGenerator, ForRangeGenerator, ForStatementGenerator, FunctionCallProcessor, GuardedAssignmentBlockGenerator, IfStatementGenerator, ListLiteralGenerator, LiteralGenerator, ObjectAccessInstrGenerator, OperationDfnGenerator, PrimaryReferenceGenerator, QuestionBlockGenerator, StmtInstrGenerator, SwitchCaseOrChainGenerator, SwitchStatementGenerator, ThrowStatementGenerator, TryCatchStatementGenerator, UnaryOperationGenerator, WhileStatementGenerator
Uses stack-based IRGenerationContext for state management, eliminating parameter threading. All generators inherit access to these safer utility methods to ensure consistency and reduce boilerplate code across the IR generation phase.
Core Principles:
- Safer Symbol Access - All symbol retrieval includes null and type checks
- Consistent Debug Info - Debug info is always tied to source locations
- Reduced Boilerplate - Common patterns are consolidated into helper methods
- Error Prevention - Invariant violations throw CompilerException with context
Available Safer Utilities:
getRecordedSymbolOrException(ParseTree)- Get symbol with null/type validationcreateTempVariable(DebugInfo)- Generate temp variable with debug infocreateTempVariableFromContext(ParseTree)- Temp variable from parse tree contextextractReturnType(ParseTree, ISymbol)- Safe return type extraction from CallSymbol
Usage Examples:
Pattern 1: Safe Symbol Access
// DON'T: Manual symbol retrieval with potential null issues
final var symbol = stackContext.getParsedModule().getRecordedSymbol(ctx);
if (symbol == null) {
throw new CompilerException("Symbol not found");
}
// DO: Use safer utility with automatic validation
final var symbol = getRecordedSymbolOrException(ctx);
Pattern 2: Temporary Variable Creation
// DON'T: Manual temp variable creation (3 lines)
final var tempName = stackContext.generateTempName();
final var debugInfo = stackContext.createDebugInfo(ctx);
final var tempDetails = new VariableDetails(tempName, debugInfo);
// DO: Use helper method (1 line when only VariableDetails needed)
final var tempDetails = createTempVariableFromContext(ctx);
// If individual components are needed (e.g., for separate use):
final var tempDetails = createTempVariableFromContext(ctx);
final var tempName = tempDetails.resultVariable();
final var debugInfo = tempDetails.debugInfo();
Pattern 3: Return Type Extraction
// DON'T: Manual type extraction with multiple conditionals
final var exprSymbol = getRecordedSymbolOrException(ctx);
ISymbol returnType;
if (exprSymbol instanceof CallSymbol cs) {
final var method = cs.getResolvedSymbolToCall();
if (method instanceof MethodSymbol ms) {
returnType = ms.getReturningSymbol().getType().orElse(fallback);
} else if (method instanceof FunctionSymbol fs) {
returnType = fs.getReturningSymbol().getType().orElse(fallback);
} else {
returnType = fallback;
}
} else {
returnType = exprSymbol.getType().orElseThrow();
}
// DO: Use helper method
final var returnType = extractReturnType(ctx, fallbackSymbol);
Integration with Other Safer Utilities:
AbstractGenerator works in conjunction with other Phase 7 safer utilities:
- TypeNameOrException - Extracts fully qualified type name from symbol
- SymbolTypeOrException - Extracts type symbol with error handling
- OperationDetailContextOrError - Locates operation context or throws
When to Use Which Utility:
- Need symbol from ParseTree? Use
getRecordedSymbolOrException(ctx) - Need type name as String? Use
typeNameOrException.apply(symbol) - Need type as ISymbol? Use
symbolTypeOrException.apply(symbol) - Need temp variable? Use
createTempVariableFromContext(ctx) - Need return type from call? Use
extractReturnType(ctx, fallback)
Design Philosophy:
These utilities follow the "fail-fast" principle: if something is wrong (null symbol, missing type, etc.), throw immediately with a descriptive error message rather than propagating null values or invalid state. This makes debugging easier and prevents cascading failures.
- See Also:
-
Field Summary
FieldsModifier and TypeFieldDescriptionprotected final DebugInfoCreatorprotected final IRInstructionBuilderprotected final IRGenerationContextprotected final TypeNameOrException -
Constructor Summary
ConstructorsConstructorDescriptionAbstractGenerator(IRGenerationContext stackContext) Constructor accepting only IRGenerationContext - the single source of state. -
Method Summary
Modifier and TypeMethodDescriptionprotected VariableDetailscreateTempVariable(DebugInfo debugInfo) Create a temporary variable with associated debug info.protected VariableDetailscreateTempVariableFromContext(org.antlr.v4.runtime.tree.ParseTree ctx) Create a temporary variable with debug info extracted from parse tree context.protected ISymbolextractReturnType(org.antlr.v4.runtime.tree.ParseTree ctx, ISymbol fallbackSymbol) Extract return type from a CallSymbol's resolved method.protected ISymbolgetRecordedSymbolOrException(org.antlr.v4.runtime.tree.ParseTree node) Safely retrieve the recorded symbol for a parse tree node with automatic validation.processBlockStatements(EK9Parser.InstructionBlockContext ctx, Function<EK9Parser.BlockStatementContext, List<IRInstr>> blockStmtGenerator) Process all block statements in an instruction block.protected voidvalidateNoPreFlowStatement(EK9Parser.PreFlowStatementContext preFlowCtx, String constructName) Validate that guards (preFlowStatement) are not present.protected voidvalidateStatementFormOnly(EK9Parser.ReturningParamContext returningParamCtx, String constructName) Validate that expression form (returningParam) is not used.
-
Field Details
-
stackContext
-
debugInfoCreator
-
instructionBuilder
-
typeNameOrException
-
-
Constructor Details
-
AbstractGenerator
AbstractGenerator(IRGenerationContext stackContext) Constructor accepting only IRGenerationContext - the single source of state.
-
-
Method Details
-
getRecordedSymbolOrException
Safely retrieve the recorded symbol for a parse tree node with automatic validation.This is the primary method for accessing symbols during IR generation. It ensures:
- Symbol was resolved by phases 1-6 (not null)
- Symbol has an associated type (required for IR generation)
When to use: ALWAYS use this instead of manually calling
stackContext.getParsedModule().getRecordedSymbol(node)to ensure proper validation.- Parameters:
node- The parse tree node to retrieve the symbol for- Returns:
- The validated symbol with guaranteed type information
- Throws:
IllegalArgumentException- if symbol is null or has no type (compiler bug)
-
createTempVariable
Create a temporary variable with associated debug info.This consolidates the common pattern of generating a temp name and wrapping it in VariableDetails. Use this when you already have debug info available (e.g., passed as a method parameter).
When to use: When debug info is already available. If you have a ParseTree context, use
createTempVariableFromContext(ParseTree)instead.Example:
// When debug info is passed in as parameter protected List<IRInstr> generateSomething(DebugInfo debugInfo) { final var tempDetails = createTempVariable(debugInfo); // ... use tempDetails }- Parameters:
debugInfo- The debug information for this variable- Returns:
- VariableDetails containing the temp variable name and debug info
-
createTempVariableFromContext
Create a temporary variable with debug info extracted from parse tree context.This consolidates the pattern of:
createDebugInfo(ctx) → generateTempName() → new VariableDetails(). Preferred method when you have a ParseTree context available.When to use: PREFERRED method when you have a ParseTree context (expression, statement, etc.). Automatically extracts source position for accurate debugging.
Example:
// Processing list elements for (final var exprCtx : listContext.expression()) { final var elementDetails = createTempVariableFromContext(exprCtx); // If you need the components separately: final var elementTemp = elementDetails.resultVariable(); final var elementDebugInfo = elementDetails.debugInfo(); }- Parameters:
ctx- The parse tree context to extract position from- Returns:
- VariableDetails containing the temp variable name and context-specific debug info
-
extractReturnType
protected ISymbol extractReturnType(org.antlr.v4.runtime.tree.ParseTree ctx, ISymbol fallbackSymbol) Extract return type from a CallSymbol's resolved method. Handles the pattern: CallSymbol → MethodSymbol/FunctionSymbol → returning type. Falls back to expression type if not a CallSymbol.- Parameters:
ctx- The parse tree context containing the expression symbolfallbackSymbol- Symbol to use if resolved method has no return type- Returns:
- The return type of the operation
-
processBlockStatements
protected List<IRInstr> processBlockStatements(EK9Parser.InstructionBlockContext ctx, Function<EK9Parser.BlockStatementContext, List<IRInstr>> blockStmtGenerator) Process all block statements in an instruction block. Consolidates the common pattern of iterating over block statements and delegating to a generator.- Parameters:
ctx- The instruction block contextblockStmtGenerator- The generator function for individual block statements- Returns:
- List of IR instructions from all block statements
-
validateNoPreFlowStatement
protected void validateNoPreFlowStatement(EK9Parser.PreFlowStatementContext preFlowCtx, String constructName) Validate that guards (preFlowStatement) are not present. Throws CompilerException if guards are used, as they're not yet implemented.- Parameters:
preFlowCtx- The preFlowStatement context to check (can be null)constructName- The name of the control flow construct for error message- Throws:
CompilerException- if guards are present
-
validateStatementFormOnly
protected void validateStatementFormOnly(EK9Parser.ReturningParamContext returningParamCtx, String constructName) Validate that expression form (returningParam) is not used. Throws CompilerException if returningParam is present, as expression forms are not yet implemented.- Parameters:
returningParamCtx- The returningParam context to check (can be null)constructName- The name of the control flow construct for error message- Throws:
CompilerException- if expression form is used
-