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
File diff suppressed because one or more lines are too long
+12 -3
View File
@@ -23,7 +23,7 @@ type
function VisitConstant(const Node: IConstantNode): Boolean; override;
function VisitKeyword(const Node: IKeywordNode): Boolean; override;
function VisitIfExpression(const Node: IIfExpressionNode): Boolean; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): Boolean; override;
function VisitCondExpression(const Node: ICondExpressionNode): Boolean; override; // Replaces Ternary
function VisitBlockExpression(const Node: IBlockExpressionNode): Boolean; override;
function VisitRecordLiteral(const Node: IRecordLiteralNode): Boolean; override;
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): Boolean; override;
@@ -184,9 +184,18 @@ begin
Result := Accept(Node.Condition) and Accept(Node.ThenBranch) and Accept(Node.ElseBranch);
end;
function TPurityAnalyzer.VisitTernaryExpression(const Node: ITernaryExpressionNode): Boolean;
function TPurityAnalyzer.VisitCondExpression(const Node: ICondExpressionNode): Boolean;
var
pair: TCondPair;
begin
Result := Accept(Node.Condition) and Accept(Node.ThenBranch) and Accept(Node.ElseBranch);
// All conditions and all branches must be pure
for pair in Node.Pairs do
begin
if not (Accept(pair.Condition) and Accept(pair.Branch)) then
Exit(False);
end;
// And the Else branch
Result := Accept(Node.ElseBranch);
end;
function TPurityAnalyzer.VisitBlockExpression(const Node: IBlockExpressionNode): Boolean;
+30 -11
View File
@@ -33,7 +33,7 @@ type
// Overrides for TCO propagation
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; // Replaces Ternary
function VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; override;
function VisitRecurNode(const Node: IRecurNode): IAstNode; override;
function VisitMacroExpansionNode(const Node: IMacroExpansionNode): IAstNode; override;
@@ -160,27 +160,46 @@ begin
Result := TAst.IfExpr(Node.Identity, newCond, newThen, newElse, Node.StaticType);
end;
function TAstTCO.VisitTernaryExpression(const Node: ITernaryExpressionNode): IAstNode;
function TAstTCO.VisitCondExpression(const Node: ICondExpressionNode): IAstNode;
var
isContextTail: Boolean;
newCond, newThen, newElse: IAstNode;
hasChanged: Boolean;
i: Integer;
newPairs: TArray<TCondPair>;
newElse: IAstNode;
newCond, newBranch: IAstNode;
begin
isContextTail := FIsTailStack.Peek;
hasChanged := False;
SetLength(newPairs, Length(Node.Pairs));
// Condition is never in tail position
FNextIsTail := False;
newCond := Accept(Node.Condition);
for i := 0 to High(Node.Pairs) do
begin
// 1. Condition is never in tail position
FNextIsTail := False;
newCond := Accept(Node.Pairs[i].Condition);
// Then/Else branches ARE in tail position if the TernaryExpr is
// 2. Branch IS in tail position (if CondExpr is)
FNextIsTail := isContextTail;
newBranch := Accept(Node.Pairs[i].Branch);
newPairs[i] := TCondPair.Create(newCond, newBranch);
if (newCond <> Node.Pairs[i].Condition) or (newBranch <> Node.Pairs[i].Branch) then
hasChanged := True;
end;
// 3. Else Branch IS in tail position
FNextIsTail := isContextTail;
newThen := Accept(Node.ThenBranch);
newElse := Accept(Node.ElseBranch);
if (newCond = Node.Condition) and (newThen = Node.ThenBranch) and (newElse = Node.ElseBranch) then
if newElse <> Node.ElseBranch then
hasChanged := True;
if not hasChanged then
Result := Node
else
// CoW: Reuse Identity
Result := TAst.TernaryExpr(Node.Identity, newCond, newThen, newElse, Node.StaticType);
Result := TAst.CondExpr(Node.Identity, newPairs, newElse, Node.StaticType);
end;
function TAstTCO.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode;
+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
+7 -4
View File
@@ -37,7 +37,7 @@ type
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
function VisitKeyword(const Node: IKeywordNode): TDataValue; override;
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override;
function VisitCondExpression(const Node: ICondExpressionNode): TDataValue; override; // Replaces Ternary
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
@@ -250,12 +250,15 @@ begin
AppendLine(Format('} -> %s', [Result.ToString]));
end;
function TDebugEvaluatorVisitor.VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
function TDebugEvaluatorVisitor.VisitCondExpression(const Node: ICondExpressionNode): TDataValue;
begin
AppendLine('TernaryExpr {');
AppendLine(Format('CondExpr (%d pairs) {', [Length(Node.Pairs)]));
Indent;
try
Result := inherited VisitTernaryExpression(Node);
// We just call inherited, which does the logic.
// We don't log every branch check here to avoid spamming output,
// but the recursive evaluation of conditions will show up in the log naturally.
Result := inherited VisitCondExpression(Node);
finally
Unindent;
end;
+15 -7
View File
@@ -34,7 +34,7 @@ type
function VisitIdentifier(const Node: IIdentifierNode): TVoid; override;
function VisitKeyword(const Node: IKeywordNode): TVoid; override;
function VisitIfExpression(const Node: IIfExpressionNode): TVoid; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TVoid; override;
function VisitCondExpression(const Node: ICondExpressionNode): TVoid; override; // Replaced Ternary
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TVoid; override;
function VisitFunctionCall(const Node: IFunctionCallNode): TVoid; override;
function VisitMacroExpansionNode(const Node: IMacroExpansionNode): TVoid; override;
@@ -187,14 +187,22 @@ begin
Unindent;
end;
function TAstDumper.VisitTernaryExpression(const Node: ITernaryExpressionNode): TVoid;
function TAstDumper.VisitCondExpression(const Node: ICondExpressionNode): TVoid;
var
i: Integer;
begin
Log('TernaryExpression', Node);
LogFmt('CondExpression (%d pairs)', [Length(Node.Pairs)], Node);
Indent;
Log('Condition:');
Node.Condition.Accept(Self);
Log('Then:');
Node.ThenBranch.Accept(Self);
for i := 0 to High(Node.Pairs) do
begin
LogFmt('Pair %d:', [i]);
Indent;
Log('Condition:');
Node.Pairs[i].Condition.Accept(Self);
Log('Branch:');
Node.Pairs[i].Branch.Accept(Self);
Unindent;
end;
Log('Else:');
Node.ElseBranch.Accept(Self);
Unindent;
+14 -6
View File
@@ -34,7 +34,7 @@ type
function VisitRecordField(const Node: IRecordFieldNode): TDataValue; virtual;
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; virtual;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; virtual;
function VisitCondExpression(const Node: ICondExpressionNode): TDataValue; virtual; // Replaces Ternary
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; virtual;
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; virtual;
function VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; virtual;
@@ -590,12 +590,20 @@ begin
Result := TDataValue.Void;
end;
function TEvaluatorVisitor.VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
function TEvaluatorVisitor.VisitCondExpression(const Node: ICondExpressionNode): TDataValue;
var
pair: TCondPair;
begin
if IsTruthy(Node.Condition.Accept(Self)) then
Result := Node.ThenBranch.Accept(Self)
else
Result := Node.ElseBranch.Accept(Self);
for pair in Node.Pairs do
begin
if IsTruthy(pair.Condition.Accept(Self)) then
begin
Result := pair.Branch.Accept(Self);
Exit;
end;
end;
// Else branch is mandatory in AST (though can be Nop/Void in source if omitted and normalized)
Result := Node.ElseBranch.Accept(Self);
end;
function TEvaluatorVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
+57 -19
View File
@@ -31,7 +31,8 @@ type
function JsonToIdentifierNode(const AObj: TJSONObject): IIdentifierNode;
function JsonToKeywordNode(const AObj: TJSONObject): IKeywordNode;
function JsonToIfExprNode(const AObj: TJSONObject): IIfExpressionNode;
function JsonToTernaryExprNode(const AObj: TJSONObject): ITernaryExpressionNode;
function JsonToCondExprNode(const AObj: TJSONObject): ICondExpressionNode;
function JsonToTernaryExprNode(const AObj: TJSONObject): IAstNode; // Backward Compatibility
function JsonToLambdaExprNode(const AObj: TJSONObject): ILambdaExpressionNode;
function JsonToMacroDefNode(const AObj: TJSONObject): IMacroDefinitionNode;
function JsonToQuasiquoteNode(const AObj: TJSONObject): IQuasiquoteNode;
@@ -44,7 +45,7 @@ type
function JsonToVarDeclNode(const AObj: TJSONObject): IVariableDeclarationNode;
function JsonToAssignmentNode(const AObj: TJSONObject): IAssignmentNode;
function JsonToIndexerNode(const AObj: TJSONObject): IIndexerNode;
function JsonToMemberAccessNode(const AObj: TJSONObject): IMemberAccessNode; // <--- KORRIGIERT
function JsonToMemberAccessNode(const AObj: TJSONObject): IMemberAccessNode;
function JsonToRecordLiteralNode(const AObj: TJSONObject): IRecordLiteralNode;
function JsonToCreateSeriesNode(const AObj: TJSONObject): ICreateSeriesNode;
function JsonToAddSeriesItemNode(const AObj: TJSONObject): IAddSeriesItemNode;
@@ -57,7 +58,7 @@ type
function VisitIdentifier(const Node: IIdentifierNode): TJSONObject; override;
function VisitKeyword(const Node: IKeywordNode): TJSONObject; override;
// List Visitors (stubbed mostly, as parents handle array generation for JSON structure)
// List Visitors
function VisitParameterList(const Node: IParameterList): TJSONObject; override;
function VisitArgumentList(const Node: IArgumentList): TJSONObject; override;
function VisitExpressionList(const Node: IExpressionList): TJSONObject; override;
@@ -65,7 +66,7 @@ type
function VisitRecordField(const Node: IRecordFieldNode): TJSONObject; override;
function VisitIfExpression(const Node: IIfExpressionNode): TJSONObject; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TJSONObject; override;
function VisitCondExpression(const Node: ICondExpressionNode): TJSONObject; override;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TJSONObject; override;
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TJSONObject; override;
function VisitQuasiquote(const Node: IQuasiquoteNode): TJSONObject; override;
@@ -186,19 +187,32 @@ begin
Result.AddPair('ElseBranch', TJSONNull.Create);
end;
function TJsonAstConverter.VisitTernaryExpression(const Node: ITernaryExpressionNode): TJSONObject;
function TJsonAstConverter.VisitCondExpression(const Node: ICondExpressionNode): TJSONObject;
var
condObj, thenObj, elseObj: TJSONObject;
pairsArray: TJSONArray;
pairObj: TJSONObject;
elseObj: TJSONObject;
i: Integer;
begin
condObj := Accept(Node.Condition);
thenObj := Accept(Node.ThenBranch);
elseObj := Accept(Node.ElseBranch);
pairsArray := TJSONArray.Create;
for i := 0 to High(Node.Pairs) do
begin
pairObj := TJSONObject.Create;
pairObj.AddPair('Condition', Accept(Node.Pairs[i].Condition));
pairObj.AddPair('Branch', Accept(Node.Pairs[i].Branch));
pairsArray.Add(pairObj);
end;
elseObj := Accept(Node.ElseBranch); // Accept handles nil
Result := TJSONObject.Create;
Result.AddPair('NodeType', TJSONString.Create('TernaryExpr'));
Result.AddPair('Condition', condObj);
Result.AddPair('ThenBranch', thenObj);
Result.AddPair('ElseBranch', elseObj);
Result.AddPair('NodeType', TJSONString.Create('CondExpr'));
Result.AddPair('Pairs', pairsArray);
if Assigned(elseObj) then
Result.AddPair('ElseBranch', elseObj)
else
Result.AddPair('ElseBranch', TJSONNull.Create);
end;
function TJsonAstConverter.VisitLambdaExpression(const Node: ILambdaExpressionNode): TJSONObject;
@@ -451,10 +465,6 @@ begin
end;
// --- List Visitors (Placeholder return) ---
// Since we iterate manually in parent nodes to form JSON Arrays, these are technically not used
// by the current logic, but required by the interface.
// Note: If we wanted strict visitor compliance, VisitFunctionCall would call Accept(List),
// which would return TJSONObject wrapping the array. We skip that level of nesting here.
function TJsonAstConverter.VisitParameterList(const Node: IParameterList): TJSONObject;
begin
@@ -544,13 +554,39 @@ begin
Result := TAst.IfExpr(condNode, thenNode, elseNode);
end;
function TJsonAstConverter.JsonToTernaryExprNode(const AObj: TJSONObject): ITernaryExpressionNode;
function TJsonAstConverter.JsonToCondExprNode(const AObj: TJSONObject): ICondExpressionNode;
var
pairsArray: TJSONArray;
pairs: TArray<TCondPair>;
elseNode: IAstNode;
i: Integer;
pairObj: TJSONObject;
begin
pairsArray := AObj.GetValue<TJSONArray>('Pairs');
SetLength(pairs, pairsArray.Count);
for i := 0 to pairsArray.Count - 1 do
begin
pairObj := pairsArray.Items[i] as TJSONObject;
pairs[i] := TCondPair.Create(JsonToNode(pairObj.GetValue('Condition')), JsonToNode(pairObj.GetValue('Branch')));
end;
if not (AObj.GetValue('ElseBranch') is TJSONNull) then
elseNode := JsonToNode(AObj.GetValue('ElseBranch'))
else
elseNode := nil;
Result := TAst.CondExpr(pairs, elseNode);
end;
function TJsonAstConverter.JsonToTernaryExprNode(const AObj: TJSONObject): IAstNode;
var
condNode, thenNode, elseNode: IAstNode;
begin
condNode := JsonToNode(AObj.GetValue('Condition'));
thenNode := JsonToNode(AObj.GetValue('ThenBranch'));
elseNode := JsonToNode(AObj.GetValue('ElseBranch'));
// Map to CondExpr using the helper in TAst
Result := TAst.TernaryExpr(condNode, thenNode, elseNode);
end;
@@ -775,8 +811,10 @@ begin
Result := JsonToKeywordNode(obj)
else if nodeType = 'IfExpr' then
Result := JsonToIfExprNode(obj)
else if nodeType = 'CondExpr' then
Result := JsonToCondExprNode(obj)
else if nodeType = 'TernaryExpr' then
Result := JsonToTernaryExprNode(obj)
Result := JsonToTernaryExprNode(obj) // Backward Compatibility
else if nodeType = 'LambdaExpr' then
Result := JsonToLambdaExprNode(obj)
else if nodeType = 'MacroDef' then
+46 -34
View File
@@ -91,7 +91,7 @@ type
// Control Flow & Structure
IIfExpressionNode = interface;
ITernaryExpressionNode = interface;
ICondExpressionNode = interface;
ILambdaExpressionNode = interface;
IFunctionCallNode = interface;
IMacroExpansionNode = interface;
@@ -123,7 +123,7 @@ type
akRecordFieldList,
akRecordField,
akIfExpression,
akTernaryExpression,
akCondExpression,
akLambdaExpression,
akFunctionCall,
akMacroExpansion,
@@ -149,6 +149,13 @@ type
function ToString: string;
end;
// Represents a single branch in a Cond expression (Condition -> Branch)
TCondPair = record
Condition: IAstNode;
Branch: IAstNode;
constructor Create(const ACondition, ABranch: IAstNode);
end;
// --- Base Interfaces ---
IAstNode = interface
@@ -173,7 +180,7 @@ type
function AsRecordField: IRecordFieldNode;
function AsIfExpression: IIfExpressionNode;
function AsTernaryExpression: ITernaryExpressionNode;
function AsCondExpression: ICondExpressionNode;
function AsLambdaExpression: ILambdaExpressionNode;
function AsFunctionCall: IFunctionCallNode;
function AsMacroExpansion: IMacroExpansionNode;
@@ -279,14 +286,12 @@ type
property ElseBranch: IAstNode read GetElseBranch;
end;
ITernaryExpressionNode = interface(IAstTypedNode)
ICondExpressionNode = interface(IAstTypedNode)
{$region 'private'}
function GetCondition: IAstNode;
function GetThenBranch: IAstNode;
function GetPairs: TArray<TCondPair>;
function GetElseBranch: IAstNode;
{$endregion}
property Condition: IAstNode read GetCondition;
property ThenBranch: IAstNode read GetThenBranch;
property Pairs: TArray<TCondPair> read GetPairs;
property ElseBranch: IAstNode read GetElseBranch;
end;
@@ -467,7 +472,7 @@ type
function VisitRecordField(const Node: IRecordFieldNode): TDataValue;
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
function VisitCondExpression(const Node: ICondExpressionNode): TDataValue;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
function VisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue;
@@ -515,7 +520,7 @@ type
function AsRecordField: IRecordFieldNode; virtual;
function AsIfExpression: IIfExpressionNode; virtual;
function AsTernaryExpression: ITernaryExpressionNode; virtual;
function AsCondExpression: ICondExpressionNode; virtual;
function AsLambdaExpression: ILambdaExpressionNode; virtual;
function AsFunctionCall: IFunctionCallNode; virtual;
function AsMacroExpansion: IMacroExpansionNode; virtual;
@@ -694,21 +699,22 @@ type
function AsIfExpression: IIfExpressionNode; override;
end;
TTernaryExpressionNode = class(TAstTypedNode, ITernaryExpressionNode)
TCondExpressionNode = class(TAstTypedNode, ICondExpressionNode)
private
FCondition, FThenBranch, FElseBranch: IAstNode;
function GetCondition: IAstNode;
function GetThenBranch: IAstNode;
FPairs: TArray<TCondPair>;
FElseBranch: IAstNode;
function GetPairs: TArray<TCondPair>;
function GetElseBranch: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(
const ACondition, AThenBranch, AElseBranch: IAstNode;
const APairs: TArray<TCondPair>;
const AElseBranch: IAstNode;
const AStaticType: IStaticType;
const AIdentity: IAstIdentity
);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsTernaryExpression: ITernaryExpressionNode; override;
function AsCondExpression: ICondExpressionNode; override;
end;
TLambdaExpressionNode = class(TAstTypedNode, ILambdaExpressionNode, IFunctionDefinition)
@@ -1004,6 +1010,14 @@ begin
Result := Result.Substring(2);
end;
{ TCondPair }
constructor TCondPair.Create(const ACondition, ABranch: IAstNode);
begin
Condition := ACondition;
Branch := ABranch;
end;
{ TCompilerError }
constructor TCompilerError.Create(ALevel: TCompilerErrorLevel; const AMessage: string; const ANode: IAstNode);
@@ -1174,7 +1188,7 @@ function TAstNode.AsIfExpression: IIfExpressionNode;
begin
Result := nil;
end;
function TAstNode.AsTernaryExpression: ITernaryExpressionNode;
function TAstNode.AsCondExpression: ICondExpressionNode;
begin
Result := nil;
end;
@@ -1567,45 +1581,43 @@ begin
Result := akIfExpression;
end;
{ TTernaryExpressionNode }
{ TCondExpressionNode }
constructor TTernaryExpressionNode.Create(
const ACondition, AThenBranch, AElseBranch: IAstNode;
constructor TCondExpressionNode.Create(
const APairs: TArray<TCondPair>;
const AElseBranch: IAstNode;
const AStaticType: IStaticType;
const AIdentity: IAstIdentity
);
begin
inherited Create(AStaticType, AIdentity);
FCondition := ACondition;
FThenBranch := AThenBranch;
FPairs := APairs;
FElseBranch := AElseBranch;
end;
function TTernaryExpressionNode.Accept(const Visitor: IAstVisitor): TDataValue;
function TCondExpressionNode.Accept(const Visitor: IAstVisitor): TDataValue;
begin
Result := Visitor.VisitTernaryExpression(Self);
Result := Visitor.VisitCondExpression(Self);
end;
function TTernaryExpressionNode.AsTernaryExpression: ITernaryExpressionNode;
function TCondExpressionNode.AsCondExpression: ICondExpressionNode;
begin
Result := Self;
end;
function TTernaryExpressionNode.GetCondition: IAstNode;
function TCondExpressionNode.GetPairs: TArray<TCondPair>;
begin
Result := FCondition;
Result := FPairs;
end;
function TTernaryExpressionNode.GetThenBranch: IAstNode;
begin
Result := FThenBranch;
end;
function TTernaryExpressionNode.GetElseBranch: IAstNode;
function TCondExpressionNode.GetElseBranch: IAstNode;
begin
Result := FElseBranch;
end;
function TTernaryExpressionNode.GetKind: TAstNodeKind;
function TCondExpressionNode.GetKind: TAstNodeKind;
begin
Result := akTernaryExpression;
Result := akCondExpression;
end;
{ TLambdaExpressionNode }
+28 -8
View File
@@ -38,7 +38,7 @@ type
// --- Structural Nodes (Replace Logic) ---
function VisitIfExpression(const Node: IIfExpressionNode): IAstNode; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): IAstNode; override;
function VisitCondExpression(const Node: ICondExpressionNode): IAstNode; override; // Replaces Ternary
function VisitAssignment(const Node: IAssignmentNode): IAstNode; override;
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode; override;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; override;
@@ -279,18 +279,38 @@ begin
Result := TAst.IfExpr(Node.Identity, newCond, newThen, newElse, Node.StaticType);
end;
function TAstNodeRemover.VisitTernaryExpression(const Node: ITernaryExpressionNode): IAstNode;
function TAstNodeRemover.VisitCondExpression(const Node: ICondExpressionNode): IAstNode;
var
newCond, newThen, newElse: IAstNode;
i: Integer;
newPairs: TArray<TCondPair>;
newElse: IAstNode;
newCond, newBranch: IAstNode;
hasChanged: Boolean;
begin
newCond := EnsureNode(Accept(Node.Condition), Node);
newThen := EnsureNode(Accept(Node.ThenBranch), Node);
newElse := EnsureNode(Accept(Node.ElseBranch), Node);
SetLength(newPairs, Length(Node.Pairs));
hasChanged := False;
if (newCond = Node.Condition) and (newThen = Node.ThenBranch) and (newElse = Node.ElseBranch) then
for i := 0 to High(Node.Pairs) do
begin
// Ensure mandatory children exist (replace with Nop if removed)
newCond := EnsureNode(Accept(Node.Pairs[i].Condition), Node);
newBranch := EnsureNode(Accept(Node.Pairs[i].Branch), Node);
newPairs[i] := TCondPair.Create(newCond, newBranch);
if (newCond <> Node.Pairs[i].Condition) or (newBranch <> Node.Pairs[i].Branch) then
hasChanged := True;
end;
// Else branch is effectively mandatory in the structure, even if it's Nop/Void
newElse := EnsureNode(Accept(Node.ElseBranch), Node);
if newElse <> Node.ElseBranch then
hasChanged := True;
if not hasChanged then
Exit(Node);
Result := TAst.TernaryExpr(Node.Identity, newCond, newThen, newElse, Node.StaticType);
Result := TAst.CondExpr(Node.Identity, newPairs, newElse, Node.StaticType);
end;
function TAstNodeRemover.VisitAssignment(const Node: IAssignmentNode): IAstNode;
+25 -10
View File
@@ -50,7 +50,7 @@ var
list_content ::= special_form | function_call
special_form ::= "if" expression expression expression?
| "?" expression expression expression
| "?" (expression expression)* expression (* cond1 branch1 ... else *)
| "def" identifier expression?
| "defmacro" identifier parameter_list expression
| "assign" identifier expression
@@ -206,7 +206,7 @@ type
function VisitRecordField(const Node: IRecordFieldNode): TVoid; override;
function VisitIfExpression(const Node: IIfExpressionNode): TVoid; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TVoid; override;
function VisitCondExpression(const Node: ICondExpressionNode): TVoid; override;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TVoid; override;
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TVoid; override;
function VisitQuasiquote(const Node: IQuasiquoteNode): TVoid; override;
@@ -642,9 +642,19 @@ begin
end
else if SameText(head.Token.Text, '?') then
begin
if Length(tailNodes) <> 3 then
Error('Syntax Error in ternary statement.');
Result := TAst.TernaryExpr(tailNodes[0], tailNodes[1], tailNodes[2], startLoc);
// (? test1 branch1 test2 branch2 ... else)
// Requires odd number of tailNodes (pairs + 1 else)
var count := Length(tailNodes);
if (count < 1) or ((count mod 2) = 0) then
Error('Syntax Error: ''?'' (cond) requires an odd number of arguments (pairs of condition/branch and one final else).');
var pairs: TArray<TCondPair>;
SetLength(pairs, count div 2);
for var i := 0 to High(pairs) do
pairs[i] := TCondPair.Create(tailNodes[i * 2], tailNodes[i * 2 + 1]);
var elseNode := tailNodes[High(tailNodes)];
Result := TAst.CondExpr(pairs, elseNode, startLoc);
end
else if SameText(head.Token.Text, 'def') then
begin
@@ -946,13 +956,18 @@ begin
Append(')');
end;
function TPrettyPrintVisitor.VisitTernaryExpression(const Node: ITernaryExpressionNode): TVoid;
function TPrettyPrintVisitor.VisitCondExpression(const Node: ICondExpressionNode): TVoid;
begin
Append('(? ');
Node.Condition.Accept(Self);
Append('(?');
Indent;
NewLine;
Node.ThenBranch.Accept(Self);
for var pair in Node.Pairs do
begin
NewLine;
pair.Condition.Accept(Self);
Append(' ');
pair.Branch.Accept(Self);
end;
// Else
NewLine;
Node.ElseBranch.Accept(Self);
Unindent;
+38 -16
View File
@@ -26,7 +26,7 @@ type
function IAstVisitor.VisitRecordField = DoVisitRecordField;
function IAstVisitor.VisitIfExpression = DoVisitIfExpression;
function IAstVisitor.VisitTernaryExpression = DoVisitTernaryExpression;
function IAstVisitor.VisitCondExpression = DoVisitCondExpression; // Updated
function IAstVisitor.VisitLambdaExpression = DoVisitLambdaExpression;
function IAstVisitor.VisitFunctionCall = DoVisitFunctionCall;
function IAstVisitor.VisitMacroExpansionNode = DoVisitMacroExpansionNode;
@@ -58,7 +58,7 @@ type
function DoVisitRecordField(const Node: IRecordFieldNode): TDataValue;
function DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue;
function DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
function DoVisitCondExpression(const Node: ICondExpressionNode): TDataValue; // Updated
function DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
function DoVisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
function DoVisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue;
@@ -94,7 +94,7 @@ type
function VisitRecordField(const Node: IRecordFieldNode): T; virtual;
function VisitIfExpression(const Node: IIfExpressionNode): T; virtual;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): T; virtual;
function VisitCondExpression(const Node: ICondExpressionNode): T; virtual; // Updated
function VisitLambdaExpression(const Node: ILambdaExpressionNode): T; virtual;
function VisitFunctionCall(const Node: IFunctionCallNode): T; virtual;
function VisitMacroExpansionNode(const Node: IMacroExpansionNode): T; virtual;
@@ -128,7 +128,7 @@ type
function VisitRecordField(const Node: IRecordFieldNode): IAstNode; override;
function VisitIfExpression(const Node: IIfExpressionNode): IAstNode; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): IAstNode; override;
function VisitCondExpression(const Node: ICondExpressionNode): IAstNode; override; // Updated
function VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; override;
function VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; override;
function VisitMacroExpansionNode(const Node: IMacroExpansionNode): IAstNode; override;
@@ -204,9 +204,9 @@ function TAstVisitor<T>.DoVisitIfExpression(const Node: IIfExpressionNode): TDat
begin
Result := TDataValue.FromGeneric<T>(VisitIfExpression(Node));
end;
function TAstVisitor<T>.DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
function TAstVisitor<T>.DoVisitCondExpression(const Node: ICondExpressionNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitTernaryExpression(Node));
Result := TDataValue.FromGeneric<T>(VisitCondExpression(Node));
end;
function TAstVisitor<T>.DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
begin
@@ -341,11 +341,16 @@ begin
Accept(Node.ElseBranch);
end;
function TAstVisitor<T>.VisitTernaryExpression(const Node: ITernaryExpressionNode): T;
function TAstVisitor<T>.VisitCondExpression(const Node: ICondExpressionNode): T;
var
pair: TCondPair;
begin
Result := Default(T);
Accept(Node.Condition);
Accept(Node.ThenBranch);
for pair in Node.Pairs do
begin
Accept(pair.Condition);
Accept(pair.Branch);
end;
Accept(Node.ElseBranch);
end;
@@ -621,18 +626,35 @@ begin
Result := TAst.IfExpr(Node.Identity, newCond, newThen, newElse, Node.StaticType);
end;
function TAstTransformer.VisitTernaryExpression(const Node: ITernaryExpressionNode): IAstNode;
function TAstTransformer.VisitCondExpression(const Node: ICondExpressionNode): IAstNode;
var
newCond, newThen, newElse: IAstNode;
newPairs: TArray<TCondPair>;
newElse: IAstNode;
hasChanged: Boolean;
i: Integer;
newCond, newBranch: IAstNode;
begin
newCond := Accept(Node.Condition);
newThen := Accept(Node.ThenBranch);
newElse := Accept(Node.ElseBranch);
hasChanged := False;
SetLength(newPairs, Length(Node.Pairs));
if (newCond = Node.Condition) and (newThen = Node.ThenBranch) and (newElse = Node.ElseBranch) then
for i := 0 to High(Node.Pairs) do
begin
newCond := Accept(Node.Pairs[i].Condition);
newBranch := Accept(Node.Pairs[i].Branch);
newPairs[i] := TCondPair.Create(newCond, newBranch);
if (newCond <> Node.Pairs[i].Condition) or (newBranch <> Node.Pairs[i].Branch) then
hasChanged := True;
end;
newElse := Accept(Node.ElseBranch); // Accept handles nil
if newElse <> Node.ElseBranch then
hasChanged := True;
if not hasChanged then
Result := Node
else
Result := TAst.TernaryExpr(Node.Identity, newCond, newThen, newElse, Node.StaticType);
Result := TAst.CondExpr(Node.Identity, newPairs, newElse, Node.StaticType);
end;
function TAstTransformer.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode;
+32 -17
View File
@@ -101,19 +101,26 @@ type
const AStaticType: IStaticType = nil
): IIfExpressionNode; overload; static;
// --- TERNARY ---
// --- COND (Previously Ternary) ---
class function CondExpr(
const APairs: TArray<TCondPair>;
const AElseBranch: IAstNode;
const Loc: ISourceLocation = nil
): ICondExpressionNode; overload; static;
class function CondExpr(
const Identity: IAstIdentity;
const APairs: TArray<TCondPair>;
const AElseBranch: IAstNode;
const AStaticType: IStaticType = nil
): ICondExpressionNode; overload; static;
// Convenience wrapper for Ternary operator behavior using CondExpr
class function TernaryExpr(
const ACondition: IAstNode;
const AThenBranch, AElseBranch: IAstNode;
const Loc: ISourceLocation = nil
): ITernaryExpressionNode; overload; static;
class function TernaryExpr(
const Identity: IAstIdentity;
const ACondition: IAstNode;
const AThenBranch, AElseBranch: IAstNode;
const AStaticType: IStaticType = nil
): ITernaryExpressionNode; overload; static;
): ICondExpressionNode; overload; static;
// --- LAMBDA ---
class function LambdaExpr(
@@ -488,22 +495,22 @@ begin
);
end;
class function TAst.TernaryExpr(const ACondition, AThenBranch, AElseBranch: IAstNode; const Loc: ISourceLocation): ITernaryExpressionNode;
class function TAst.CondExpr(const APairs: TArray<TCondPair>; const AElseBranch: IAstNode; const Loc: ISourceLocation): ICondExpressionNode;
begin
var id := TIdentities.Structural(Loc);
Result := TTernaryExpressionNode.Create(ACondition, AThenBranch, AElseBranch, TTypes.Unknown, id);
Result := TCondExpressionNode.Create(APairs, AElseBranch, TTypes.Unknown, id);
end;
class function TAst.TernaryExpr(
class function TAst.CondExpr(
const Identity: IAstIdentity;
const ACondition, AThenBranch, AElseBranch: IAstNode;
const APairs: TArray<TCondPair>;
const AElseBranch: IAstNode;
const AStaticType: IStaticType
): ITernaryExpressionNode;
): ICondExpressionNode;
begin
Result :=
TTernaryExpressionNode.Create(
ACondition,
AThenBranch,
TCondExpressionNode.Create(
APairs,
AElseBranch,
if AStaticType <> nil then AStaticType
else TTypes.Unknown,
@@ -511,6 +518,14 @@ begin
);
end;
class function TAst.TernaryExpr(const ACondition, AThenBranch, AElseBranch: IAstNode; const Loc: ISourceLocation): ICondExpressionNode;
var
pair: TCondPair;
begin
pair := TCondPair.Create(ACondition, AThenBranch);
Result := TAst.CondExpr([pair], AElseBranch, Loc);
end;
class function TAst.LambdaExpr(
const AParameters: TArray<IIdentifierNode>;
const ABody: IAstNode;
+69 -13
View File
@@ -32,12 +32,20 @@ type
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
end;
TTernaryExpressionNodeHandler = class(TBaseNodeHandler<ITernaryExpressionNode>)
// Handles the 'cond' expression (multi-branch if/else)
TCondExpressionNodeHandler = class(TBaseNodeHandler<ICondExpressionNode>)
private
FConditionNode: TAstViewNode;
FThenNode: TAstViewNode;
type
TBranchView = record
Condition: TAstViewNode;
Branch: TAstViewNode;
end;
private
FBranchNodes: TList<TBranchView>;
FElseNode: TAstViewNode;
public
constructor Create(const ANode: ICondExpressionNode);
destructor Destroy; override;
procedure BuildUI(OwnerNode: TAstViewNode); override;
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
end;
@@ -152,26 +160,74 @@ begin
Result := TAst.IfExpr(FNode.Identity, FConditionNode.CreateAst, FThenNode.CreateAst, elseAst, FNode.StaticType);
end;
{ TTernaryExpressionNodeHandler }
{ TCondExpressionNodeHandler }
procedure TTernaryExpressionNodeHandler.BuildUI(OwnerNode: TAstViewNode);
constructor TCondExpressionNodeHandler.Create(const ANode: ICondExpressionNode);
begin
inherited Create(ANode);
FBranchNodes := TList<TBranchView>.Create;
end;
destructor TCondExpressionNodeHandler.Destroy;
begin
FBranchNodes.Free;
inherited;
end;
procedure TCondExpressionNodeHandler.BuildUI(OwnerNode: TAstViewNode);
var
visu: IAstVisualizer;
pair: TCondPair;
i: Integer;
row: TAutoFitLayout;
bv: TBranchView;
begin
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
OwnerNode.Frameless := True;
OwnerNode.Orientation := loHorizontal;
FConditionNode := visu.CallAccept(FNode.Condition);
OwnerNode.AddLabel(OwnerNode, '?');
FThenNode := visu.CallAccept(FNode.ThenBranch);
OwnerNode.AddLabel(OwnerNode, ':');
OwnerNode.Frameless := False;
OwnerNode.Orientation := loVertical;
OwnerNode.Alignment := laFlush;
var title := OwnerNode.AddLabel(OwnerNode, '?');
title.FontSettings.Font.Style := [TFontStyle.fsBold];
for i := 0 to High(FNode.Pairs) do
begin
pair := FNode.Pairs[i];
row := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter);
row.Margins := TMarginRect.Create(0, 2, 0, 2);
bv.Condition := visu.CallAccept(pair.Condition);
row.AddChild(bv.Condition);
OwnerNode.AddLabel(row, '->');
bv.Branch := visu.CallAccept(pair.Branch);
row.AddChild(bv.Branch);
FBranchNodes.Add(bv);
end;
// Else Branch
var elseRow := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter);
elseRow.Margins := TMarginRect.Create(0, 4, 0, 0); // Extra spacing
OwnerNode.AddLabel(elseRow, 'else ->');
FElseNode := visu.CallAccept(FNode.ElseBranch);
// FIX: Use AddChild instead of assigning Parent directly
elseRow.AddChild(FElseNode);
end;
function TTernaryExpressionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
function TCondExpressionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
var
newPairs: TArray<TCondPair>;
i: Integer;
begin
Result := TAst.TernaryExpr(FNode.Identity, FConditionNode.CreateAst, FThenNode.CreateAst, FElseNode.CreateAst, FNode.StaticType);
SetLength(newPairs, FBranchNodes.Count);
for i := 0 to FBranchNodes.Count - 1 do
begin
newPairs[i] := TCondPair.Create(FBranchNodes[i].Condition.CreateAst, FBranchNodes[i].Branch.CreateAst);
end;
Result := TAst.CondExpr(FNode.Identity, newPairs, FElseNode.CreateAst, FNode.StaticType);
end;
{ TLambdaExpressionNodeHandler }
+3 -3
View File
@@ -43,7 +43,7 @@ type
// Control Flow
function VisitIfExpression(const Node: IIfExpressionNode): TAstViewNode; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstViewNode; override;
function VisitCondExpression(const Node: ICondExpressionNode): TAstViewNode; override; // Replaces Ternary
function VisitBlockExpression(const Node: IBlockExpressionNode): TAstViewNode; override;
function VisitRecurNode(const Node: IRecurNode): TAstViewNode; override;
function VisitNop(const Node: INopNode): TAstViewNode; override;
@@ -225,9 +225,9 @@ begin
Result := TAstViewNode.Create(Self, TIfExpressionNodeHandler.Create(Node));
end;
function TAstVisualizer.VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstViewNode;
function TAstVisualizer.VisitCondExpression(const Node: ICondExpressionNode): TAstViewNode;
begin
Result := TAstViewNode.Create(Self, TTernaryExpressionNodeHandler.Create(Node));
Result := TAstViewNode.Create(Self, TCondExpressionNodeHandler.Create(Node));
end;
function TAstVisualizer.VisitRecurNode(const Node: IRecurNode): TAstViewNode;