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