Ast ternary expr replaced by cond expr
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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 }
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user