Refactoring for immutable nodes

This commit is contained in:
Michael Schimmel
2025-11-05 13:21:17 +01:00
parent 9bd2d6f7ab
commit c0a689d2bc
13 changed files with 217 additions and 190 deletions
+2 -2
View File
@@ -172,9 +172,9 @@ end;
function TAstBinder.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode;
begin
// --- Transformation: Keyword-as-Function ---
if (Node.Callee is TKeywordNode) then
if Node.Callee.Kind = akKeyword then
begin
var keywordNode := (Node.Callee as TKeywordNode);
var keywordNode := Node.Callee.AsKeyword;
if Length(Node.Arguments) <> 1 then
raise EArgumentException.CreateFmt(
'Keyword :%s expects exactly one argument (the record/map), but got %d',
+4 -8
View File
@@ -117,11 +117,10 @@ end;
function TAstTCO.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode;
var
isContextTail: Boolean;
newExprs: TArray<IAstNode>; // For CoW
newExprs: TArray<IAstNode>;
begin
isContextTail := FIsTailStack.Peek;
// Call the base implementation which handles CoW
var nTail := High(Node.Expressions);
newExprs :=
AcceptNodes(
@@ -237,20 +236,17 @@ end;
function TAstTCO.VisitMacroExpansionNode(const Node: IMacroExpansionNode): IAstNode;
var
N: TMacroExpansionNode;
newBody: IAstNode;
begin
N := (Node as TMacroExpansionNode);
// Propagate tail call status to the expanded body
FNextIsTail := FIsTailStack.Peek;
newBody := Accept(N.ExpandedBody);
newBody := Accept(Node.ExpandedBody);
if newBody = N.ExpandedBody then
if newBody = Node.ExpandedBody then
Result := Node
else
// Rebuild, preserving the original CallNode metadata
Result := TMacroExpansionNode.Create(N.CallNode, newBody, newBody.AsTypedNode.StaticType);
Result := TMacroExpansionNode.Create(Node.CallNode, newBody.AsTypedNode);
end;
function TAstTCO.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode;
+1 -5
View File
@@ -739,11 +739,7 @@ begin
for i := 0 to fieldsArray.Count - 1 do
begin
fieldObj := fieldsArray.Items[i] as TJSONObject;
fields[i] :=
TRecordFieldLiteral.Create(
TKeywordNode.Create(TKeywordRegistry.Intern(fieldObj.GetValue<string>('Name'))),
JsonToNode(fieldObj.GetValue('Value'))
);
fields[i] := TRecordFieldLiteral.Create(TAst.Keyword(fieldObj.GetValue<string>('Name')), JsonToNode(fieldObj.GetValue('Value')));
end;
Result := TAst.RecordLiteral(fields);
end;
+3 -3
View File
@@ -85,16 +85,16 @@ end;
function TAstLowerer.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode;
var
calleeIdentifier: TIdentifierNode;
calleeIdentifier: IIdentifierNode;
binaryOp: TScalar.TBinaryOp;
unaryOp: TScalar.TUnaryOp;
left, right: IAstNode;
nodeType: IStaticType;
begin
// --- Optimization: Operator Folding ---
if (Node.Callee is TIdentifierNode) then
if Node.Callee.Kind = akIdentifier then
begin
calleeIdentifier := Node.Callee as TIdentifierNode;
calleeIdentifier := Node.Callee.AsIdentifier;
// Get the type *before* replacing the node (it's an IAstTypedNode)
nodeType := Node.AsTypedNode.StaticType;
+6 -6
View File
@@ -113,9 +113,9 @@ begin
try
for var node in ANodes do
begin
if (node is TUnquoteSplicingNode) then
if node.Kind = akUnquoteSplicing then
begin
var spliceExpr := (node as TUnquoteSplicingNode).Expression;
var spliceExpr := node.AsUnquoteSplicing.Expression;
// Evaluate the unquoted expression
var evaluatedSpliceValue := FEvaluate(spliceExpr);
@@ -158,9 +158,9 @@ begin
expr := Node.Expression;
// Check if we are unquoting a macro parameter (simple identifier)
if (expr is TIdentifierNode) then
if expr.Kind = akIdentifier then
begin
symbol := FMacroScope.CreateDescriptor.FindSymbol((expr as TIdentifierNode).Name);
symbol := FMacroScope.CreateDescriptor.FindSymbol(expr.AsIdentifier.Name);
if (symbol.Address.Kind = akLocalOrParent) and (symbol.Address.ScopeDepth = 0) then
begin
// It's a parameter. Return the TDataValue containing the AST node passed as argument.
@@ -269,7 +269,7 @@ end;
function TMacroExpander.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode;
var
calleeIdentifier: TIdentifierNode;
calleeIdentifier: IIdentifierNode;
macroDef: IMacroDefinitionNode;
i: Integer;
begin
@@ -277,7 +277,7 @@ begin
if Node.Callee.Kind <> akIdentifier then
exit(inherited VisitFunctionCall(Node));
calleeIdentifier := Node.Callee as TIdentifierNode;
calleeIdentifier := Node.Callee.AsIdentifier;
// Check if this identifier is a macro
macroDef := FCurrentDescriptor.FindMacro(calleeIdentifier.Name);
+2
View File
@@ -132,6 +132,7 @@ type
IAstNode = interface(IInterface)
{$region 'private'}
function GetKind: TAstNodeKind;
function GetIsTyped: Boolean;
{$endregion}
function Accept(const Visitor: IAstVisitor): TDataValue;
@@ -164,6 +165,7 @@ type
function AsBoundIdentifierNode: IBoundIdentifierNode;
function AsTypedNode: IAstTypedNode;
property IsTyped: Boolean read GetIsTyped;
property Kind: TAstNodeKind read GetKind;
end;
+17 -5
View File
@@ -112,6 +112,7 @@ type
TScopeItem = record
Value: TDataValue;
IsBoxed: Boolean;
function GetContent: TDataValue;
end;
private
@@ -606,7 +607,6 @@ end;
procedure TScopeDescriptor.PopulateFromScope(Scope: TExecutionScope);
var
val: TDataValue;
i: Integer;
begin
// Recreate descriptor by iterating all defined symbols in the runtime scope.
@@ -627,11 +627,16 @@ begin
// FSlotTypes[slotIndex] remains TTypes.Unknown.
// Check if the symbol is also a macro and add it to the macro table.
val := Scope.ValuesArray[slotIndex].Value;
if (val.Kind = vkInterface) and (val.AsIntf<IAstNode> is TMacroDefinitionNode) then
var val := Scope.ValuesArray[slotIndex].GetContent;
if val.Kind = vkInterface then
begin
if not FMacros.ContainsKey(name) then
FMacros.Add(name, val.AsIntf<IMacroDefinitionNode>);
var node := val.AsIntf<IAstNode>;
if (node <> nil) and (node.Kind = akMacroDefinition) then
begin
if not FMacros.ContainsKey(name) then
FMacros.Add(name, node.AsMacroDefinition);
end;
end;
end;
end;
@@ -652,4 +657,11 @@ begin
Result := TExecutionScope.Create(Parent, Descriptor, CapturedUpvalues);
end;
function TExecutionScope.TScopeItem.GetContent: TDataValue;
begin
Result := Value;
if IsBoxed then
Result := Result.AsIntf<IValueCell>.Value;
end;
end.
+2 -2
View File
@@ -511,7 +511,7 @@ begin
raise Exception.Create('Syntax Error: Missing value for key ' + fieldName + ' in record literal.');
fieldValue := ParseExpression.Node;
fields.Add(TRecordFieldLiteral.Create(TKeywordNode.Create(TKeywordRegistry.Intern(fieldName)), fieldValue));
fields.Add(TRecordFieldLiteral.Create(TAst.Keyword(fieldName), fieldValue));
end;
Result := TAst.RecordLiteral(fields.ToArray);
@@ -945,7 +945,7 @@ var
arg: IAstNode;
begin
// Special case for (quote ...) to print it as '...
if (Node.Callee is TIdentifierNode) and (TIdentifierNode(Node.Callee).Name = 'quote') and (Length(Node.Arguments) = 1) then
if (Node.Callee.Kind = akIdentifier) and (Node.Callee.AsIdentifier.Name = 'quote') and (Length(Node.Arguments) = 1) then
begin
Append('''');
Node.Arguments[0].Accept(Self);
+9 -18
View File
@@ -87,28 +87,19 @@ begin
end;
function TTypeChecker.VisitConstant(const Node: IConstantNode): IAstNode;
var
constType: IStaticType;
begin
// This is a leaf node.
// Assign the type based on the literal value
case Node.Value.Kind of
TDataValueKind.vkScalar: constType := TTypes.FromScalarKind(Node.Value.AsScalar.Kind);
TDataValueKind.vkText: constType := TTypes.Text;
TDataValueKind.vkVoid: constType := TTypes.Void;
else
constType := TTypes.Unknown;
end;
// Create a new node with the correct type
Result := TConstantNode.Create(Node.Value, constType);
// If the constructor couldn't set the type, nobody can
Assert(Node.StaticType.Kind <> stUnknown);
Result := Node;
end;
function TTypeChecker.VisitKeyword(const Node: IKeywordNode): IAstNode;
begin
// This is a leaf node.
// The TKeywordNode constructor *forces* the type to be TTypes.Keyword.
Result := TKeywordNode.Create(Node.Value);
Assert(Node.StaticType.Kind = stKeyword);
Result := Node;
end;
function TTypeChecker.VisitIdentifier(const Node: IIdentifierNode): IAstNode;
@@ -123,7 +114,7 @@ begin
adr := Node.AsBoundIdentifierNode.Address;
// Create a new node, copying the address and assigning the inferred type
Result := TBoundIdentifierNode.Create(Node.Name, adr, symbol.StaticType);
Result := TAst.BoundIdentifier(Node.Name, adr, symbol.StaticType);
end;
function TTypeChecker.VisitRecurNode(const Node: IRecurNode): IAstNode;
@@ -169,7 +160,7 @@ begin
FCurrentDescriptor.UpdateType(adr.SlotIndex, initType);
// 5. Create the new (typed) identifier node
newIdent := TBoundIdentifierNode.Create(boundIdent.Name, adr, initType);
newIdent := TAst.BoundIdentifier(boundIdent.Name, adr, initType);
// 6. Create the new VariableDeclaration node
Result := TVariableDeclarationNode.Create(newIdent.AsIdentifier, newInitializer, initType);
@@ -205,7 +196,7 @@ begin
FCurrentDescriptor.UpdateType(adr.SlotIndex, sourceType);
// Re-create the identifier node *with the new type*
newIdent := TBoundIdentifierNode.Create(newIdent.AsIdentifier.Name, adr, sourceType);
newIdent := TAst.BoundIdentifier(newIdent.AsIdentifier.Name, adr, sourceType);
targetType := sourceType;
end;
@@ -239,7 +230,7 @@ begin
// (even if they are just TTypes.Unknown for now, for type inference placeholders)
var paramIdent := boundNode.Parameters[i];
var paramAdr := paramIdent.AsBoundIdentifierNode.Address;
var newParam := TBoundIdentifierNode.Create(paramIdent.Name, paramAdr, TTypes.Unknown);
var newParam := TAst.BoundIdentifier(paramIdent.Name, paramAdr);
newParams[i] := newParam;
paramTypes[i] := TTypes.Unknown;
+7 -20
View File
@@ -571,28 +571,15 @@ end;
function TAstTransformer.VisitMacroExpansionNode(const Node: IMacroExpansionNode): IAstNode;
var
newBody: IAstNode;
N: TMacroExpansionNode;
newType: IStaticType;
newBody: IAstTypedNode;
begin
N := (Node as TMacroExpansionNode);
// Visit the body and check if it changed
newBody := Accept(Node.ExpandedBody).AsTypedNode;
if newBody = Node.ExpandedBody then
exit(Node);
// 1. Visit the body
newBody := Accept(N.ExpandedBody);
// 2. Check if the body changed (Copy-on-Write)
if newBody = N.ExpandedBody then
begin
// No change, return the original immutable node
Result := Node;
end
else
begin
// The body changed. Create a NEW wrapper node.
// The type of the wrapper is the type of its body.
newType := newBody.AsTypedNode.StaticType;
Result := TMacroExpansionNode.Create(N.CallNode, newBody, newType);
end;
// The body changed. Create a NEW wrapper node.
Result := TMacroExpansionNode.Create(Node.CallNode, newBody);
end;
function TAstTransformer.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode;
+158 -115
View File
@@ -33,7 +33,7 @@ type
class function Nop: IAstNode; static;
// --- Factory functions ---
class function Constant(const AValue: TDataValue): IConstantNode; overload; static;
class function Constant(const AValue: TDataValue; const AStaticType: IStaticType = nil): IConstantNode; overload; static;
class function Constant(const AValue: String): IConstantNode; overload; static;
class function Keyword(const AName: string): IKeywordNode; static;
class function Identifier(AName: string): IIdentifierNode; static;
@@ -71,13 +71,18 @@ type
): IAddSeriesItemNode; static;
class function SeriesLength(const ASeries: IIdentifierNode): ISeriesLengthNode; static;
class function BoundIdentifier(AName: string; const Address: TResolvedAddress): IBoundIdentifierNode; static;
class function BoundIdentifier(
AName: string;
const Address: TResolvedAddress;
const AStaticType: IStaticType = nil
): IBoundIdentifierNode; static;
end;
// Common base class for AST nodes to reduce boilerplate.
TAstNode = class(TInterfacedObject, IAstNode)
private
function GetKind: TAstNodeKind; virtual; abstract;
function GetIsTyped: Boolean; virtual;
public
constructor Create;
function Accept(const Visitor: IAstVisitor): TDataValue; virtual; abstract;
@@ -112,6 +117,7 @@ type
function AsBoundIdentifierNode: IBoundIdentifierNode; virtual;
function AsTypedNode: IAstTypedNode; virtual;
property IsTyped: Boolean read GetIsTyped;
property Kind: TAstNodeKind read GetKind;
end;
@@ -119,59 +125,13 @@ type
private
FStaticType: IStaticType;
function GetStaticType: IStaticType;
function GetIsTyped: Boolean; override;
public
constructor Create(const AStaticType: IStaticType);
function AsTypedNode: IAstTypedNode; override;
property StaticType: IStaticType read GetStaticType;
end;
TConstantNode = class(TAstTypedNode, IConstantNode)
private
FValue: TDataValue;
function GetValue: TDataValue;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AValue: TDataValue; const AStaticType: IStaticType);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsConstant: IConstantNode; override;
property Value: TDataValue read GetValue; // Value ist immutable
end;
TIdentifierNode = class(TAstTypedNode, IIdentifierNode)
private
FName: string;
function GetName: string;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AName: string; const AStaticType: IStaticType);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsIdentifier: IIdentifierNode; override;
property Name: string read FName; // Name ist immutable
end;
TBoundIdentifierNode = class(TIdentifierNode, IBoundIdentifierNode)
private
FAddress: TResolvedAddress;
function GetAddress: TResolvedAddress;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AName: string; const AAddress: TResolvedAddress; const AStaticType: IStaticType);
function AsBoundIdentifierNode: IBoundIdentifierNode; override;
property Address: TResolvedAddress read GetAddress;
end;
TKeywordNode = class(TAstTypedNode, IKeywordNode)
private
FValue: IKeyword;
function GetValue: IKeyword;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AValue: IKeyword);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsKeyword: IKeywordNode; override;
property Value: IKeyword read FValue; // Value ist immutable
end;
TBinaryExpressionNode = class(TAstTypedNode, IBinaryExpressionNode)
private
FLeft: IAstNode;
@@ -263,60 +223,6 @@ type
property HasNestedLambdas: Boolean read FHasNestedLambdas write FHasNestedLambdas;
end;
TMacroDefinitionNode = class(TAstNode, IMacroDefinitionNode)
private
FName: IIdentifierNode;
FParameters: TArray<IIdentifierNode>;
FBody: IAstNode;
function GetName: IIdentifierNode;
function GetParameters: TArray<IIdentifierNode>;
function GetBody: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AName: IIdentifierNode; const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsMacroDefinition: IMacroDefinitionNode; override;
property Name: IIdentifierNode read GetName;
property Parameters: TArray<IIdentifierNode> read FParameters;
property Body: IAstNode read FBody;
end;
TQuasiquoteNode = class(TAstNode, IQuasiquoteNode)
private
FExpression: IAstNode;
function GetExpression: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AExpression: IAstNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsQuasiquote: IQuasiquoteNode; override;
property Expression: IAstNode read GetExpression;
end;
TUnquoteNode = class(TAstNode, IUnquoteNode)
private
FExpression: IAstNode;
function GetExpression: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AExpression: IAstNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsUnquote: IUnquoteNode; override;
property Expression: IAstNode read GetExpression;
end;
TUnquoteSplicingNode = class(TAstNode, IUnquoteSplicingNode)
private
FExpression: IQuasiquoteNode;
function GetExpression: IQuasiquoteNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AExpression: IQuasiquoteNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsUnquoteSplicing: IUnquoteSplicingNode; override;
property Expression: IQuasiquoteNode read GetExpression;
end;
TFunctionCallNode = class(TAstTypedNode, IFunctionCallNode)
private
FCallee: IAstNode;
@@ -349,16 +255,16 @@ type
TMacroExpansionNode = class(TAstTypedNode, IMacroExpansionNode)
private
FCallNode: IFunctionCallNode;
FExpandedBody: IAstNode;
FExpandedBody: IAstTypedNode;
function GetCallNode: IFunctionCallNode;
function GetExpandedBody: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const ACallNode: IFunctionCallNode; const AExpandedBody: IAstNode; const AStaticType: IStaticType);
constructor Create(const ACallNode: IFunctionCallNode; const AExpandedBody: IAstTypedNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsMacroExpansion: IMacroExpansionNode; override;
property CallNode: IFunctionCallNode read GetCallNode;
property ExpandedBody: IAstNode read FExpandedBody;
property ExpandedBody: IAstTypedNode read FExpandedBody;
end;
TBlockExpressionNode = class(TAstTypedNode, IBlockExpressionNode)
@@ -508,8 +414,108 @@ implementation
uses
System.Generics.Defaults;
// Added Nop
type
TConstantNode = class(TAstTypedNode, IConstantNode)
private
FValue: TDataValue;
function GetValue: TDataValue;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AValue: TDataValue; const AStaticType: IStaticType);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsConstant: IConstantNode; override;
property Value: TDataValue read GetValue;
end;
TIdentifierNode = class(TAstTypedNode, IIdentifierNode)
private
FName: string;
function GetName: string;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AName: string; const AStaticType: IStaticType);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsIdentifier: IIdentifierNode; override;
property Name: string read FName;
end;
TBoundIdentifierNode = class(TIdentifierNode, IBoundIdentifierNode)
private
FAddress: TResolvedAddress;
function GetAddress: TResolvedAddress;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AName: string; const AAddress: TResolvedAddress; const AStaticType: IStaticType);
function AsBoundIdentifierNode: IBoundIdentifierNode; override;
property Address: TResolvedAddress read GetAddress;
end;
TKeywordNode = class(TAstTypedNode, IKeywordNode)
private
FValue: IKeyword;
function GetValue: IKeyword;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AValue: IKeyword);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsKeyword: IKeywordNode; override;
property Value: IKeyword read FValue; // Value ist immutable
end;
TMacroDefinitionNode = class(TAstNode, IMacroDefinitionNode)
private
FName: IIdentifierNode;
FParameters: TArray<IIdentifierNode>;
FBody: IAstNode;
function GetName: IIdentifierNode;
function GetParameters: TArray<IIdentifierNode>;
function GetBody: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AName: IIdentifierNode; const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsMacroDefinition: IMacroDefinitionNode; override;
property Name: IIdentifierNode read GetName;
property Parameters: TArray<IIdentifierNode> read FParameters;
property Body: IAstNode read FBody;
end;
TQuasiquoteNode = class(TAstNode, IQuasiquoteNode)
private
FExpression: IAstNode;
function GetExpression: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AExpression: IAstNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsQuasiquote: IQuasiquoteNode; override;
property Expression: IAstNode read GetExpression;
end;
TUnquoteNode = class(TAstNode, IUnquoteNode)
private
FExpression: IAstNode;
function GetExpression: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AExpression: IAstNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsUnquote: IUnquoteNode; override;
property Expression: IAstNode read GetExpression;
end;
TUnquoteSplicingNode = class(TAstNode, IUnquoteSplicingNode)
private
FExpression: IQuasiquoteNode;
function GetExpression: IQuasiquoteNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AExpression: IQuasiquoteNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsUnquoteSplicing: IUnquoteSplicingNode; override;
property Expression: IQuasiquoteNode read GetExpression;
end;
TNopNode = class(TAstNode, INopNode)
private
function GetKind: TAstNodeKind; override;
@@ -574,14 +580,28 @@ begin
Result := TBlockExpressionNode.Create(AExpressions, TTypes.Unknown);
end;
class function TAst.Constant(const AValue: TDataValue): IConstantNode;
class function TAst.Constant(const AValue: TDataValue; const AStaticType: IStaticType = nil): IConstantNode;
begin
Result := TConstantNode.Create(AValue, TTypes.Unknown);
var constType := AStaticType;
if constType = nil then
begin
case AValue.Kind of
TDataValueKind.vkScalar: constType := TTypes.FromScalarKind(AValue.AsScalar.Kind);
TDataValueKind.vkText: constType := TTypes.Text;
TDataValueKind.vkVoid: constType := TTypes.Void;
else
constType := TTypes.Unknown;
end;
end;
// Create a new node with the correct type
Result := TConstantNode.Create(AValue, constType);
end;
class function TAst.Constant(const AValue: String): IConstantNode;
begin
Result := TConstantNode.Create(AValue, TTypes.Unknown);
Result := TConstantNode.Create(AValue, TTypes.Text);
end;
class constructor TAst.Create;
@@ -594,9 +614,19 @@ begin
FLibraries.Free;
end;
class function TAst.BoundIdentifier(AName: string; const Address: TResolvedAddress): IBoundIdentifierNode;
class function TAst.BoundIdentifier(
AName: string;
const Address: TResolvedAddress;
const AStaticType: IStaticType = nil
): IBoundIdentifierNode;
begin
Result := TBoundIdentifierNode.Create(AName, Address, TTypes.Unknown);
Result :=
TBoundIdentifierNode.Create(
AName,
Address,
if AStaticType <> nil then AStaticType
else TTypes.Unknown
);
end;
class procedure TAst.RegisterLibrary(const AProc: TRegisterLibraryProc);
@@ -645,7 +675,10 @@ end;
class function TAst.MacroExpansionNode(const AOriginalCallNode: IFunctionCallNode; const AExpandedBody: IAstNode): IMacroExpansionNode;
begin
Result := TMacroExpansionNode.Create(AOriginalCallNode, AExpandedBody, TTypes.Unknown);
if AExpandedBody.IsTyped then
Result := TMacroExpansionNode.Create(AOriginalCallNode, AExpandedBody.AsTypedNode)
else
Result := TMacroExpansionNode.Create(AOriginalCallNode, Block([]));
end;
class function TAst.MemberAccess(const ABase: IAstNode; const AMember: IKeywordNode): IMemberAccessNode;
@@ -871,6 +904,11 @@ begin
raise ETypeException.Create('Node is not a VariableDeclaration');
end;
function TAstNode.GetIsTyped: Boolean;
begin
Result := false;
end;
{ TAstTypedNode }
constructor TAstTypedNode.Create(const AStaticType: IStaticType);
@@ -885,6 +923,11 @@ begin
Result := Self;
end;
function TAstTypedNode.GetIsTyped: Boolean;
begin
Result := true;
end;
function TAstTypedNode.GetStaticType: IStaticType;
begin
Result := FStaticType;
@@ -1334,10 +1377,10 @@ end;
{ TMacroExpansionNode }
constructor TMacroExpansionNode.Create(const ACallNode: IFunctionCallNode; const AExpandedBody: IAstNode; const AStaticType: IStaticType);
constructor TMacroExpansionNode.Create(const ACallNode: IFunctionCallNode; const AExpandedBody: IAstTypedNode);
begin
// Copy properties from the original call node
inherited Create(AStaticType);
inherited Create(AExpandedBody.StaticType);
FExpandedBody := AExpandedBody;
FCallNode := ACallNode;
end;