Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Source/DelphiAST.Classes.pas
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ TCompoundSyntaxNode = class(TSyntaxNode)
FEndLine: Integer;
public
function Clone: TSyntaxNode; override;
//counterpart to AssignPositionFrom, for a node rebuilt from a parsed one
procedure AssignEndPositionFrom(const Node: TCompoundSyntaxNode);

property EndCol: Integer read FEndCol write FEndCol;
property EndLine: Integer read FEndLine write FEndLine;
Expand Down Expand Up @@ -629,6 +631,12 @@ procedure TSyntaxNode.AssignPositionFrom(const Node: TSyntaxNode);

{ TCompoundSyntaxNode }

procedure TCompoundSyntaxNode.AssignEndPositionFrom(const Node: TCompoundSyntaxNode);
begin
FEndCol := Node.EndCol;
FEndLine := Node.EndLine;
end;

function TCompoundSyntaxNode.Clone: TSyntaxNode;
begin
Result := inherited;
Expand Down
9 changes: 7 additions & 2 deletions Source/DelphiAST.pas
Original file line number Diff line number Diff line change
Expand Up @@ -1195,9 +1195,11 @@ procedure TPasSyntaxTreeBuilder.CompoundStatement;

procedure TPasSyntaxTreeBuilder.ConstantDeclaration;
begin
FStack.Push(ntConstant);
//compound: a constant's value can span lines, so record where it ends. as TypeDeclaration.
FStack.PushCompoundSyntaxNode(ntConstant);
try
inherited;
SetCurrentCompoundNodesEndPosition;
finally
FStack.Pop;
end;
Expand Down Expand Up @@ -1329,9 +1331,12 @@ procedure TPasSyntaxTreeBuilder.ConstSection;
if Constant.Typ <> ntName then
Continue;

Temp := FStack.Push(ConstList.Typ);
//compound: start from the name, end from the ConstList that measured the value.
Temp := FStack.PushCompoundSyntaxNode(ConstList.Typ);
try
Temp.AssignPositionFrom(Constant);
if ConstList is TCompoundSyntaxNode then
TCompoundSyntaxNode(Temp).AssignEndPositionFrom(TCompoundSyntaxNode(ConstList));

FStack.AddChild(Constant.Clone);
if Assigned(TypeInfo) then
Expand Down
34 changes: 34 additions & 0 deletions Test/UnitTests/DelphiAST.Tests.pas
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,39 @@ procedure TestSourcePositions;
end;
end;

procedure TestConstantEndPosition;
var
Root, ConstsNode, Node, Spanning, Single: TSyntaxNode;
begin
Root := ParseSource('unit Consts;' + sLineBreak + 'interface' + sLineBreak + 'const' +
sLineBreak + ' Spanning = ''first part '' +' + sLineBreak + ' ''second part'';' +
sLineBreak + ' Single = 42;' + sLineBreak + 'implementation' + sLineBreak + 'end.');
try
ConstsNode := FindDescendant(Root, ntConstants);
AssertNotNil(ConstsNode, 'No const section was produced');
Spanning := nil;
Single := nil;
for Node in ConstsNode.ChildNodes do
if Node.Typ = ntConstant then
if Node.Line = 4 then
Spanning := Node
else if Node.Line = 6 then
Single := Node;

AssertNotNil(Spanning, 'No constant starting on line 4');
AssertTrue(Spanning is TCompoundSyntaxNode,
'Constant node must be compound so it can carry an end position');
AssertEquals(5, TCompoundSyntaxNode(Spanning).EndLine,
'A multi-line constant must reach the last line of its value');

AssertNotNil(Single, 'No constant starting on line 6');
AssertEquals(6, TCompoundSyntaxNode(Single).EndLine,
'A single-line constant must end on its own line, not run on to what follows');
finally
Root.Free;
end;
end;

procedure TestInvalidSyntax;
var
Root: TSyntaxNode;
Expand Down Expand Up @@ -229,6 +262,7 @@ procedure RunAllTests;
RunTest('AST.GenericRecordAndProperty', TestGenericRecordAndProperty);
RunTest('Writer.LiteralsUnicodeAndXmlEscaping', TestLiteralsAndUnicode);
RunTest('AST.SourcePositions', TestSourcePositions);
RunTest('AST.ConstantEndPosition', TestConstantEndPosition);
RunTest('Parser.InvalidSyntax', TestInvalidSyntax);
{$IFNDEF FPC}
RunTest('Serialization.BinaryRoundTrip', TestBinarySerializationRoundTrip);
Expand Down