AST development

This commit is contained in:
Michael Schimmel
2025-09-01 19:24:22 +02:00
parent 3b3d94291d
commit 375e64411b
8 changed files with 864 additions and 297 deletions
+36 -6
View File
@@ -25,6 +25,7 @@ type
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TAstValue; virtual;
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TAstValue; virtual;
function VisitIfExpression(const Node: IIfExpressionNode): TAstValue; virtual;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstValue; virtual;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue; virtual;
function VisitFunctionCall(const Node: IFunctionCallNode): TAstValue; virtual;
function VisitBlockExpression(const Node: IBlockExpressionNode): TAstValue; virtual;
@@ -52,6 +53,7 @@ type
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TAstValue; override;
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TAstValue; override;
function VisitIfExpression(const Node: IIfExpressionNode): TAstValue; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstValue; override;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue; override;
function VisitFunctionCall(const Node: IFunctionCallNode): TAstValue; override;
function VisitBlockExpression(const Node: IBlockExpressionNode): TAstValue; override;
@@ -170,15 +172,13 @@ end;
function TEvaluatorVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAstValue;
var
varName: string;
initValue: TAstValue;
begin
varName := Node.Identifier.Name;
if Assigned(Node.Initializer) then
initValue := Node.Initializer.Accept(Self)
Result := Node.Initializer.Accept(Self)
else
initValue := TAstValue.Void;
FScope.SetValue(varName, initValue);
Result := TAstValue.Void;
Result := TAstValue.Void;
FScope.SetValue(varName, Result);
end;
function TEvaluatorVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue;
@@ -210,7 +210,7 @@ begin
if (arguments.Count <> Length(closure.Parameters)) then
raise EArgumentException.CreateFmt('Argument count mismatch: expected %d, got %d', [Length(closure.Parameters), arguments.Count]);
callScope := T_ExecutionScope.Create(closure.ClosureScope);
callScope := TExecutionScope.Create(closure.ClosureScope);
for i := 0 to arguments.Count - 1 do
begin
@@ -219,6 +219,13 @@ begin
end;
innerVisitor := Self.CreateVisitorForScope(callScope);
// Introduce 'Result' variable for imperative-style assignments within the closure.
callScope.SetValue('Result', TAstValue.Void);
// The return value of the function is the value of its body expression.
// This supports both functional-style returns (direct value) and
// imperative-style returns (via an assignment, which also returns the value).
Result := closure.Body.Accept(innerVisitor);
end;
@@ -314,6 +321,17 @@ begin
Result := Node.ElseBranch.Accept(Self);
end;
function TEvaluatorVisitor.VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstValue;
var
conditionValue: TAstValue;
begin
conditionValue := Node.Condition.Accept(Self);
if IsTruthy(conditionValue) then
Result := Node.ThenBranch.Accept(Self)
else
Result := Node.ElseBranch.Accept(Self);
end;
function TEvaluatorVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): TAstValue;
var
expression: IExpressionNode;
@@ -457,6 +475,18 @@ begin
AppendLine(Format('} -> %s', [Result.ToString]));
end;
function TDebugEvaluatorVisitor.VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstValue;
begin
AppendLine('TernaryExpr{');
Indent;
try
Result := inherited VisitTernaryExpression(Node);
finally
Unindent;
end;
AppendLine(Format('} -> %s', [Result.ToString]));
end;
function TDebugEvaluatorVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue;
begin
AppendLine('LambdaExpr{');
+42 -24
View File
@@ -33,6 +33,8 @@ type
IBinaryExpressionNode = interface;
IUnaryExpressionNode = interface;
IIfExpressionNode = interface;
// Added forward declaration for the new ternary expression node.
ITernaryExpressionNode = interface;
ILambdaExpressionNode = interface;
IFunctionCallNode = interface;
IBlockExpressionNode = interface;
@@ -55,9 +57,25 @@ type
TAstValue = record
private
FKind: TAstValueKind;
FScalar: TScalar;
FInterface: IInterface;
type
IVal<T> = interface
['{70210CAF-0857-4BF1-8254-B8239A155A02}']
function GetValue: T;
property Value: T read GetValue;
end;
TVal<T> = class(TInterfacedObject, IVal<T>)
private
FValue: T;
function GetValue: T;
public
constructor Create(const AValue: T);
end;
var
FKind: TAstValueKind;
FScalar: TScalar;
FInterface: IInterface;
function GetKind: TAstValueKind; inline;
function GetIsVoid: Boolean; inline;
public
@@ -93,6 +111,8 @@ type
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TAstValue;
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TAstValue;
function VisitIfExpression(const Node: IIfExpressionNode): TAstValue;
// Added visitor method for the new ternary expression node.
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstValue;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue;
function VisitFunctionCall(const Node: IFunctionCallNode): TAstValue;
function VisitBlockExpression(const Node: IBlockExpressionNode): TAstValue;
@@ -141,6 +161,7 @@ type
property Right: IExpressionNode read GetRight;
end;
// Represents an if-statement for control flow.
IIfExpressionNode = interface(IExpressionNode)
{$region 'private'}
function GetCondition: IExpressionNode;
@@ -152,6 +173,18 @@ type
property ElseBranch: IExpressionNode read GetElseBranch;
end;
// Represents a ternary expression (e.g., condition ? true_expr : false_expr) for value selection.
ITernaryExpressionNode = interface(IExpressionNode)
{$region 'private'}
function GetCondition: IExpressionNode;
function GetThenBranch: IExpressionNode;
function GetElseBranch: IExpressionNode;
{$endregion}
property Condition: IExpressionNode read GetCondition;
property ThenBranch: IExpressionNode read GetThenBranch;
property ElseBranch: IExpressionNode read GetElseBranch;
end;
ILambdaExpressionNode = interface(IExpressionNode)
{$region 'private'}
function GetParameters: TArray<IIdentifierNode>;
@@ -200,31 +233,15 @@ implementation
uses
System.Classes;
type
// Private interface to encapsulate a non scalar value for reference counting.
IAstValue<T> = interface
function GetValue: string;
property Value: string read GetValue;
end;
// Implementation of the text value interface.
TAstValue<T> = class(TInterfacedObject, IAstValue<T>)
private
FValue: string;
function GetValue: string;
public
constructor Create(const AValue: string);
end;
{ TAstValue }
constructor TAstValue<T>.Create(const AValue: string);
constructor TAstValue.TVal<T>.Create(const AValue: T);
begin
inherited Create;
FValue := AValue;
end;
function TAstValue<T>.GetValue: string;
function TAstValue.TVal<T>.GetValue: T;
begin
Result := FValue;
end;
@@ -255,7 +272,8 @@ function TAstValue.AsText: String;
begin
if (FKind <> avkText) then
raise EInvalidCast.Create('Cannot read value as Text.');
Result := IAstValue<String>(FInterface).Value;
Result := (FInterface as IVal<String>).Value;
end;
class function TAstValue.FromClosure(const AValue: IEvaluatorClosure): TAstValue;
@@ -275,7 +293,7 @@ end;
class function TAstValue.FromText(const AValue: String): TAstValue;
begin
Result.FKind := avkText;
Result.FInterface := TAstValue<String>.Create(AValue);
Result.FInterface := TVal<String>.Create(AValue);
Result.FScalar := Default(TScalar);
end;
@@ -313,7 +331,7 @@ begin
case Self of
boAdd: Result := '+';
boSubtract: Result := '-';
boMultiply: Result := #$2A2F;
boMultiply: Result := '*';
boDivide: Result := '/';
boEqual: Result := '==';
boNotEqual: Result := '!=';
+21
View File
@@ -27,6 +27,7 @@ type
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TAstValue;
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TAstValue;
function VisitIfExpression(const Node: IIfExpressionNode): TAstValue;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstValue;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue;
function VisitFunctionCall(const Node: IFunctionCallNode): TAstValue;
function VisitBlockExpression(const Node: IBlockExpressionNode): TAstValue;
@@ -128,6 +129,26 @@ begin
Result := TAstValue.Void;
end;
function TPrettyPrintVisitor.VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstValue;
begin
AppendLine('TernaryExpr');
Indent;
AppendLine('Condition:');
Indent;
Node.Condition.Accept(Self);
Unindent;
AppendLine('Then:');
Indent;
Node.ThenBranch.Accept(Self);
Unindent;
AppendLine('Else:');
Indent;
Node.ElseBranch.Accept(Self);
Unindent;
Unindent;
Result := TAstValue.Void;
end;
function TPrettyPrintVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue;
var
param: IIdentifierNode;
+12 -12
View File
@@ -9,7 +9,7 @@ uses
Myc.Ast.Nodes;
type
T_ExecutionScope = class(TInterfacedObject, IExecutionScope)
TExecutionScope = class(TInterfacedObject, IExecutionScope)
private
FParent: IExecutionScope;
FVariables: TDictionary<string, TAstValue>;
@@ -29,27 +29,27 @@ type
implementation
{ T_ExecutionScope }
{ TExecutionScope }
constructor T_ExecutionScope.Create(AParent: IExecutionScope);
constructor TExecutionScope.Create(AParent: IExecutionScope);
begin
inherited Create;
FParent := AParent;
FVariables := TDictionary<string, TAstValue>.Create;
end;
destructor T_ExecutionScope.Destroy;
destructor TExecutionScope.Destroy;
begin
FVariables.Free;
inherited Destroy;
end;
function T_ExecutionScope.GetParent: IExecutionScope;
function TExecutionScope.GetParent: IExecutionScope;
begin
Result := FParent;
end;
procedure T_ExecutionScope.AssignValue(const Name: string; const Value: TAstValue);
procedure TExecutionScope.AssignValue(const Name: string; const Value: TAstValue);
begin
if FVariables.ContainsKey(Name) then
FVariables.AddOrSetValue(Name, Value)
@@ -59,14 +59,14 @@ begin
raise Exception.CreateFmt('Cannot assign to undeclared variable "%s".', [Name]);
end;
procedure T_ExecutionScope.Clear;
procedure TExecutionScope.Clear;
begin
FVariables.Clear;
if Assigned(FParent) then
FParent.Clear;
end;
procedure T_ExecutionScope.DumpScope(const ABuilder: TStringBuilder; AIndent: Integer);
procedure TExecutionScope.DumpScope(const ABuilder: TStringBuilder; AIndent: Integer);
var
pair: TPair<string, TAstValue>;
indentStr: string;
@@ -88,11 +88,11 @@ begin
// As FParent is now an interface, we must cast it back to the class to call the private DumpScope.
// This indicates that DumpScope should perhaps be part of the interface or handled differently.
// For now, we use a cast to keep the functionality.
(FParent as T_ExecutionScope).DumpScope(ABuilder, AIndent + 2);
(FParent as TExecutionScope).DumpScope(ABuilder, AIndent + 2);
end;
end;
function T_ExecutionScope.Dump: string;
function TExecutionScope.Dump: string;
var
builder: TStringBuilder;
begin
@@ -106,7 +106,7 @@ begin
end;
end;
function T_ExecutionScope.FindValue(const Name: string; out Value: TAstValue): Boolean;
function TExecutionScope.FindValue(const Name: string; out Value: TAstValue): Boolean;
begin
Result := FVariables.TryGetValue(Name, Value);
if not Result and Assigned(FParent) then
@@ -115,7 +115,7 @@ begin
end;
end;
procedure T_ExecutionScope.SetValue(const Name: string; const Value: TAstValue);
procedure TExecutionScope.SetValue(const Name: string; const Value: TAstValue);
begin
FVariables.AddOrSetValue(Name, Value);
end;
+60
View File
@@ -22,11 +22,17 @@ type
const ACondition: IExpressionNode;
const AThenBranch, AElseBranch: IExpressionNode
): IIfExpressionNode; static;
// Added factory function for the new ternary expression node.
class function TernaryExpr(
const ACondition: IExpressionNode;
const AThenBranch, AElseBranch: IExpressionNode
): ITernaryExpressionNode; static;
class function LambdaExpr(const AParameters: TArray<IIdentifierNode>; const ABody: IExpressionNode): ILambdaExpressionNode; static;
class function FunctionCall(const ACallee: IExpressionNode; const AArguments: array of IExpressionNode): IFunctionCallNode; static;
class function Block(const AExpressions: array of IExpressionNode): IBlockExpressionNode; static;
class function VarDecl(const AIdentifier: IIdentifierNode; AInitializer: IExpressionNode): IVariableDeclarationNode; static;
class function Assign(const AIdentifier: IIdentifierNode; const AValue: IExpressionNode): IAssignmentNode; static;
class function AssignResult(const AValue: IExpressionNode): IAssignmentNode; static;
end;
implementation
@@ -103,6 +109,20 @@ type
function Accept(const Visitor: IAstVisitor): TAstValue; override;
end;
{ TTernaryExpressionNode }
TTernaryExpressionNode = class(TAstNode, ITernaryExpressionNode)
private
FCondition: IExpressionNode;
FThenBranch: IExpressionNode;
FElseBranch: IExpressionNode;
function GetCondition: IExpressionNode;
function GetThenBranch: IExpressionNode;
function GetElseBranch: IExpressionNode;
public
constructor Create(const ACondition, AThenBranch, AElseBranch: IExpressionNode);
function Accept(const Visitor: IAstVisitor): TAstValue; override;
end;
{ TLambdaExpressionNode }
TLambdaExpressionNode = class(TAstNode, ILambdaExpressionNode)
private
@@ -283,6 +303,36 @@ begin
Result := FThenBranch;
end;
{ TTernaryExpressionNode }
constructor TTernaryExpressionNode.Create(const ACondition, AThenBranch, AElseBranch: IExpressionNode);
begin
inherited Create;
FCondition := ACondition;
FThenBranch := AThenBranch;
FElseBranch := AElseBranch;
end;
function TTernaryExpressionNode.Accept(const Visitor: IAstVisitor): TAstValue;
begin
Result := Visitor.VisitTernaryExpression(Self);
end;
function TTernaryExpressionNode.GetCondition: IExpressionNode;
begin
Result := FCondition;
end;
function TTernaryExpressionNode.GetElseBranch: IExpressionNode;
begin
Result := FElseBranch;
end;
function TTernaryExpressionNode.GetThenBranch: IExpressionNode;
begin
Result := FThenBranch;
end;
{ TLambdaExpressionNode }
constructor TLambdaExpressionNode.Create(const AParameters: TArray<IIdentifierNode>; const ABody: IExpressionNode);
@@ -424,6 +474,11 @@ begin
Result := TAssignmentNode.Create(AIdentifier, AValue);
end;
class function TAst.AssignResult(const AValue: IExpressionNode): IAssignmentNode;
begin
Result := Assign(TAst.Identifier('Result'), AValue);
end;
class function TAst.Block(const AExpressions: array of IExpressionNode): IBlockExpressionNode;
begin
Result := TBlockExpressionNode.Create(AExpressions);
@@ -454,6 +509,11 @@ begin
Result := TIfExpressionNode.Create(ACondition, AThenBranch, AElseBranch);
end;
class function TAst.TernaryExpr(const ACondition, AThenBranch, AElseBranch: IExpressionNode): ITernaryExpressionNode;
begin
Result := TTernaryExpressionNode.Create(ACondition, AThenBranch, AElseBranch);
end;
class function TAst.LambdaExpr(const AParameters: TArray<IIdentifierNode>; const ABody: IExpressionNode): ILambdaExpressionNode;
begin
Result := TLambdaExpressionNode.Create(AParameters, ABody);