Ast ternary expr replaced by cond expr

This commit is contained in:
Michael Schimmel
2025-12-07 12:06:29 +01:00
parent 91c4d57aaf
commit 1d13d0cdaa
15 changed files with 449 additions and 180 deletions
+72 -28
View File
@@ -50,7 +50,7 @@ type
function VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; override;
function VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode; override;
function VisitIfExpression(const Node: IIfExpressionNode): IAstNode; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): IAstNode; override;
function VisitCondExpression(const Node: ICondExpressionNode): IAstNode; override; // Replaced Ternary
function VisitMemberAccess(const Node: IMemberAccessNode): IAstNode; override;
function VisitIndexer(const Node: IIndexerNode): IAstNode; override;
function VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode; override;
@@ -221,7 +221,7 @@ begin
for i := 0 to Node.Arguments.Count - 1 do
newArgs[i] := Accept(Node.Arguments[i]);
// FIX: Wrap in List
// Wrap in List
var argList := TArgumentList.Create(newArgs, Node.Arguments.Identity);
Result := TAst.Recur(Node.Identity, argList, TTypes.Void);
end;
@@ -395,7 +395,7 @@ begin
temp.Free;
end;
// FIX: Wrap in List
// Wrap in List
var paramList := TParameterList.Create(newParams, Node.Parameters.Identity);
Result :=
@@ -493,7 +493,7 @@ begin
retType := TTypes.Unknown;
end;
// FIX: Wrap in List
// Wrap in List
var argList := TArgumentList.Create(newArgs, Node.Arguments.Identity);
Result := TAst.FunctionCall(Node.Identity, newCallee, argList, retType, Node.IsTailCall, nil, False);
@@ -514,7 +514,7 @@ begin
else
blockType := TTypes.Void;
// FIX: Wrap in List
// Wrap in List
var exprList := TExpressionList.Create(newExprs, Node.Expressions.Identity);
Result := TAst.Block(Node.Identity, exprList, blockType);
end;
@@ -553,36 +553,80 @@ begin
Result := TAst.IfExpr(Node.Identity, newCond, newThen, newElse, resultType);
end;
function TTypeChecker.VisitTernaryExpression(const Node: ITernaryExpressionNode): IAstNode;
function TTypeChecker.VisitCondExpression(const Node: ICondExpressionNode): IAstNode;
var
conditionType, thenType, elseType, resultType: IStaticType;
newCond, newThen, newElse: IAstNode;
i: Integer;
newPairs: TArray<TCondPair>;
newElse: IAstNode;
condType, branchType, resultType: IStaticType;
begin
newCond := Accept(Node.Condition);
newThen := Accept(Node.ThenBranch);
SetLength(newPairs, Length(Node.Pairs));
resultType := nil; // Start with nothing
for i := 0 to High(Node.Pairs) do
begin
// 1. Visit Condition
var newCond := Accept(Node.Pairs[i].Condition);
condType := newCond.AsTypedNode.StaticType;
if (condType.Kind <> stUnknown)
and not TTypeRules.CanAssign(TTypes.Ordinal, condType)
and not TTypeRules.CanAssign(TTypes.Boolean, condType) then
begin
if Assigned(FLog) then
FLog.AddError(Format('Cond condition must be Boolean or Ordinal, but got %s', [condType.ToString]), Node);
end;
// 2. Visit Branch
var newBranch := Accept(Node.Pairs[i].Branch);
branchType := newBranch.AsTypedNode.StaticType;
newPairs[i] := TCondPair.Create(newCond, newBranch);
// 3. Promote Result Type
if resultType = nil then
resultType := branchType
else
begin
var promoted := TTypeRules.Promote(resultType, branchType);
if promoted = nil then
begin
if Assigned(FLog) then
FLog.AddError(
Format('Incompatible types in Cond branches: %s and %s', [resultType.ToString, branchType.ToString]),
Node
);
resultType := TTypes.Unknown;
end
else
resultType := promoted;
end;
end;
// 4. Visit Else
newElse := Accept(Node.ElseBranch);
// Else branch is mandatory in our new AST structure (can be Nop/Void, but is present)
var elseType := newElse.AsTypedNode.StaticType;
conditionType := newCond.AsTypedNode.StaticType;
if (conditionType.Kind <> stUnknown)
and not TTypeRules.CanAssign(TTypes.Ordinal, conditionType)
and not TTypeRules.CanAssign(TTypes.Boolean, conditionType) then
begin
if Assigned(FLog) then
FLog.AddError(Format('Ternary condition must be Boolean or Ordinal, but got %s', [conditionType.ToString]), Node);
end;
thenType := newThen.AsTypedNode.StaticType;
elseType := newElse.AsTypedNode.StaticType;
resultType := TTypeRules.Promote(thenType, elseType);
if resultType = nil then
resultType := elseType
else
begin
if Assigned(FLog) then
FLog.AddError(Format('Cannot promote types %s and %s in Ternary-Expression', [thenType.ToString, elseType.ToString]), Node);
resultType := TTypes.Unknown;
var promoted := TTypeRules.Promote(resultType, elseType);
if promoted = nil then
begin
if Assigned(FLog) then
FLog.AddError(
Format('Incompatible types in Cond branches (Else): %s and %s', [resultType.ToString, elseType.ToString]),
Node
);
resultType := TTypes.Unknown;
end
else
resultType := promoted;
end;
Result := TAst.TernaryExpr(Node.Identity, newCond, newThen, newElse, resultType);
Result := TAst.CondExpr(Node.Identity, newPairs, newElse, resultType);
end;
function TTypeChecker.VisitMemberAccess(const Node: IMemberAccessNode): IAstNode;
@@ -726,7 +770,7 @@ begin
scalarDefFields[i] := TScalarRecordField.Create(newFields[i].Key.Value, scalarKind);
end;
// FIX: Wrap in List
// Wrap in List
var fieldList := TRecordFieldList.Create(newFields, Node.Fields.Identity);
if allScalar then