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