ITupleNode signature change
This commit is contained in:
@@ -135,14 +135,14 @@ end;
|
||||
|
||||
function TPurityAnalyzer.VisitTuple(const Node: IAstNode): Boolean;
|
||||
var
|
||||
i: Integer;
|
||||
T: ITupleNode;
|
||||
begin
|
||||
T := Node.AsTuple;
|
||||
// A tuple is pure if ALL its elements are pure.
|
||||
for i := 0 to T.Count - 1 do
|
||||
// Optimization: Use Elements array directly
|
||||
for var item in T.Elements do
|
||||
begin
|
||||
if not IsNodePure(T.Items[i]) then
|
||||
if not IsNodePure(item) then
|
||||
exit(False);
|
||||
end;
|
||||
Result := True;
|
||||
|
||||
@@ -195,7 +195,6 @@ function TUpvalueAnalyzer.VisitLambdaExpression(const Node: IAstNode): IAstNode;
|
||||
var
|
||||
L: ILambdaExpressionNode;
|
||||
i: Integer;
|
||||
paramTuple: ITupleNode;
|
||||
begin
|
||||
L := Node.AsLambdaExpression;
|
||||
|
||||
@@ -205,11 +204,13 @@ begin
|
||||
// 2. Register parameters (they mask outer variables)
|
||||
// We pass 'nil' as the node because we currently don't box parameters,
|
||||
// but we must ensure Resolve() finds them so we don't accidentally box a shadowed variable.
|
||||
paramTuple := L.Parameters;
|
||||
for i := 0 to paramTuple.Count - 1 do
|
||||
|
||||
// Optimized: Access Elements array directly
|
||||
var paramElements := L.Parameters.Elements;
|
||||
for i := 0 to High(paramElements) do
|
||||
begin
|
||||
if paramTuple.Items[i].Kind = akIdentifier then
|
||||
FCurrentScope.Define(paramTuple.Items[i].AsIdentifier.Name, nil);
|
||||
if paramElements[i].Kind = akIdentifier then
|
||||
FCurrentScope.Define(paramElements[i].AsIdentifier.Name, nil);
|
||||
end;
|
||||
|
||||
// 3. Visit Body
|
||||
|
||||
@@ -343,7 +343,6 @@ var
|
||||
startCount: Integer;
|
||||
hasNested: Boolean;
|
||||
paramIdentity: INamedIdentity;
|
||||
paramsTuple: ITupleNode;
|
||||
paramNode: IAstNode;
|
||||
begin
|
||||
L := Node.AsLambdaExpression;
|
||||
@@ -359,12 +358,12 @@ begin
|
||||
try
|
||||
FCurrentBuilder.Define('<self>');
|
||||
|
||||
paramsTuple := L.Parameters;
|
||||
SetLength(newParams, paramsTuple.Count);
|
||||
var paramElements := L.Parameters.Elements;
|
||||
SetLength(newParams, Length(paramElements));
|
||||
|
||||
for i := 0 to paramsTuple.Count - 1 do
|
||||
for i := 0 to High(paramElements) do
|
||||
begin
|
||||
paramNode := paramsTuple.Items[i];
|
||||
paramNode := paramElements[i];
|
||||
|
||||
if paramNode.Kind <> akIdentifier then
|
||||
begin
|
||||
@@ -454,14 +453,15 @@ begin
|
||||
// 1. Keyword as Function Logic
|
||||
if C.Callee.Kind = akKeyword then
|
||||
begin
|
||||
if C.Arguments.Count <> 1 then
|
||||
var args := C.Arguments.Elements;
|
||||
if Length(args) <> 1 then
|
||||
begin
|
||||
if Assigned(FLog) then
|
||||
FLog.AddError(Format('Keyword access :%s requires exactly one argument.', [C.Callee.AsKeyword.Value.Name]), Node);
|
||||
end
|
||||
else
|
||||
begin
|
||||
var memberAccess := TAst.MemberAccess(Node.Identity, Accept(C.Arguments.Items[0]), C.Callee.AsKeyword);
|
||||
var memberAccess := TAst.MemberAccess(Node.Identity, Accept(args[0]), C.Callee.AsKeyword);
|
||||
Result := memberAccess;
|
||||
exit;
|
||||
end;
|
||||
|
||||
@@ -196,9 +196,11 @@ var
|
||||
begin
|
||||
newList := TList<IAstNode>.Create;
|
||||
try
|
||||
for i := 0 to ANodes.Count - 1 do
|
||||
// Optimization: Access Elements array directly
|
||||
var elements := ANodes.Elements;
|
||||
for i := 0 to High(elements) do
|
||||
begin
|
||||
node := ANodes.Items[i];
|
||||
node := elements[i];
|
||||
if node.Kind = akUnquoteSplicing then
|
||||
begin
|
||||
var spliceExpr := node.AsUnquoteSplicing.Expression;
|
||||
@@ -218,15 +220,15 @@ begin
|
||||
// Unification: Lists are now Tuples.
|
||||
if nodeToSplice.Kind = akTuple then
|
||||
begin
|
||||
var tuple := nodeToSplice.AsTuple;
|
||||
for var k := 0 to tuple.Count - 1 do
|
||||
newList.Add(tuple.Items[k]);
|
||||
var tupleElements := nodeToSplice.AsTuple.Elements;
|
||||
for var k := 0 to High(tupleElements) do
|
||||
newList.Add(tupleElements[k]);
|
||||
end
|
||||
else if nodeToSplice.Kind = akBlockExpression then
|
||||
begin
|
||||
var blkTuple := nodeToSplice.AsBlockExpression.Expressions;
|
||||
for var k := 0 to blkTuple.Count - 1 do
|
||||
newList.Add(blkTuple.Items[k]);
|
||||
var blkElements := nodeToSplice.AsBlockExpression.Expressions.Elements;
|
||||
for var k := 0 to High(blkElements) do
|
||||
newList.Add(blkElements[k]);
|
||||
end
|
||||
else
|
||||
begin
|
||||
@@ -290,15 +292,14 @@ var
|
||||
newBody: IAstNode;
|
||||
newName: string;
|
||||
i: Integer;
|
||||
paramsTuple: ITupleNode;
|
||||
begin
|
||||
L := Node.AsLambdaExpression;
|
||||
paramsTuple := L.Parameters;
|
||||
SetLength(newParams, paramsTuple.Count);
|
||||
var paramsElements := L.Parameters.Elements;
|
||||
SetLength(newParams, Length(paramsElements));
|
||||
|
||||
for i := 0 to paramsTuple.Count - 1 do
|
||||
for i := 0 to High(paramsElements) do
|
||||
begin
|
||||
var param := paramsTuple.Items[i].AsIdentifier; // Binder ensures params are Identifiers
|
||||
var param := paramsElements[i].AsIdentifier; // Binder ensures params are Identifiers
|
||||
newName := Gensym(param.Name);
|
||||
newParams[i] := TAst.Identifier(newName, param.Identity.Location);
|
||||
end;
|
||||
@@ -497,16 +498,18 @@ begin
|
||||
if macroDef <> nil then
|
||||
begin
|
||||
var expansionScope := TScope.CreateScope(FInitialScope, nil, nil);
|
||||
var paramsTuple := macroDef.Parameters;
|
||||
var argsTuple := C.Arguments;
|
||||
|
||||
if argsTuple.Count <> paramsTuple.Count then
|
||||
raise EMacroException.CreateFmt('Macro %s expects %d arguments.', [calleeIdentifier.Name, paramsTuple.Count]);
|
||||
// Optimization: Access elements directly
|
||||
var paramsElements := macroDef.Parameters.Elements;
|
||||
var argsElements := C.Arguments.Elements;
|
||||
|
||||
for i := 0 to paramsTuple.Count - 1 do
|
||||
if Length(argsElements) <> Length(paramsElements) then
|
||||
raise EMacroException.CreateFmt('Macro %s expects %d arguments.', [calleeIdentifier.Name, Length(paramsElements)]);
|
||||
|
||||
for i := 0 to High(paramsElements) do
|
||||
begin
|
||||
var paramName := paramsTuple.Items[i].AsIdentifier.Name;
|
||||
expansionScope.Define(paramName, TDataValue.FromIntf<IAstNode>(argsTuple.Items[i]));
|
||||
var paramName := paramsElements[i].AsIdentifier.Name;
|
||||
expansionScope.Define(paramName, TDataValue.FromIntf<IAstNode>(argsElements[i]));
|
||||
end;
|
||||
|
||||
var expandedBody := TExpansionVisitor.Expand(expansionScope, macroDef.Body.AsQuasiquote.Expression, FMacroEvaluator);
|
||||
|
||||
@@ -162,11 +162,14 @@ begin
|
||||
funcName := calleeIdent.Name;
|
||||
|
||||
// 3. Check if all argument types are statically known
|
||||
// Optimization: Use Elements array directly
|
||||
var argsElements := newArgs.Elements;
|
||||
allTypesKnown := True;
|
||||
SetLength(argTypes, newArgs.Count);
|
||||
for i := 0 to newArgs.Count - 1 do
|
||||
SetLength(argTypes, Length(argsElements));
|
||||
|
||||
for i := 0 to High(argsElements) do
|
||||
begin
|
||||
argTypes[i] := newArgs.Items[i].AsTypedNode.StaticType;
|
||||
argTypes[i] := argsElements[i].AsTypedNode.StaticType;
|
||||
if argTypes[i].Kind = stUnknown then
|
||||
begin
|
||||
allTypesKnown := False;
|
||||
|
||||
@@ -123,19 +123,22 @@ var
|
||||
i: Integer;
|
||||
item, newItem: IAstNode;
|
||||
hasChanged: Boolean;
|
||||
elements: TArray<IAstNode>;
|
||||
begin
|
||||
B := Node.AsBlockExpression;
|
||||
isContextTail := FIsTailStack.Peek;
|
||||
exprsTuple := B.Expressions;
|
||||
elements := exprsTuple.Elements;
|
||||
|
||||
SetLength(newExprs, exprsTuple.Count);
|
||||
var count := Length(elements);
|
||||
SetLength(newExprs, count);
|
||||
hasChanged := False;
|
||||
|
||||
var nTail := exprsTuple.Count - 1;
|
||||
var nTail := count - 1;
|
||||
|
||||
for i := 0 to nTail do
|
||||
begin
|
||||
item := exprsTuple.Items[i];
|
||||
item := elements[i];
|
||||
|
||||
// Only the last expression in the block inherits the tail position status
|
||||
FNextIsTail := isContextTail and (i = nTail);
|
||||
@@ -150,8 +153,10 @@ begin
|
||||
if not hasChanged then
|
||||
Result := Node
|
||||
else
|
||||
begin
|
||||
// Create new Tuple for expressions
|
||||
Result := TAst.Block(Node.Identity, TAst.Tuple(B.Expressions.Identity, newExprs), B.StaticType);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TAstTCO.VisitIfExpression(const Node: IAstNode): IAstNode;
|
||||
@@ -324,6 +329,7 @@ var
|
||||
i: Integer;
|
||||
hasChanged: Boolean;
|
||||
savedNextIsTail: Boolean;
|
||||
elements: TArray<IAstNode>;
|
||||
begin
|
||||
T := Node.AsTuple;
|
||||
savedNextIsTail := FNextIsTail; // Zustand sichern
|
||||
@@ -332,13 +338,15 @@ begin
|
||||
FNextIsTail := False;
|
||||
|
||||
hasChanged := False;
|
||||
SetLength(newElements, T.Count);
|
||||
elements := T.Elements;
|
||||
var count := Length(elements);
|
||||
SetLength(newElements, count);
|
||||
|
||||
try
|
||||
for i := 0 to T.Count - 1 do
|
||||
for i := 0 to count - 1 do
|
||||
begin
|
||||
newElements[i] := Accept(T.Items[i]);
|
||||
if newElements[i] <> T.Items[i] then
|
||||
newElements[i] := Accept(elements[i]);
|
||||
if newElements[i] <> elements[i] then
|
||||
hasChanged := True;
|
||||
end;
|
||||
finally
|
||||
|
||||
@@ -314,9 +314,11 @@ var
|
||||
newDim: TArray<Integer>;
|
||||
|
||||
finalType: IStaticType;
|
||||
elementsArray: TArray<IAstNode>;
|
||||
begin
|
||||
T := Node.AsTuple;
|
||||
var count := T.Count;
|
||||
elementsArray := T.Elements;
|
||||
var count := Length(elementsArray);
|
||||
|
||||
SetLength(newElements, count);
|
||||
SetLength(elementTypes, count);
|
||||
@@ -325,7 +327,7 @@ begin
|
||||
// Recursively type-check all elements first to determine their static types.
|
||||
for i := 0 to count - 1 do
|
||||
begin
|
||||
newElements[i] := Accept(T.Items[i]);
|
||||
newElements[i] := Accept(elementsArray[i]);
|
||||
if newElements[i].IsTyped then
|
||||
elementTypes[i] := newElements[i].AsTypedNode.StaticType
|
||||
else
|
||||
@@ -503,8 +505,7 @@ function TTypeChecker.VisitBlockExpression(const Node: IAstNode): IAstNode;
|
||||
var
|
||||
newBlock: IBlockExpressionNode;
|
||||
blockType: IStaticType;
|
||||
exprs: ITupleNode;
|
||||
i: Integer;
|
||||
exprs: TArray<IAstNode>;
|
||||
begin
|
||||
var transformedNode := inherited VisitBlockExpression(Node);
|
||||
|
||||
@@ -512,30 +513,25 @@ begin
|
||||
raise ECompilationFailed.Create([TCompilerError.Create(elError, 'Internal Error: Block transformation returned nil.', Node)]);
|
||||
|
||||
newBlock := transformedNode.AsBlockExpression;
|
||||
exprs := newBlock.Expressions;
|
||||
exprs := newBlock.Expressions.Elements;
|
||||
|
||||
if exprs.Count > 0 then
|
||||
if Length(exprs) > 0 then
|
||||
begin
|
||||
for i := 0 to exprs.Count - 1 do
|
||||
begin
|
||||
if exprs.Items[i] = nil then
|
||||
raise ECompilationFailed.Create(
|
||||
[TCompilerError.Create(elError, Format('Internal Error: Block expression #%d transformed to nil.', [i]), Node)]);
|
||||
end;
|
||||
blockType := exprs.Items[exprs.Count - 1].AsTypedNode.StaticType;
|
||||
// The type of the block is the type of the last expression
|
||||
blockType := exprs[High(exprs)].AsTypedNode.StaticType;
|
||||
end
|
||||
else
|
||||
begin
|
||||
blockType := TTypes.Void;
|
||||
end;
|
||||
|
||||
Result := TAst.Block(Node.Identity, exprs, blockType);
|
||||
Result := TAst.Block(Node.Identity, newBlock.Expressions, blockType);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitLambdaExpression(const Node: IAstNode): IAstNode;
|
||||
var
|
||||
L: ILambdaExpressionNode;
|
||||
newParams: TArray<IIdentifierNode>;
|
||||
newParams: TArray<IAstNode>;
|
||||
newBody: IAstNode;
|
||||
bodyType, methodType: IStaticType;
|
||||
paramTypes: TArray<IStaticType>;
|
||||
@@ -545,7 +541,7 @@ var
|
||||
paramIdent: IIdentifierNode;
|
||||
injectedType: IStaticType;
|
||||
paramsTuple: ITupleNode;
|
||||
paramsAsNodes: TArray<IAstNode>;
|
||||
paramsElements: TArray<IAstNode>;
|
||||
begin
|
||||
L := Node.AsLambdaExpression;
|
||||
|
||||
@@ -566,12 +562,13 @@ begin
|
||||
FCurrentContext := TTypeContext.Create(FCurrentContext, L.Layout, upvalueTypes, nil);
|
||||
try
|
||||
paramsTuple := L.Parameters;
|
||||
SetLength(newParams, paramsTuple.Count);
|
||||
SetLength(paramTypes, paramsTuple.Count);
|
||||
paramsElements := paramsTuple.Elements;
|
||||
SetLength(newParams, Length(paramsElements));
|
||||
SetLength(paramTypes, Length(paramsElements));
|
||||
|
||||
for i := 0 to paramsTuple.Count - 1 do
|
||||
for i := 0 to High(paramsElements) do
|
||||
begin
|
||||
paramIdent := paramsTuple.Items[i].AsIdentifier;
|
||||
paramIdent := paramsElements[i].AsIdentifier;
|
||||
injectedType := paramIdent.AsTypedNode.StaticType;
|
||||
|
||||
if injectedType.Kind = stUnknown then
|
||||
@@ -597,11 +594,7 @@ begin
|
||||
temp.Free;
|
||||
end;
|
||||
|
||||
SetLength(paramsAsNodes, Length(newParams));
|
||||
for i := 0 to High(newParams) do
|
||||
paramsAsNodes[i] := newParams[i];
|
||||
|
||||
var paramList := TAst.Tuple(L.Parameters.Identity, paramsAsNodes);
|
||||
var paramList := TAst.Tuple(L.Parameters.Identity, newParams);
|
||||
|
||||
Result :=
|
||||
TAst.LambdaExpr(Node.Identity, paramList, newBody, L.Layout, finalDescriptor, L.Upvalues, L.HasNestedLambdas, L.IsPure, methodType);
|
||||
@@ -617,17 +610,19 @@ var
|
||||
bestSig: IMethodSignature;
|
||||
match: Boolean;
|
||||
newArgs: ITupleNode;
|
||||
argsElements: TArray<IAstNode>;
|
||||
begin
|
||||
newCall := inherited VisitFunctionCall(Node).AsFunctionCall;
|
||||
var newCallee := newCall.Callee;
|
||||
newArgs := newCall.Arguments;
|
||||
argsElements := newArgs.Elements;
|
||||
|
||||
SetLength(argTypes, newArgs.Count);
|
||||
SetLength(argTypes, Length(argsElements));
|
||||
hasUnknownArgs := False;
|
||||
|
||||
for i := 0 to newArgs.Count - 1 do
|
||||
for i := 0 to High(argsElements) do
|
||||
begin
|
||||
argTypes[i] := newArgs.Items[i].AsTypedNode.StaticType;
|
||||
argTypes[i] := argsElements[i].AsTypedNode.StaticType;
|
||||
if argTypes[i].Kind = stUnknown then
|
||||
hasUnknownArgs := True;
|
||||
end;
|
||||
@@ -761,18 +756,20 @@ var
|
||||
valType: IStaticType;
|
||||
key: IKeyword;
|
||||
newFields: ITupleNode;
|
||||
fieldsElements: TArray<IAstNode>;
|
||||
begin
|
||||
R := Node.AsRecordLiteral;
|
||||
newFields := Visit(R.Fields).AsTuple;
|
||||
fieldsElements := newFields.Elements;
|
||||
|
||||
var count := newFields.Count;
|
||||
var count := Length(fieldsElements);
|
||||
SetLength(fieldTypes, count);
|
||||
SetLength(scalarFieldTypes, count);
|
||||
isScalar := True;
|
||||
|
||||
for i := 0 to count - 1 do
|
||||
begin
|
||||
var field := newFields.Items[i].AsRecordField;
|
||||
var field := fieldsElements[i].AsRecordField;
|
||||
key := field.Key.Value;
|
||||
valType := field.Value.AsTypedNode.StaticType;
|
||||
|
||||
@@ -865,17 +862,22 @@ var
|
||||
selectorsNode: ITupleNode;
|
||||
newSelectors: TList<IAstNode>;
|
||||
streamType: IStaticType;
|
||||
rawInputsElements: TArray<IAstNode>;
|
||||
rawTupleElements: TArray<IAstNode>;
|
||||
selectorsElements: TArray<IAstNode>;
|
||||
lambdaParamsElements: TArray<IAstNode>;
|
||||
begin
|
||||
P := Node.AsPipe;
|
||||
rawInputs := P.Inputs; // This is the Tuple of Tuples [[id [sel]] ...]
|
||||
rawInputsElements := rawInputs.Elements;
|
||||
|
||||
newInputs := TList<IAstNode>.Create;
|
||||
paramTypes := TList<IStaticType>.Create;
|
||||
try
|
||||
// 1. Iterate over input definitions
|
||||
for i := 0 to rawInputs.Count - 1 do
|
||||
for i := 0 to High(rawInputsElements) do
|
||||
begin
|
||||
inputPair := rawInputs.Items[i];
|
||||
inputPair := rawInputsElements[i];
|
||||
|
||||
// Validate Structure: [StreamSource, [Selectors]]
|
||||
if inputPair.Kind <> akTuple then
|
||||
@@ -886,7 +888,9 @@ begin
|
||||
end;
|
||||
|
||||
rawTuple := inputPair.AsTuple;
|
||||
if rawTuple.Count <> 2 then
|
||||
rawTupleElements := rawTuple.Elements;
|
||||
|
||||
if Length(rawTupleElements) <> 2 then
|
||||
begin
|
||||
if Assigned(FLog) then
|
||||
FLog.AddError('Pipe input vector must have exactly 2 elements.', inputPair);
|
||||
@@ -894,15 +898,15 @@ begin
|
||||
end;
|
||||
|
||||
// Element 0: Stream Identifier
|
||||
if rawTuple.Items[0].Kind <> akIdentifier then
|
||||
if rawTupleElements[0].Kind <> akIdentifier then
|
||||
begin
|
||||
if Assigned(FLog) then
|
||||
FLog.AddError('Pipe source must be an identifier.', rawTuple.Items[0]);
|
||||
FLog.AddError('Pipe source must be an identifier.', rawTupleElements[0]);
|
||||
continue;
|
||||
end;
|
||||
|
||||
// Resolve Stream Identifier (Type Binding)
|
||||
streamNode := Accept(rawTuple.Items[0]).AsIdentifier;
|
||||
streamNode := Accept(rawTupleElements[0]).AsIdentifier;
|
||||
streamType := streamNode.StaticType;
|
||||
|
||||
// Validate Stream Type
|
||||
@@ -919,19 +923,21 @@ begin
|
||||
end;
|
||||
|
||||
// Element 1: Selector Vector
|
||||
if rawTuple.Items[1].Kind <> akTuple then
|
||||
if rawTupleElements[1].Kind <> akTuple then
|
||||
begin
|
||||
if Assigned(FLog) then
|
||||
FLog.AddError('Pipe selectors must be a vector of keywords.', rawTuple.Items[1]);
|
||||
FLog.AddError('Pipe selectors must be a vector of keywords.', rawTupleElements[1]);
|
||||
continue;
|
||||
end;
|
||||
selectorsNode := rawTuple.Items[1].AsTuple;
|
||||
selectorsNode := rawTupleElements[1].AsTuple;
|
||||
selectorsElements := selectorsNode.Elements;
|
||||
|
||||
newSelectors := TList<IAstNode>.Create;
|
||||
try
|
||||
// Iterate Selectors
|
||||
for k := 0 to selectorsNode.Count - 1 do
|
||||
for k := 0 to High(selectorsElements) do
|
||||
begin
|
||||
var selItem := selectorsNode.Items[k];
|
||||
var selItem := selectorsElements[k];
|
||||
if selItem.Kind <> akKeyword then
|
||||
begin
|
||||
if Assigned(FLog) then
|
||||
@@ -974,23 +980,24 @@ begin
|
||||
|
||||
// 2. Process Transformation Lambda
|
||||
lambda := P.Transformation;
|
||||
lambdaParamsElements := lambda.Parameters.Elements;
|
||||
|
||||
if lambda.Parameters.Count <> paramTypes.Count then
|
||||
if Length(lambdaParamsElements) <> paramTypes.Count then
|
||||
begin
|
||||
if Assigned(FLog) then
|
||||
FLog.AddError(
|
||||
Format(
|
||||
'Pipe lambda expects %d parameters (one per selector), but got %d.',
|
||||
[paramTypes.Count, lambda.Parameters.Count]
|
||||
[paramTypes.Count, Length(lambdaParamsElements)]
|
||||
),
|
||||
lambda
|
||||
);
|
||||
end;
|
||||
|
||||
SetLength(newParams, lambda.Parameters.Count);
|
||||
for k := 0 to lambda.Parameters.Count - 1 do
|
||||
SetLength(newParams, Length(lambdaParamsElements));
|
||||
for k := 0 to High(lambdaParamsElements) do
|
||||
begin
|
||||
var oldP := lambda.Parameters.Items[k].AsIdentifier;
|
||||
var oldP := lambdaParamsElements[k].AsIdentifier;
|
||||
var typeToInject :=
|
||||
if k < paramTypes.Count then paramTypes[k]
|
||||
else TTypes.Unknown;
|
||||
|
||||
@@ -300,9 +300,11 @@ var
|
||||
argTypes: TArray<string>;
|
||||
i: Integer;
|
||||
args: ITupleNode;
|
||||
argsElements: TArray<IAstNode>;
|
||||
begin
|
||||
C := Node.AsFunctionCall;
|
||||
args := C.Arguments;
|
||||
argsElements := args.Elements;
|
||||
|
||||
LogFmt(
|
||||
'FunctionCall (IsTailCall: %s, StaticTarget: %s, IsTargetPure: %s)',
|
||||
@@ -317,11 +319,11 @@ begin
|
||||
if Assigned(C.StaticTarget) then
|
||||
begin
|
||||
Indent;
|
||||
SetLength(argTypes, args.Count);
|
||||
for i := 0 to args.Count - 1 do
|
||||
SetLength(argTypes, Length(argsElements));
|
||||
for i := 0 to High(argsElements) do
|
||||
begin
|
||||
if args.Items[i].IsTyped then
|
||||
argTypes[i] := args.Items[i].AsTypedNode.StaticType.ToString
|
||||
if argsElements[i].IsTyped then
|
||||
argTypes[i] := argsElements[i].AsTypedNode.StaticType.ToString
|
||||
else
|
||||
argTypes[i] := 'Untyped';
|
||||
end;
|
||||
@@ -332,7 +334,7 @@ begin
|
||||
Indent;
|
||||
Log('Callee:');
|
||||
Visit(C.Callee);
|
||||
LogFmt('Arguments (%d):', [args.Count]);
|
||||
LogFmt('Arguments (%d):', [Length(argsElements)]);
|
||||
Visit(args);
|
||||
Unindent;
|
||||
end;
|
||||
@@ -469,7 +471,7 @@ var
|
||||
R: IRecordLiteralNode;
|
||||
begin
|
||||
R := Node.AsRecordLiteral;
|
||||
LogFmt('RecordLiteral (%d fields)', [R.Fields.Count], Node);
|
||||
LogFmt('RecordLiteral (%d fields)', [Length(R.Fields.Elements)], Node);
|
||||
Indent;
|
||||
Visit(R.Fields);
|
||||
Unindent;
|
||||
@@ -527,15 +529,17 @@ function TAstDumper.VisitTuple(const Node: IAstNode): TVoid;
|
||||
var
|
||||
T: ITupleNode;
|
||||
i: Integer;
|
||||
elements: TArray<IAstNode>;
|
||||
begin
|
||||
T := Node.AsTuple;
|
||||
LogFmt('Tuple (%d elements)', [T.Count], Node);
|
||||
elements := T.Elements;
|
||||
LogFmt('Tuple (%d elements)', [Length(elements)], Node);
|
||||
Indent;
|
||||
for i := 0 to T.Count - 1 do
|
||||
for i := 0 to High(elements) do
|
||||
begin
|
||||
LogFmt('Item %d:', [i]);
|
||||
Indent;
|
||||
Visit(T.Items[i]);
|
||||
Visit(elements[i]);
|
||||
Unindent;
|
||||
end;
|
||||
Unindent;
|
||||
|
||||
@@ -179,10 +179,12 @@ function TEvaluatorVisitor.VisitTuple(const N: ITupleNode): TDataValue;
|
||||
var
|
||||
elements: TArray<TDataValue>;
|
||||
i: Integer;
|
||||
astElements: TArray<IAstNode>;
|
||||
begin
|
||||
SetLength(elements, N.Count);
|
||||
for i := 0 to N.Count - 1 do
|
||||
elements[i] := Visit(N.Items[i]);
|
||||
astElements := N.Elements;
|
||||
SetLength(elements, Length(astElements));
|
||||
for i := 0 to High(astElements) do
|
||||
elements[i] := Visit(astElements[i]);
|
||||
|
||||
// Uses the implicit operator: TArray<TDataValue> -> TDataValue (vkTuple)
|
||||
Result := elements;
|
||||
@@ -194,6 +196,7 @@ var
|
||||
i: Integer;
|
||||
closureScope: IExecutionScope;
|
||||
visitorFactory: TEvaluatorFactory;
|
||||
paramsElements: TArray<IAstNode>;
|
||||
begin
|
||||
if Length(N.Upvalues) > 0 then
|
||||
begin
|
||||
@@ -210,7 +213,7 @@ begin
|
||||
visitorFactory := CreateVisitorFactory();
|
||||
|
||||
var descriptor := N.Descriptor;
|
||||
var params := N.Parameters;
|
||||
paramsElements := N.Parameters.Elements;
|
||||
|
||||
var [unsafe] closure: TDataValue.TFunc;
|
||||
closure :=
|
||||
@@ -220,17 +223,17 @@ begin
|
||||
bodyVisitor: IAstVisitor;
|
||||
k: Integer;
|
||||
begin
|
||||
if (Length(ArgValues) <> params.Count) then
|
||||
if (Length(ArgValues) <> Length(paramsElements)) then
|
||||
raise EEvaluatorException.Create('Arg mismatch');
|
||||
lambdaScope := TScope.CreateScope(closureScope, descriptor, capturedCells);
|
||||
|
||||
// Self-reference for recursion (Slot 0)
|
||||
lambdaScope.SetValues(TResolvedAddress.Create(akLocalOrParent, 0, 0), TDataValue(closure));
|
||||
|
||||
for k := 0 to params.Count - 1 do
|
||||
for k := 0 to High(paramsElements) do
|
||||
begin
|
||||
// Parameters are guaranteed to be Identifiers by the Binder
|
||||
var paramNode := params.Items[k].AsIdentifier;
|
||||
var paramNode := paramsElements[k].AsIdentifier;
|
||||
lambdaScope[paramNode.Address] := ArgValues[k];
|
||||
end;
|
||||
|
||||
@@ -245,12 +248,12 @@ var
|
||||
calleeValue: TDataValue;
|
||||
argValues: TArray<TDataValue>;
|
||||
i: Integer;
|
||||
argsTuple: ITupleNode;
|
||||
argsElements: TArray<IAstNode>;
|
||||
begin
|
||||
argsTuple := N.Arguments;
|
||||
SetLength(argValues, argsTuple.Count);
|
||||
for i := 0 to argsTuple.Count - 1 do
|
||||
argValues[i] := Visit(argsTuple.Items[i]);
|
||||
argsElements := N.Arguments.Elements;
|
||||
SetLength(argValues, Length(argsElements));
|
||||
for i := 0 to High(argsElements) do
|
||||
argValues[i] := Visit(argsElements[i]);
|
||||
|
||||
if Assigned(N.StaticTarget) then
|
||||
begin
|
||||
@@ -278,12 +281,12 @@ function TEvaluatorVisitor.VisitRecurNode(const N: IRecurNode): TDataValue;
|
||||
var
|
||||
argValues: TArray<TDataValue>;
|
||||
i: Integer;
|
||||
argsTuple: ITupleNode;
|
||||
argsElements: TArray<IAstNode>;
|
||||
begin
|
||||
argsTuple := N.Arguments;
|
||||
SetLength(argValues, argsTuple.Count);
|
||||
for i := 0 to argsTuple.Count - 1 do
|
||||
argValues[i] := Visit(argsTuple.Items[i]);
|
||||
argsElements := N.Arguments.Elements;
|
||||
SetLength(argValues, Length(argsElements));
|
||||
for i := 0 to High(argsElements) do
|
||||
argValues[i] := Visit(argsElements[i]);
|
||||
|
||||
// The "self" function is always at Slot 0
|
||||
var callee := FScope[TResolvedAddress.Create(akLocalOrParent, 0, 0)];
|
||||
@@ -292,13 +295,13 @@ end;
|
||||
|
||||
function TEvaluatorVisitor.VisitBlockExpression(const N: IBlockExpressionNode): TDataValue;
|
||||
var
|
||||
exprs: ITupleNode;
|
||||
exprs: TArray<IAstNode>;
|
||||
i: Integer;
|
||||
begin
|
||||
exprs := N.Expressions;
|
||||
exprs := N.Expressions.Elements;
|
||||
Result := TDataValue.Void;
|
||||
for i := 0 to exprs.Count - 1 do
|
||||
Result := Visit(exprs.Items[i]);
|
||||
for i := 0 to High(exprs) do
|
||||
Result := Visit(exprs[i]);
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitIfExpression(const N: IIfExpressionNode): TDataValue;
|
||||
@@ -397,16 +400,16 @@ end;
|
||||
function TEvaluatorVisitor.VisitRecordLiteral(const N: IRecordLiteralNode): TDataValue;
|
||||
var
|
||||
i: Integer;
|
||||
fieldsTuple: ITupleNode;
|
||||
fieldsElements: TArray<IAstNode>;
|
||||
begin
|
||||
fieldsElements := N.Fields.Elements;
|
||||
if Assigned(N.ScalarDefinition) then
|
||||
begin
|
||||
var vals: TArray<TScalar.TValue>;
|
||||
fieldsTuple := N.Fields;
|
||||
SetLength(vals, fieldsTuple.Count);
|
||||
for i := 0 to fieldsTuple.Count - 1 do
|
||||
SetLength(vals, Length(fieldsElements));
|
||||
for i := 0 to High(fieldsElements) do
|
||||
begin
|
||||
var field := fieldsTuple.Items[i].AsRecordField;
|
||||
var field := fieldsElements[i].AsRecordField;
|
||||
vals[i] := Visit(field.Value).AsScalar.Value;
|
||||
end;
|
||||
Result := TScalarRecord.Create(N.ScalarDefinition, vals);
|
||||
@@ -414,11 +417,10 @@ begin
|
||||
else
|
||||
begin
|
||||
var fields: TArray<TPair<IKeyword, TDataValue>>;
|
||||
fieldsTuple := N.Fields;
|
||||
SetLength(fields, fieldsTuple.Count);
|
||||
for i := 0 to fieldsTuple.Count - 1 do
|
||||
SetLength(fields, Length(fieldsElements));
|
||||
for i := 0 to High(fieldsElements) do
|
||||
begin
|
||||
var field := fieldsTuple.Items[i].AsRecordField;
|
||||
var field := fieldsElements[i].AsRecordField;
|
||||
fields[i] := TPair<IKeyword, TDataValue>.Create(field.Key.Value, Visit(field.Value));
|
||||
end;
|
||||
Result := TGenericRecord<TDataValue>.Create(fields);
|
||||
@@ -460,24 +462,26 @@ var
|
||||
sourceSeries: IScalarRecordSeries;
|
||||
lambdaFunc: TDataValue.TFunc;
|
||||
|
||||
inputsTuple: ITupleNode;
|
||||
inputsElements: TArray<IAstNode>;
|
||||
entryTuple: ITupleNode;
|
||||
entryElements: TArray<IAstNode>;
|
||||
sourceId: IIdentifierNode;
|
||||
selectorsTuple: ITupleNode;
|
||||
selectorsElements: TArray<IAstNode>;
|
||||
begin
|
||||
inputsTuple := N.Inputs;
|
||||
inputsElements := N.Inputs.Elements;
|
||||
|
||||
SetLength(sources, inputsTuple.Count);
|
||||
SetLength(config, inputsTuple.Count);
|
||||
SetLength(sources, Length(inputsElements));
|
||||
SetLength(config, Length(inputsElements));
|
||||
|
||||
for i := 0 to inputsTuple.Count - 1 do
|
||||
for i := 0 to High(inputsElements) do
|
||||
begin
|
||||
// Unpack: [Source, [Selectors]]
|
||||
// Note: Structure is guaranteed by TypeChecker
|
||||
entryTuple := inputsTuple.Items[i].AsTuple;
|
||||
entryTuple := inputsElements[i].AsTuple;
|
||||
entryElements := entryTuple.Elements;
|
||||
|
||||
sourceId := entryTuple.Items[0].AsIdentifier;
|
||||
selectorsTuple := entryTuple.Items[1].AsTuple;
|
||||
sourceId := entryElements[0].AsIdentifier;
|
||||
selectorsElements := entryElements[1].AsTuple.Elements;
|
||||
|
||||
// Resolve Source Stream from Scope
|
||||
// The Binder has already linked sourceId to its variable address
|
||||
@@ -491,10 +495,10 @@ begin
|
||||
var srcDef := sourceSeries.Def;
|
||||
|
||||
// Build Selectors Config
|
||||
SetLength(config[i], selectorsTuple.Count);
|
||||
for var k := 0 to selectorsTuple.Count - 1 do
|
||||
SetLength(config[i], Length(selectorsElements));
|
||||
for var k := 0 to High(selectorsElements) do
|
||||
begin
|
||||
var key := selectorsTuple.Items[k].AsKeyword.Value;
|
||||
var key := selectorsElements[k].AsKeyword.Value;
|
||||
var idx := srcDef.IndexOf(key);
|
||||
// Index check already done in TypeChecker, but good for safety
|
||||
if idx < 0 then
|
||||
|
||||
@@ -202,13 +202,18 @@ var
|
||||
T: ITupleNode;
|
||||
elemsArray: TJSONArray;
|
||||
i: Integer;
|
||||
elements: TArray<IAstNode>;
|
||||
begin
|
||||
T := Node.AsTuple;
|
||||
Result := TJSONObject.Create;
|
||||
Result.AddPair('NodeType', TJSONString.Create('Tuple'));
|
||||
elemsArray := TJSONArray.Create;
|
||||
for i := 0 to T.Count - 1 do
|
||||
elemsArray.Add(Visit(T.Items[i]));
|
||||
|
||||
// Updated: Use Elements array directly
|
||||
elements := T.Elements;
|
||||
for i := 0 to High(elements) do
|
||||
elemsArray.Add(Visit(elements[i]));
|
||||
|
||||
Result.AddPair('Elements', elemsArray);
|
||||
end;
|
||||
|
||||
@@ -611,7 +616,8 @@ var
|
||||
begin
|
||||
identNodes := TList<IIdentifierNode>.Create;
|
||||
try
|
||||
for node in JsonToNode(AObj.GetValue('Parameters')).AsTuple.ToArray do
|
||||
// Updated: Use Elements instead of ToArray (or iterate if ToArray is missing)
|
||||
for node in JsonToNode(AObj.GetValue('Parameters')).AsTuple.Elements do
|
||||
identNodes.Add(node.AsIdentifier);
|
||||
Result := TAst.LambdaExpr(identNodes.ToArray, JsonToNode(AObj.GetValue('Body')));
|
||||
finally
|
||||
@@ -626,7 +632,8 @@ var
|
||||
begin
|
||||
identNodes := TList<IIdentifierNode>.Create;
|
||||
try
|
||||
for node in JsonToNode(AObj.GetValue('Parameters')).AsTuple.ToArray do
|
||||
// Updated: Use Elements
|
||||
for node in JsonToNode(AObj.GetValue('Parameters')).AsTuple.Elements do
|
||||
identNodes.Add(node.AsIdentifier);
|
||||
Result :=
|
||||
TAst.MacroDef(
|
||||
@@ -656,7 +663,8 @@ end;
|
||||
|
||||
function TJsonAstConverter.JsonToFunctionCallNode(const AObj: TJSONObject): IFunctionCallNode;
|
||||
begin
|
||||
Result := TAst.FunctionCall(JsonToNode(AObj.GetValue('Callee')), JsonToNode(AObj.GetValue('Arguments')).AsTuple.ToArray);
|
||||
// Updated: Use Elements
|
||||
Result := TAst.FunctionCall(JsonToNode(AObj.GetValue('Callee')), JsonToNode(AObj.GetValue('Arguments')).AsTuple.Elements);
|
||||
end;
|
||||
|
||||
function TJsonAstConverter.JsonToMacroExpansionNode(const AObj: TJSONObject): IMacroExpansionNode;
|
||||
@@ -667,17 +675,20 @@ begin
|
||||
callee := JsonToNode(AObj.GetValue('Callee'));
|
||||
expandedBody := JsonToNode(AObj.GetValue('ExpandedBody'));
|
||||
argsTuple := JsonToNode(AObj.GetValue('Arguments')).AsTuple;
|
||||
Result := TAst.MacroExpansionNode(TAst.FunctionCall(callee, argsTuple.ToArray), expandedBody);
|
||||
// Updated: Use Elements
|
||||
Result := TAst.MacroExpansionNode(TAst.FunctionCall(callee, argsTuple.Elements), expandedBody);
|
||||
end;
|
||||
|
||||
function TJsonAstConverter.JsonToRecurNode(const AObj: TJSONObject): IRecurNode;
|
||||
begin
|
||||
Result := TAst.Recur(JsonToNode(AObj.GetValue('Arguments')).AsTuple.ToArray);
|
||||
// Updated: Use Elements
|
||||
Result := TAst.Recur(JsonToNode(AObj.GetValue('Arguments')).AsTuple.Elements);
|
||||
end;
|
||||
|
||||
function TJsonAstConverter.JsonToBlockNode(const AObj: TJSONObject): IBlockExpressionNode;
|
||||
begin
|
||||
Result := TAst.Block(JsonToNode(AObj.GetValue('Expressions')).AsTuple.ToArray);
|
||||
// Updated: Use Elements
|
||||
Result := TAst.Block(JsonToNode(AObj.GetValue('Expressions')).AsTuple.Elements);
|
||||
end;
|
||||
|
||||
function TJsonAstConverter.JsonToVarDeclNode(const AObj: TJSONObject): IVariableDeclarationNode;
|
||||
|
||||
@@ -263,12 +263,9 @@ type
|
||||
|
||||
ITupleNode = interface(IAstTypedNode)
|
||||
{$region 'private'}
|
||||
function GetCount: Integer;
|
||||
function GetItems(Idx: Integer): IAstNode;
|
||||
function GetElements: TArray<IAstNode>;
|
||||
{$endregion}
|
||||
function ToArray: TArray<IAstNode>;
|
||||
property Count: Integer read GetCount;
|
||||
property Items[Idx: Integer]: IAstNode read GetItems; default;
|
||||
property Elements: TArray<IAstNode> read GetElements;
|
||||
end;
|
||||
|
||||
IIfExpressionNode = interface(IAstTypedNode)
|
||||
@@ -582,11 +579,9 @@ type
|
||||
TTupleNode = class(TAstTypedNode, ITupleNode)
|
||||
private
|
||||
FElements: TArray<IAstNode>;
|
||||
function GetCount: Integer;
|
||||
function GetItems(Idx: Integer): IAstNode;
|
||||
function GetElements: TArray<IAstNode>;
|
||||
protected
|
||||
function GetKind: TAstNodeKind; override;
|
||||
function ToArray: TArray<IAstNode>;
|
||||
public
|
||||
constructor Create(const AElements: TArray<IAstNode>; const AIdentity: IAstIdentity; const AStaticType: IStaticType);
|
||||
function AsTuple: ITupleNode; override;
|
||||
@@ -1372,14 +1367,9 @@ begin
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function TTupleNode.GetCount: Integer;
|
||||
function TTupleNode.GetElements: TArray<IAstNode>;
|
||||
begin
|
||||
Result := Length(FElements);
|
||||
end;
|
||||
|
||||
function TTupleNode.GetItems(Idx: Integer): IAstNode;
|
||||
begin
|
||||
Result := FElements[Idx];
|
||||
Result := FElements;
|
||||
end;
|
||||
|
||||
function TTupleNode.GetKind: TAstNodeKind;
|
||||
@@ -1387,11 +1377,6 @@ begin
|
||||
Result := akTuple;
|
||||
end;
|
||||
|
||||
function TTupleNode.ToArray: TArray<IAstNode>;
|
||||
begin
|
||||
Result := FElements;
|
||||
end;
|
||||
|
||||
{ TCreateSeriesNode }
|
||||
|
||||
constructor TCreateSeriesNode.Create(const AIdentity: IDefinitionIdentity; const AStaticType: IStaticType);
|
||||
|
||||
@@ -127,12 +127,14 @@ var
|
||||
i: Integer;
|
||||
item, transformed: IAstNode;
|
||||
list: TList<IAstNode>;
|
||||
elements: TArray<IAstNode>;
|
||||
begin
|
||||
list := TList<IAstNode>.Create;
|
||||
try
|
||||
for i := 0 to Source.Count - 1 do
|
||||
elements := Source.Elements;
|
||||
for i := 0 to High(elements) do
|
||||
begin
|
||||
item := Source.Items[i];
|
||||
item := elements[i];
|
||||
transformed := Accept(item);
|
||||
if Assigned(transformed) then
|
||||
list.Add(transformed);
|
||||
@@ -335,14 +337,16 @@ var
|
||||
item, transformed: IAstNode;
|
||||
i: Integer;
|
||||
hasChanged: Boolean;
|
||||
elements: TArray<IAstNode>;
|
||||
begin
|
||||
T := Node.AsTuple;
|
||||
list := TList<IAstNode>.Create;
|
||||
hasChanged := False;
|
||||
try
|
||||
for i := 0 to T.Count - 1 do
|
||||
elements := T.Elements;
|
||||
for i := 0 to High(elements) do
|
||||
begin
|
||||
item := T.Items[i];
|
||||
item := elements[i];
|
||||
transformed := Accept(item);
|
||||
|
||||
if transformed <> item then
|
||||
|
||||
@@ -198,12 +198,13 @@ var
|
||||
i: Integer;
|
||||
begin
|
||||
T := N.AsTuple;
|
||||
var elements := T.Elements;
|
||||
Append('[');
|
||||
for i := 0 to T.Count - 1 do
|
||||
for i := 0 to High(elements) do
|
||||
begin
|
||||
if i > 0 then
|
||||
Append(' ');
|
||||
Visit(T.Items[i]);
|
||||
Visit(elements[i]);
|
||||
end;
|
||||
Append(']');
|
||||
end;
|
||||
@@ -315,26 +316,25 @@ function TPrettyPrintVisitor.VisitFunctionCall(const N: IAstNode): TVoid;
|
||||
var
|
||||
C: IFunctionCallNode;
|
||||
i: Integer;
|
||||
args: ITupleNode;
|
||||
begin
|
||||
C := N.AsFunctionCall;
|
||||
args := C.Arguments;
|
||||
var args := C.Arguments.Elements;
|
||||
|
||||
// Special case for 'quote'
|
||||
if (C.Callee.Kind = akIdentifier) and (C.Callee.AsIdentifier.Name = 'quote') and (args.Count = 1) then
|
||||
if (C.Callee.Kind = akIdentifier) and (C.Callee.AsIdentifier.Name = 'quote') and (Length(args) = 1) then
|
||||
begin
|
||||
Append('''');
|
||||
Visit(args.Items[0]);
|
||||
Visit(args[0]);
|
||||
exit;
|
||||
end;
|
||||
|
||||
Append('(');
|
||||
Visit(C.Callee);
|
||||
// Manually iterate arguments tuple to avoid printing [...] inside ()
|
||||
for i := 0 to args.Count - 1 do
|
||||
for i := 0 to High(args) do
|
||||
begin
|
||||
Append(' ');
|
||||
Visit(args.Items[i]);
|
||||
Visit(args[i]);
|
||||
end;
|
||||
Append(')');
|
||||
end;
|
||||
@@ -348,16 +348,15 @@ function TPrettyPrintVisitor.VisitRecurNode(const N: IAstNode): TVoid;
|
||||
var
|
||||
R: IRecurNode;
|
||||
i: Integer;
|
||||
args: ITupleNode;
|
||||
begin
|
||||
R := N.AsRecur;
|
||||
args := R.Arguments;
|
||||
var args := R.Arguments.Elements;
|
||||
Append('(recur');
|
||||
// Manually iterate arguments
|
||||
for i := 0 to args.Count - 1 do
|
||||
for i := 0 to High(args) do
|
||||
begin
|
||||
Append(' ');
|
||||
Visit(args.Items[i]);
|
||||
Visit(args[i]);
|
||||
end;
|
||||
Append(')');
|
||||
end;
|
||||
@@ -365,18 +364,17 @@ end;
|
||||
function TPrettyPrintVisitor.VisitBlockExpression(const N: IAstNode): TVoid;
|
||||
var
|
||||
B: IBlockExpressionNode;
|
||||
exprs: ITupleNode;
|
||||
i: Integer;
|
||||
begin
|
||||
B := N.AsBlockExpression;
|
||||
exprs := B.Expressions;
|
||||
var exprs := B.Expressions.Elements;
|
||||
Append('(do');
|
||||
Indent;
|
||||
// Manually iterate expressions tuple for newlines
|
||||
for i := 0 to exprs.Count - 1 do
|
||||
for i := 0 to High(exprs) do
|
||||
begin
|
||||
NewLine;
|
||||
Visit(exprs.Items[i]);
|
||||
Visit(exprs[i]);
|
||||
end;
|
||||
Unindent;
|
||||
NewLine;
|
||||
@@ -437,22 +435,21 @@ end;
|
||||
function TPrettyPrintVisitor.VisitRecordLiteral(const N: IAstNode): TVoid;
|
||||
var
|
||||
R: IRecordLiteralNode;
|
||||
fields: ITupleNode;
|
||||
i: Integer;
|
||||
begin
|
||||
R := N.AsRecordLiteral;
|
||||
fields := R.Fields;
|
||||
if fields.Count = 0 then
|
||||
var fields := R.Fields.Elements;
|
||||
if Length(fields) = 0 then
|
||||
begin
|
||||
Append('{}');
|
||||
exit;
|
||||
end;
|
||||
Append('{');
|
||||
Indent;
|
||||
for i := 0 to fields.Count - 1 do
|
||||
for i := 0 to High(fields) do
|
||||
begin
|
||||
NewLine;
|
||||
Visit(fields.Items[i]);
|
||||
Visit(fields[i]);
|
||||
end;
|
||||
Unindent;
|
||||
NewLine;
|
||||
|
||||
@@ -453,12 +453,14 @@ begin
|
||||
ErrorFmt('%s expects a vector [...]', [Context]);
|
||||
|
||||
tuple := Node.AsTuple;
|
||||
SetLength(Result, tuple.Count);
|
||||
for i := 0 to tuple.Count - 1 do
|
||||
// Updated to use Elements property
|
||||
var elements := tuple.Elements;
|
||||
SetLength(Result, Length(elements));
|
||||
for i := 0 to High(elements) do
|
||||
begin
|
||||
if tuple.Items[i].Kind <> akIdentifier then
|
||||
if elements[i].Kind <> akIdentifier then
|
||||
ErrorFmt('%s vector must contain only identifiers.', [Context]);
|
||||
Result[i] := tuple.Items[i].AsIdentifier;
|
||||
Result[i] := elements[i].AsIdentifier;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
@@ -539,11 +539,14 @@ var
|
||||
begin
|
||||
T := N.AsTuple;
|
||||
hasChanged := False;
|
||||
SetLength(newElements, T.Count);
|
||||
|
||||
for i := 0 to T.Count - 1 do
|
||||
// Updated: Use Elements directly
|
||||
var oldElements := T.Elements;
|
||||
SetLength(newElements, Length(oldElements));
|
||||
|
||||
for i := 0 to High(oldElements) do
|
||||
begin
|
||||
item := T.Items[i];
|
||||
item := oldElements[i];
|
||||
newItem := Visit(item);
|
||||
newElements[i] := newItem;
|
||||
if item <> newItem then
|
||||
@@ -553,7 +556,7 @@ begin
|
||||
if not hasChanged then
|
||||
Result := N
|
||||
else
|
||||
Result := TAst.Tuple(N.Identity, newElements, N.AsTypedNode.StaticType);
|
||||
Result := TAst.Tuple(N.Identity, newElements, T.AsTypedNode.StaticType);
|
||||
end;
|
||||
|
||||
{ TAstVisitor (Walker) }
|
||||
@@ -731,12 +734,11 @@ begin
|
||||
end;
|
||||
|
||||
function TAstVisitor.WalkTuple(const N: IAstNode): TVoid;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
// Updated: Iterate directly via Elements
|
||||
var t := N.AsTuple;
|
||||
for i := 0 to t.Count - 1 do
|
||||
Visit(t.Items[i]);
|
||||
for var item in t.Elements do
|
||||
Visit(item);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
@@ -335,6 +335,7 @@ var
|
||||
i: Integer;
|
||||
argView: TAstViewNode;
|
||||
opLabel: TTextNode;
|
||||
argsElements: TArray<IAstNode>;
|
||||
begin
|
||||
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
|
||||
|
||||
@@ -342,19 +343,23 @@ begin
|
||||
OwnerNode.Orientation := loHorizontal;
|
||||
OwnerNode.Alignment := laCenter;
|
||||
|
||||
if FNode.Arguments.Count = 1 then
|
||||
// Optimization: Access Elements directly
|
||||
argsElements := FNode.Arguments.Elements;
|
||||
var argCount := Length(argsElements);
|
||||
|
||||
if argCount = 1 then
|
||||
begin
|
||||
opLabel := OwnerNode.AddLabel(OwnerNode, FCalleeName);
|
||||
opLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
|
||||
opLabel.Color := TAlphaColors.Darkorange;
|
||||
opLabel.Margins := TMarginRect.Create(2, 0, 2, 0);
|
||||
|
||||
argView := visu.CallAccept(FNode.Arguments.Items[0]);
|
||||
argView := visu.CallAccept(argsElements[0]);
|
||||
FArgumentNodes.Add(argView);
|
||||
end
|
||||
else
|
||||
begin
|
||||
for i := 0 to FNode.Arguments.Count - 1 do
|
||||
for i := 0 to argCount - 1 do
|
||||
begin
|
||||
if i > 0 then
|
||||
begin
|
||||
@@ -365,12 +370,12 @@ begin
|
||||
opLabel.Margins := TMarginRect.Create(0, 0, 0, 0);
|
||||
end;
|
||||
|
||||
argView := visu.CallAccept(FNode.Arguments.Items[i]);
|
||||
argView := visu.CallAccept(argsElements[i]);
|
||||
FArgumentNodes.Add(argView);
|
||||
end;
|
||||
end;
|
||||
|
||||
if FNode.Arguments.Count = 0 then
|
||||
if argCount = 0 then
|
||||
begin
|
||||
opLabel := OwnerNode.AddLabel(OwnerNode, FCalleeName);
|
||||
opLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
|
||||
|
||||
@@ -47,6 +47,7 @@ var
|
||||
i: Integer;
|
||||
childView: TAstViewNode;
|
||||
lbl: TTextNode;
|
||||
elements: TArray<IAstNode>;
|
||||
begin
|
||||
// Tuples act as lists, using horizontal flow (e.g. [1 2 3] or [[src [:sel]]])
|
||||
OwnerNode.Frameless := True;
|
||||
@@ -60,18 +61,21 @@ begin
|
||||
|
||||
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth);
|
||||
|
||||
for i := 0 to FNode.Count - 1 do
|
||||
// Optimization: Access Elements array directly
|
||||
elements := FNode.Elements;
|
||||
|
||||
for i := 0 to High(elements) do
|
||||
begin
|
||||
// Standard spacing between elements
|
||||
if i > 0 then
|
||||
OwnerNode.AddLabel(OwnerNode, ' ');
|
||||
|
||||
childView := visu.CallAccept(FNode.Items[i]);
|
||||
childView := visu.CallAccept(elements[i]);
|
||||
FChildNodes.Add(childView);
|
||||
end;
|
||||
|
||||
// Visual hint for empty tuples
|
||||
if FNode.Count = 0 then
|
||||
if Length(elements) = 0 then
|
||||
begin
|
||||
OwnerNode.AddLabel(OwnerNode, ' '); // spacer
|
||||
end;
|
||||
|
||||
@@ -13,14 +13,15 @@ uses
|
||||
|
||||
type
|
||||
// --- Abstract List Base ---
|
||||
// Implements IReorderable to support drag & drop reordering within the virtual tree
|
||||
TNodeListHandler<T: IAstNode> = class(TBaseNodeHandler<INodeList<T>>, IReorderable)
|
||||
// Implements IReorderable to support drag & drop reordering within the virtual tree.
|
||||
// Now operates on the untyped ITupleNode.
|
||||
TNodeListHandler = class(TBaseNodeHandler<ITupleNode>, IReorderable)
|
||||
protected
|
||||
FChildNodes: TList<TAstViewNode>;
|
||||
function GetOrientation: TLayoutOrientation; virtual; abstract;
|
||||
function GetAlignment: TLayoutAlignment; virtual;
|
||||
public
|
||||
constructor Create(const ANode: INodeList<T>);
|
||||
constructor Create(const ANode: ITupleNode);
|
||||
destructor Destroy; override;
|
||||
procedure BuildUI(OwnerNode: TAstViewNode); override;
|
||||
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; abstract;
|
||||
@@ -32,32 +33,33 @@ type
|
||||
|
||||
implementation
|
||||
|
||||
{ TNodeListHandler<T> }
|
||||
{ TNodeListHandler }
|
||||
|
||||
constructor TNodeListHandler<T>.Create(const ANode: INodeList<T>);
|
||||
constructor TNodeListHandler.Create(const ANode: ITupleNode);
|
||||
begin
|
||||
inherited Create(ANode);
|
||||
FChildNodes := TList<TAstViewNode>.Create;
|
||||
end;
|
||||
|
||||
destructor TNodeListHandler<T>.Destroy;
|
||||
destructor TNodeListHandler.Destroy;
|
||||
begin
|
||||
FChildNodes.Free;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TNodeListHandler<T>.GetAlignment: TLayoutAlignment;
|
||||
function TNodeListHandler.GetAlignment: TLayoutAlignment;
|
||||
begin
|
||||
Result := TLayoutAlignment.laCenter;
|
||||
end;
|
||||
|
||||
procedure TNodeListHandler<T>.BuildUI(OwnerNode: TAstViewNode);
|
||||
procedure TNodeListHandler.BuildUI(OwnerNode: TAstViewNode);
|
||||
var
|
||||
visu: IAstVisualizer;
|
||||
i: Integer;
|
||||
childView: TAstViewNode;
|
||||
openTok, closeTok, sep: string;
|
||||
listId: IListIdentity;
|
||||
elements: TArray<IAstNode>;
|
||||
begin
|
||||
if (FNode.Identity <> nil) and (FNode.Identity.Kind = ikList) then
|
||||
begin
|
||||
@@ -83,19 +85,22 @@ begin
|
||||
if openTok <> '' then
|
||||
OwnerNode.AddLabel(OwnerNode, openTok);
|
||||
|
||||
for i := 0 to FNode.Count - 1 do
|
||||
// Optimization: Access Elements array directly from ITupleNode
|
||||
elements := FNode.Elements;
|
||||
|
||||
for i := 0 to High(elements) do
|
||||
begin
|
||||
childView := visu.CallAccept(FNode[i]);
|
||||
childView := visu.CallAccept(elements[i]);
|
||||
FChildNodes.Add(childView);
|
||||
|
||||
if (i < FNode.Count - 1) and (sep <> '') and (sep <> ' ') then
|
||||
if (i < High(elements)) and (sep <> '') and (sep <> ' ') then
|
||||
OwnerNode.AddLabel(OwnerNode, sep);
|
||||
end;
|
||||
|
||||
if closeTok <> '' then
|
||||
OwnerNode.AddLabel(OwnerNode, closeTok);
|
||||
|
||||
if FNode.Count = 0 then
|
||||
if Length(elements) = 0 then
|
||||
begin
|
||||
if (openTok = '') and (closeTok = '') then
|
||||
begin
|
||||
@@ -107,7 +112,7 @@ end;
|
||||
|
||||
// IReorderable Implementation
|
||||
|
||||
function TNodeListHandler<T>.CanDrag(Child: TVisualNode): Boolean;
|
||||
function TNodeListHandler.CanDrag(Child: TVisualNode): Boolean;
|
||||
begin
|
||||
// Only allow dragging if the child is one of our managed ViewNodes
|
||||
if Child is TAstViewNode then
|
||||
@@ -116,7 +121,7 @@ begin
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
procedure TNodeListHandler<T>.MoveChild(SourceIndex, TargetIndex: Integer);
|
||||
procedure TNodeListHandler.MoveChild(SourceIndex, TargetIndex: Integer);
|
||||
var
|
||||
item: TAstViewNode;
|
||||
begin
|
||||
|
||||
Reference in New Issue
Block a user