ITupleNode signature change
This commit is contained in:
@@ -119,7 +119,8 @@ begin
|
||||
if Node.Kind = akBlockExpression then
|
||||
begin
|
||||
block := Node.AsBlockExpression;
|
||||
for child in block.Expressions.ToArray do
|
||||
// Updated: Use Elements instead of ToArray
|
||||
for child in block.Expressions.Elements do
|
||||
begin
|
||||
Result := FindFirstVarName(child);
|
||||
if Result <> '' then
|
||||
|
||||
@@ -23,6 +23,7 @@ type
|
||||
[TestCase('Integer', '42,42')]
|
||||
[TestCase('Negative', '-10,-10')]
|
||||
[TestCase('Zero', '0,0')]
|
||||
[TestCase('Nop', '...')]
|
||||
procedure Parser_Number_Integer(const Source: string; Expected: Int64);
|
||||
|
||||
[Test]
|
||||
@@ -129,6 +130,12 @@ var
|
||||
node: IAstNode;
|
||||
begin
|
||||
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<TScalar.TKind>(TScalar.TKind.Ordinal, node.AsConstant.Value.AsScalar.Kind);
|
||||
Assert.AreEqual<Int64>(Expected, node.AsConstant.Value.AsScalar.Value.AsInt64);
|
||||
@@ -209,11 +216,11 @@ begin
|
||||
call := node.AsFunctionCall;
|
||||
|
||||
Assert.AreEqual<string>('add', call.Callee.AsIdentifier.Name);
|
||||
// Use Count instead of Length
|
||||
Assert.AreEqual<Integer>(2, call.Arguments.Count);
|
||||
// Use Length(Elements) instead of Count
|
||||
Assert.AreEqual<Integer>(2, Length(call.Arguments.Elements));
|
||||
|
||||
Assert.AreEqual<Int64>(1, call.Arguments[0].AsConstant.Value.AsScalar.Value.AsInt64);
|
||||
Assert.AreEqual<Int64>(2, call.Arguments[1].AsConstant.Value.AsScalar.Value.AsInt64);
|
||||
Assert.AreEqual<Int64>(1, call.Arguments.Elements[0].AsConstant.Value.AsScalar.Value.AsInt64);
|
||||
Assert.AreEqual<Int64>(2, call.Arguments.Elements[1].AsConstant.Value.AsScalar.Value.AsInt64);
|
||||
end;
|
||||
|
||||
procedure TTestMycAstScript.Parser_RecordLiteral;
|
||||
@@ -226,14 +233,15 @@ begin
|
||||
Assert.AreEqual<TAstNodeKind>(TAstNodeKind.akRecordLiteral, node.Kind);
|
||||
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
|
||||
Assert.AreEqual<string>('a', rec.Fields[0].AsRecordField.Key.Value.Name);
|
||||
Assert.AreEqual<Int64>(1, rec.Fields[0].AsRecordField.Value.AsConstant.Value.AsScalar.Value.AsInt64);
|
||||
Assert.AreEqual<string>('a', rec.Fields.Elements[0].AsRecordField.Key.Value.Name);
|
||||
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<Int64>(2, rec.Fields[1].AsRecordField.Value.AsConstant.Value.AsScalar.Value.AsInt64);
|
||||
Assert.AreEqual<string>('b', rec.Fields.Elements[1].AsRecordField.Key.Value.Name);
|
||||
Assert.AreEqual<Int64>(2, rec.Fields.Elements[1].AsRecordField.Value.AsConstant.Value.AsScalar.Value.AsInt64);
|
||||
end;
|
||||
|
||||
procedure TTestMycAstScript.Parser_RecordLiteral_Empty;
|
||||
@@ -242,7 +250,8 @@ var
|
||||
begin
|
||||
node := Parse('{}');
|
||||
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;
|
||||
|
||||
// --- Special Forms ---
|
||||
@@ -271,10 +280,11 @@ begin
|
||||
Assert.AreEqual<TAstNodeKind>(TAstNodeKind.akLambdaExpression, node.Kind);
|
||||
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
|
||||
Assert.AreEqual<string>('a', lam.Parameters[0].AsIdentifier.Name);
|
||||
Assert.AreEqual<string>('b', lam.Parameters[1].AsIdentifier.Name);
|
||||
Assert.AreEqual<string>('a', lam.Parameters.Elements[0].AsIdentifier.Name);
|
||||
Assert.AreEqual<string>('b', lam.Parameters.Elements[1].AsIdentifier.Name);
|
||||
|
||||
Assert.AreEqual<TAstNodeKind>(TAstNodeKind.akFunctionCall, lam.Body.Kind);
|
||||
end;
|
||||
@@ -322,8 +332,9 @@ begin
|
||||
call := node.AsFunctionCall;
|
||||
|
||||
Assert.AreEqual<string>('quote', call.Callee.AsIdentifier.Name);
|
||||
Assert.AreEqual<Integer>(1, call.Arguments.Count);
|
||||
Assert.AreEqual<string>('foo', call.Arguments[0].AsIdentifier.Name);
|
||||
// Use Length(Elements) instead of Count
|
||||
Assert.AreEqual<Integer>(1, Length(call.Arguments.Elements));
|
||||
Assert.AreEqual<string>('foo', call.Arguments.Elements[0].AsIdentifier.Name);
|
||||
end;
|
||||
|
||||
procedure TTestMycAstScript.Parser_Quasiquote_CreatesNode;
|
||||
@@ -360,27 +371,27 @@ end;
|
||||
|
||||
procedure TTestMycAstScript.Parser_Error_UnbalancedParens_MissingRight;
|
||||
begin
|
||||
Assert.WillRaise(procedure begin Parse('(a b'); end);
|
||||
Assert.WillRaise(procedure begin Parse('(a b'); end, EParserException);
|
||||
end;
|
||||
|
||||
procedure TTestMycAstScript.Parser_Error_UnbalancedParens_ExtraRight;
|
||||
begin
|
||||
Assert.WillRaise(procedure begin Parse('a )'); end);
|
||||
Assert.WillRaise(procedure begin Parse('a )'); end, EParserException);
|
||||
end;
|
||||
|
||||
procedure TTestMycAstScript.Parser_Error_UnterminatedString;
|
||||
begin
|
||||
Assert.WillRaise(procedure begin Parse('"hello'); end);
|
||||
Assert.WillRaise(procedure begin Parse('"hello'); end, EParserException);
|
||||
end;
|
||||
|
||||
procedure TTestMycAstScript.Parser_Error_EmptyList;
|
||||
begin
|
||||
Assert.WillRaise(procedure begin Parse('()'); end);
|
||||
Assert.WillRaise(procedure begin Parse('()'); end, EParserException);
|
||||
end;
|
||||
|
||||
procedure TTestMycAstScript.Parser_Error_Record_MissingValue;
|
||||
begin
|
||||
Assert.WillRaise(procedure begin Parse('{:a 1 :b}'); end);
|
||||
Assert.WillRaise(procedure begin Parse('{:a 1 :b}'); end, EParserException);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
@@ -104,8 +104,8 @@ end;
|
||||
|
||||
function TTestAstBinder.Unwrap(const Node: IAstNode): IAstNode;
|
||||
begin
|
||||
if (Node.Kind = akBlockExpression) and (Node.AsBlockExpression.Expressions.Count = 1) then
|
||||
Result := Node.AsBlockExpression.Expressions[0]
|
||||
if (Node.Kind = akBlockExpression) and (Length(Node.AsBlockExpression.Expressions.Elements) = 1) then
|
||||
Result := Node.AsBlockExpression.Expressions.Elements[0]
|
||||
else
|
||||
Result := Node;
|
||||
end;
|
||||
@@ -132,7 +132,7 @@ begin
|
||||
block := bound.AsBlockExpression;
|
||||
|
||||
// Check definition of 'b'
|
||||
decl := block.Expressions[1].AsVariableDeclaration;
|
||||
decl := block.Expressions.Elements[1].AsVariableDeclaration;
|
||||
initIdent := decl.Initializer.AsIdentifier;
|
||||
|
||||
// 'a' is Slot 0. 'b' is Slot 1.
|
||||
@@ -177,7 +177,7 @@ begin
|
||||
Assert.IsFalse(log.HasErrors);
|
||||
|
||||
block := bound.AsBlockExpression;
|
||||
ident := block.Expressions[1].AsIdentifier;
|
||||
ident := block.Expressions.Elements[1].AsIdentifier;
|
||||
Assert.AreEqual<TAddressKind>(akLocalOrParent, ident.Address.Kind);
|
||||
Assert.AreEqual<Integer>(0, ident.Address.ScopeDepth);
|
||||
Assert.AreEqual<Integer>(0, ident.Address.SlotIndex);
|
||||
@@ -192,14 +192,15 @@ var
|
||||
innerUsage: IIdentifierNode;
|
||||
log: ICompilerLog;
|
||||
begin
|
||||
root :=
|
||||
TAst.Block([TAst.VarDecl(TAst.Identifier('x'), TAst.Constant(1)), TAst.LambdaExpr([TAst.Identifier('x')], TAst.Identifier('x'))]);
|
||||
// Convert array to tuple for lambda params
|
||||
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);
|
||||
|
||||
Assert.IsFalse(log.HasErrors);
|
||||
|
||||
block := bound.AsBlockExpression;
|
||||
innerLambda := block.Expressions[1].AsLambdaExpression;
|
||||
innerLambda := block.Expressions.Elements[1].AsLambdaExpression;
|
||||
innerUsage := innerLambda.Body.AsIdentifier;
|
||||
Assert.AreEqual<Integer>(1, innerUsage.Address.SlotIndex); // Parameter x (Slot 1 because <self> is Slot 0)
|
||||
end;
|
||||
@@ -211,7 +212,8 @@ var
|
||||
log: ICompilerLog;
|
||||
begin
|
||||
// (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);
|
||||
|
||||
@@ -230,14 +232,16 @@ var
|
||||
lambda: ILambdaExpressionNode;
|
||||
log: ICompilerLog;
|
||||
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));
|
||||
|
||||
Assert.IsFalse(log.HasErrors);
|
||||
|
||||
lambda := bound.AsLambdaExpression;
|
||||
// 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;
|
||||
|
||||
procedure TTestAstBinder.Test_MultipleParameters_AreBoundCorrectly;
|
||||
@@ -247,15 +251,17 @@ var
|
||||
lambda: ILambdaExpressionNode;
|
||||
log: ICompilerLog;
|
||||
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));
|
||||
|
||||
Assert.IsFalse(log.HasErrors);
|
||||
|
||||
lambda := bound.AsLambdaExpression;
|
||||
// FIX: Cast elements to Identifier
|
||||
Assert.AreEqual<Integer>(1, lambda.Parameters[0].AsIdentifier.Address.SlotIndex);
|
||||
Assert.AreEqual<Integer>(2, lambda.Parameters[1].AsIdentifier.Address.SlotIndex);
|
||||
Assert.AreEqual<Integer>(1, lambda.Parameters.Elements[0].AsIdentifier.Address.SlotIndex);
|
||||
Assert.AreEqual<Integer>(2, lambda.Parameters.Elements[1].AsIdentifier.Address.SlotIndex);
|
||||
end;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -271,13 +277,14 @@ var
|
||||
bodyIdent: IIdentifierNode;
|
||||
log: ICompilerLog;
|
||||
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);
|
||||
|
||||
Assert.IsFalse(log.HasErrors);
|
||||
|
||||
block := bound.AsBlockExpression;
|
||||
lambda := block.Expressions[1].AsLambdaExpression;
|
||||
lambda := block.Expressions.Elements[1].AsLambdaExpression;
|
||||
bodyIdent := lambda.Body.AsIdentifier;
|
||||
|
||||
// Inside the lambda, 'x' is accessed via an Upvalue
|
||||
@@ -293,16 +300,20 @@ var
|
||||
midLambda, innerLambda: ILambdaExpressionNode;
|
||||
log: ICompilerLog;
|
||||
begin
|
||||
var emptyParams := TAst.Tuple([]);
|
||||
root :=
|
||||
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);
|
||||
|
||||
Assert.IsFalse(log.HasErrors);
|
||||
|
||||
outerBlock := bound.AsBlockExpression;
|
||||
midLambda := outerBlock.Expressions[1].AsLambdaExpression;
|
||||
midLambda := outerBlock.Expressions.Elements[1].AsLambdaExpression;
|
||||
innerLambda := midLambda.Body.AsLambdaExpression;
|
||||
|
||||
// Inner lambda accesses 'top' via upvalue
|
||||
@@ -316,7 +327,8 @@ var
|
||||
lambda: ILambdaExpressionNode;
|
||||
log: ICompilerLog;
|
||||
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));
|
||||
|
||||
Assert.IsFalse(log.HasErrors);
|
||||
|
||||
Reference in New Issue
Block a user