Refactoring for immutable nodes
This commit is contained in:
@@ -401,7 +401,7 @@ begin
|
||||
if sym.Address.Kind = akUnresolved then
|
||||
begin
|
||||
// Distinguish between loading a macro and loading a function.
|
||||
if funcAst is TMacroDefinitionNode then
|
||||
if funcAst.Kind = akMacroDefinition then
|
||||
begin
|
||||
// Macros are stored as raw AST nodes in the scope.
|
||||
FGScope.Define(pair.JsonString.Value, TDataValue.FromIntf<IAstNode>(funcAst));
|
||||
@@ -461,9 +461,9 @@ begin
|
||||
definitions.Add(decl.Identifier.Name, decl.Initializer);
|
||||
end
|
||||
// Handle macro definitions inside the block
|
||||
else if expr is TMacroDefinitionNode then
|
||||
else if expr.Kind = akMacroDefinition then
|
||||
begin
|
||||
var macroDef := expr as TMacroDefinitionNode;
|
||||
var macroDef := expr.AsMacroDefinition;
|
||||
// Store the entire macro definition node for serialization.
|
||||
definitions.Add(macroDef.Name.Name, macroDef);
|
||||
end;
|
||||
@@ -475,9 +475,9 @@ begin
|
||||
definitions.Add(decl.Identifier.Name, decl.Initializer);
|
||||
end
|
||||
// Handle a single macro definition
|
||||
else if rootNode is TMacroDefinitionNode then
|
||||
else if rootNode.Kind = akMacroDefinition then
|
||||
begin
|
||||
var macroDef := rootNode as TMacroDefinitionNode;
|
||||
var macroDef := rootNode.AsMacroDefinition;
|
||||
definitions.Add(macroDef.Name.Name, macroDef);
|
||||
end;
|
||||
|
||||
|
||||
@@ -1809,7 +1809,7 @@ end;
|
||||
|
||||
function TMacroExpansionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
|
||||
begin
|
||||
Result := TAst.MacroExpansionNode(FNode.CallNode, FExpandedBodyNode.CreateAst);
|
||||
Result := TAst.MacroExpansionNode(FNode.CallNode, FExpandedBodyNode.CreateAst.AsTypedNode);
|
||||
end;
|
||||
|
||||
{ TRecurNodeHandler }
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user