Compiler exceptions
This commit is contained in:
@@ -25,13 +25,12 @@ type
|
||||
TTypeChecker = class(TAstTransformer, IAstTypeChecker)
|
||||
private
|
||||
type
|
||||
// Helper to track types per scope during traversal (The "Scratchpad")
|
||||
TTypeContext = class
|
||||
private
|
||||
FParent: TTypeContext;
|
||||
FLayout: IScopeLayout;
|
||||
FSlotTypes: TArray<IStaticType>;
|
||||
FUpvalueTypes: TArray<IStaticType>; // Types of captured variables
|
||||
FUpvalueTypes: TArray<IStaticType>;
|
||||
public
|
||||
constructor Create(AParent: TTypeContext; ALayout: IScopeLayout; const AUpvalueTypes: TArray<IStaticType>);
|
||||
function LookupType(const Address: TResolvedAddress): IStaticType;
|
||||
@@ -41,12 +40,9 @@ type
|
||||
|
||||
private
|
||||
FCurrentContext: TTypeContext;
|
||||
|
||||
// Helper to recursively rebuild the context stack from the layout hierarchy
|
||||
function CreateContextChain(L: IScopeLayout): TTypeContext;
|
||||
|
||||
protected
|
||||
// Override all visit methods to perform type checking
|
||||
function VisitIdentifier(const Node: IIdentifierNode): IAstNode; override;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode; override;
|
||||
function VisitAssignment(const Node: IAssignmentNode): IAstNode; override;
|
||||
@@ -64,7 +60,6 @@ type
|
||||
function VisitRecurNode(const Node: IRecurNode): IAstNode; override;
|
||||
function VisitNop(const Node: INopNode): IAstNode; override;
|
||||
|
||||
// Base cases (types are now set here)
|
||||
function VisitConstant(const Node: IConstantNode): IAstNode; override;
|
||||
function VisitKeyword(const Node: IKeywordNode): IAstNode; override;
|
||||
|
||||
@@ -92,7 +87,6 @@ begin
|
||||
FLayout := ALayout;
|
||||
FUpvalueTypes := AUpvalueTypes;
|
||||
|
||||
// Initialize slot types with Unknown
|
||||
if Assigned(FLayout) then
|
||||
begin
|
||||
SetLength(FSlotTypes, FLayout.SlotCount);
|
||||
@@ -125,7 +119,6 @@ begin
|
||||
end;
|
||||
akUpvalue:
|
||||
begin
|
||||
// Look up type in our local upvalue type cache
|
||||
if (Address.SlotIndex >= 0) and (Address.SlotIndex < Length(FUpvalueTypes)) then
|
||||
Result := FUpvalueTypes[Address.SlotIndex]
|
||||
else
|
||||
@@ -151,30 +144,20 @@ begin
|
||||
if L = nil then
|
||||
exit(nil);
|
||||
|
||||
// Recursively build parent context
|
||||
p := CreateContextChain(L.Parent);
|
||||
|
||||
// Create context for current layout level
|
||||
// Note: We don't know UpvalueTypes for these static/parent layouts here, so [] is passed.
|
||||
// Also: Slot types will be initialized to Unknown.
|
||||
Result := TTypeContext.Create(p, L, []);
|
||||
end;
|
||||
|
||||
constructor TTypeChecker.Create(const RootLayout: IScopeLayout);
|
||||
begin
|
||||
inherited Create;
|
||||
// Build the full context chain based on the Layout's parent hierarchy
|
||||
// This ensures that ScopeDepth lookups can traverse up to the root.
|
||||
FCurrentContext := CreateContextChain(RootLayout);
|
||||
|
||||
// Fallback if RootLayout is nil (should not happen in valid pipeline)
|
||||
if FCurrentContext = nil then
|
||||
FCurrentContext := TTypeContext.Create(nil, nil, []);
|
||||
end;
|
||||
|
||||
destructor TTypeChecker.Destroy;
|
||||
begin
|
||||
// Cleanup context stack
|
||||
while Assigned(FCurrentContext) do
|
||||
begin
|
||||
var temp := FCurrentContext;
|
||||
@@ -192,7 +175,6 @@ end;
|
||||
|
||||
function TTypeChecker.Execute(const RootNode: IAstNode; const Layout: IScopeLayout): IAstNode;
|
||||
begin
|
||||
// Note: Layout passed here matches what was passed to Create/Constructor (via recursed ContextChain)
|
||||
Result := Accept(RootNode);
|
||||
if not Assigned(Result) then
|
||||
Result := TAst.Block([]);
|
||||
@@ -216,10 +198,7 @@ var
|
||||
adr: TResolvedAddress;
|
||||
begin
|
||||
adr := Node.Address;
|
||||
// Lookup type in our scratchpad context using the address resolved by Binder
|
||||
typ := FCurrentContext.LookupType(adr);
|
||||
|
||||
// Create a new node with the inferred type
|
||||
Result := TAst.Identifier(Node.Name, adr, typ);
|
||||
end;
|
||||
|
||||
@@ -247,7 +226,6 @@ begin
|
||||
adr := Node.Target.AsIdentifier.Address;
|
||||
initType := TTypes.Unknown;
|
||||
|
||||
// Recursive lambda bootstrap logic
|
||||
placeholderType := nil;
|
||||
if (Node.Initializer <> nil) and (Node.Initializer.Kind = akLambdaExpression) then
|
||||
begin
|
||||
@@ -258,8 +236,6 @@ begin
|
||||
paramTypes[i] := TTypes.Unknown;
|
||||
|
||||
placeholderType := TTypes.CreateMethod(paramTypes, TTypes.Unknown);
|
||||
|
||||
// Update Context (Scratchpad)
|
||||
FCurrentContext.SetType(adr.SlotIndex, placeholderType);
|
||||
initType := placeholderType;
|
||||
end;
|
||||
@@ -274,12 +250,10 @@ begin
|
||||
else if not Assigned(placeholderType) then
|
||||
initType := TTypes.Unknown;
|
||||
|
||||
// Update Context with final type
|
||||
if initType.Kind <> stUnknown then
|
||||
FCurrentContext.SetType(adr.SlotIndex, initType);
|
||||
|
||||
newIdent := TAst.Identifier(Node.Target.AsIdentifier.Name, adr, initType);
|
||||
|
||||
Result := TAst.VarDecl(newIdent.AsIdentifier, newInitializer, initType, Node.IsBoxed);
|
||||
end;
|
||||
|
||||
@@ -296,7 +270,6 @@ begin
|
||||
targetType := newIdent.AsTypedNode.StaticType;
|
||||
adr := newIdent.AsIdentifier.Address;
|
||||
|
||||
// Recursive lambda assignment check
|
||||
placeholderType := nil;
|
||||
if (Node.Value <> nil) and (Node.Value.Kind = akLambdaExpression) then
|
||||
begin
|
||||
@@ -344,28 +317,18 @@ var
|
||||
newBody: IAstNode;
|
||||
bodyType, methodType: IStaticType;
|
||||
paramTypes: TArray<IStaticType>;
|
||||
|
||||
// Upvalue Type Resolution
|
||||
upvalueTypes: TArray<IStaticType>;
|
||||
upvalueAddrs: TArray<TResolvedAddress>;
|
||||
|
||||
i: Integer;
|
||||
finalDescriptor: IScopeDescriptor;
|
||||
begin
|
||||
// 1. Resolve Upvalue Types *in the current (parent) context*
|
||||
upvalueAddrs := Node.Upvalues;
|
||||
SetLength(upvalueTypes, Length(upvalueAddrs));
|
||||
for i := 0 to High(upvalueAddrs) do
|
||||
begin
|
||||
// We look up the physical address (from Binder) in the current context chain
|
||||
upvalueTypes[i] := FCurrentContext.LookupType(upvalueAddrs[i]);
|
||||
end;
|
||||
|
||||
// 2. Create new TypeContext for this lambda scope, PASSING the upvalue types
|
||||
// We use the layout from the Binder-Result-Node
|
||||
FCurrentContext := TTypeContext.Create(FCurrentContext, Node.Layout, upvalueTypes);
|
||||
try
|
||||
// 3. Set parameter types in the context
|
||||
SetLength(newParams, Length(Node.Parameters));
|
||||
SetLength(paramTypes, Length(Node.Parameters));
|
||||
|
||||
@@ -373,37 +336,22 @@ begin
|
||||
begin
|
||||
var paramIdent := Node.Parameters[i];
|
||||
var paramAdr := paramIdent.Address;
|
||||
|
||||
// Here we could infer types if we had type annotations. For now, parameters are Unknown.
|
||||
paramTypes[i] := TTypes.Unknown;
|
||||
|
||||
// Update context so body can resolve params
|
||||
FCurrentContext.SetType(paramAdr.SlotIndex, paramTypes[i]);
|
||||
|
||||
newParams[i] := TAst.Identifier(paramIdent.Name, paramAdr, paramTypes[i]);
|
||||
end;
|
||||
|
||||
// 4. Visit body
|
||||
newBody := Accept(Node.Body);
|
||||
bodyType := newBody.AsTypedNode.StaticType;
|
||||
|
||||
// 5. Create method type
|
||||
methodType := TTypes.CreateMethod(paramTypes, bodyType);
|
||||
|
||||
// 6. Update <self> type in context (Slot 0)
|
||||
FCurrentContext.SetType(0, methodType);
|
||||
|
||||
// 7. FINALIZE: Bake the Descriptor
|
||||
finalDescriptor := TScope.CreateDescriptor(Node.Layout, FCurrentContext.Types);
|
||||
|
||||
finally
|
||||
// 8. Pop Context
|
||||
var temp := FCurrentContext;
|
||||
FCurrentContext := FCurrentContext.FParent;
|
||||
temp.Free;
|
||||
end;
|
||||
|
||||
// 9. Create new node with the Descriptor attached!
|
||||
Result :=
|
||||
TAst.LambdaExpr(newParams, newBody, Node.Layout, finalDescriptor, Node.Upvalues, Node.HasNestedLambdas, Node.IsPure, methodType);
|
||||
end;
|
||||
@@ -509,7 +457,6 @@ begin
|
||||
newElse := Accept(Node.ElseBranch);
|
||||
|
||||
conditionType := newCond.AsTypedNode.StaticType;
|
||||
// Ordinal and Boolean are valid for if-conditions
|
||||
if (conditionType.Kind <> stUnknown)
|
||||
and not TTypeRules.CanAssign(TTypes.Ordinal, conditionType)
|
||||
and not TTypeRules.CanAssign(TTypes.Boolean, conditionType) then
|
||||
@@ -520,12 +467,9 @@ begin
|
||||
if newElse <> nil then newElse.AsTypedNode.StaticType
|
||||
else TTypes.Void;
|
||||
|
||||
try
|
||||
resultType := TTypeRules.Promote(thenType, elseType);
|
||||
except
|
||||
on E: Exception do // Catch base exception (ETypeException from Myc.Ast.Types)
|
||||
raise ETypeCheckException.Create(E.Message);
|
||||
end;
|
||||
resultType := TTypeRules.Promote(thenType, elseType);
|
||||
if resultType = nil then
|
||||
raise ETypeCheckException.CreateFmt('Cannot promote types %s and %s in If-Expression', [thenType.ToString, elseType.ToString]);
|
||||
|
||||
Result := TAst.IfExpr(newCond, newThen, newElse, resultType);
|
||||
end;
|
||||
@@ -548,12 +492,9 @@ begin
|
||||
thenType := newThen.AsTypedNode.StaticType;
|
||||
elseType := newElse.AsTypedNode.StaticType;
|
||||
|
||||
try
|
||||
resultType := TTypeRules.Promote(thenType, elseType);
|
||||
except
|
||||
on E: Exception do
|
||||
raise ETypeCheckException.Create(E.Message);
|
||||
end;
|
||||
resultType := TTypeRules.Promote(thenType, elseType);
|
||||
if resultType = nil then
|
||||
raise ETypeCheckException.CreateFmt('Cannot promote types %s and %s in Ternary-Expression', [thenType.ToString, elseType.ToString]);
|
||||
|
||||
Result := TAst.TernaryExpr(newCond, newThen, newElse, resultType);
|
||||
end;
|
||||
@@ -698,10 +639,12 @@ var
|
||||
elemType: IStaticType;
|
||||
begin
|
||||
try
|
||||
// TScalar.StringToKind might throw EConvertError or generic Exception if string is invalid
|
||||
elemType := TTypes.FromScalarKind(TScalar.StringToKind(Node.Definition));
|
||||
except
|
||||
on E: Exception do
|
||||
elemType := TTypes.Unknown;
|
||||
// Instead of silently using Unknown, we now raise a proper compiler error
|
||||
raise ETypeCheckException.CreateFmt('Invalid type definition "%s" in new-series.', [Node.Definition]);
|
||||
end;
|
||||
|
||||
Result := TAst.CreateSeries(Node.Definition, TTypes.CreateSeries(elemType));
|
||||
|
||||
Reference in New Issue
Block a user