1313#include " swift-c/SyntaxParser/SwiftSyntaxParser.h"
1414#include " swift/Basic/LLVM.h"
1515#include " llvm/ADT/StringRef.h"
16+ #include " swift/Syntax/Serialization/SyntaxSerialization.h"
1617#include < vector>
1718#include " gtest/gtest.h"
1819
1920using namespace swift ;
21+ using namespace swift ::syntax;
22+ using namespace serialization ;
2023
2124static swiftparse_client_node_t
2225parse (StringRef source, swiftparse_node_handler_t node_handler,
@@ -29,63 +32,110 @@ parse(StringRef source, swiftparse_node_handler_t node_handler,
2932 return top;
3033}
3134
35+ static bool containsChild (swiftparse_layout_data_t layout_data, void *child) {
36+ for (size_t i = 0 ; i < layout_data.nodes_count ; i++) {
37+ if (layout_data.nodes [i] == child) {
38+ return true ;
39+ }
40+ }
41+ return false ;
42+ }
43+
3244TEST (SwiftSyntaxParserTests, IncrementalParsing) {
3345 StringRef source1 =
3446 " func t1() { }\n "
35- " func t2() { }\n " ;
47+ " func t2() { }\n "
48+ " func t3() { }\n " ;
49+
3650 StringRef source2 =
3751 " func t1renamed() { }\n "
38- " func t2() { }\n " ;
52+ " func t2() { }\n "
53+ " func t3() { }\n " ;
54+
55+ swiftparse_syntax_kind_t token = getNumericValue (SyntaxKind::Token);
56+ swiftparse_syntax_kind_t functionDecl = getNumericValue (SyntaxKind::FunctionDecl);
57+ swiftparse_syntax_kind_t codeBlockItem = getNumericValue (SyntaxKind::CodeBlockItem);
58+ swiftparse_syntax_kind_t codeBlockItemList = getNumericValue (SyntaxKind::CodeBlockItemList);
59+
60+ // Set up a bunch of node ids that we can later use.
61+ void *t1Token = &t1Token;
62+ void *t1Func = &t1Func;
63+ void *t1CodeBlockItem = &t1CodeBlockItem;
64+ void *t2Token = &t2Token;
65+ void *t2Func = &t2Func;
66+ void *t2CodeBlockItem = &t2CodeBlockItem;
67+ void *t3Token = &t3Token;
68+ void *t3Func = &t3Func;
69+ void *t3CodeBlockItem = &t3CodeBlockItem;
3970
40- // FIXME: Use the syntax kind directly instead of the serialization number.
41- swiftparse_syntax_kind_t codeBlockItemList = 163 ;
42- swiftparse_syntax_kind_t codeBlockItem = 92 ;
71+ // Find the t1/t2/t3 tokens in the source
72+ size_t t1TokenOffset = StringRef (source1).find (" t1" );
73+ size_t t2TokenOffset = StringRef (source1).find (" t2" );
74+ size_t t3TokenOffset = StringRef (source1).find (" t3" );
4375
44- // Assign id numbers to codeBlockItem nodes and collect the ids that are
45- // listed as members of a codeBlockItemList node into a vector.
46- // When we reparse, check that we got the parser to resuse the node id from
47- // the previous parse.
76+ // The length of the t2/t3 code block items
77+ size_t t2CodeBlockItemLength = 14 ;
78+ size_t t3CodeBlockItemLength = 14 ;
79+
80+ // Collect the node ids of the code block items in this list and verify that
81+ // t2 and t3 get reused after the edit from source1 to source2.
82+ __block std::vector<void *> codeBlockItemIds;
4883
49- __block std::vector<int > nodeids;
50- __block int idcounter = 0 ;
51- size_t t2Offset = StringRef (source1).find (" \n func t2" );
52- __block int t2NodeId = 0 ;
53- __block size_t t2NodeLength = 0 ;
5484 swiftparse_node_handler_t nodeHandler =
5585 ^swiftparse_client_node_t (const swiftparse_syntax_node_t *raw_node) {
56- if (raw_node->kind == codeBlockItem) {
57- int nodeid = ++idcounter;
58- if (raw_node->range .offset == t2Offset) {
59- t2NodeId = nodeid;
60- t2NodeLength = raw_node->range .length ;
86+ if (raw_node->kind == token) {
87+ if (raw_node->token_data .range .offset == t1TokenOffset) {
88+ return t1Token;
89+ } else if (raw_node->token_data .range .offset == t2TokenOffset) {
90+ return t2Token;
91+ } else if (raw_node->token_data .range .offset == t3TokenOffset) {
92+ return t3Token;
6193 }
62- return (void *)(intptr_t )nodeid;
63- }
64- if (raw_node->kind == codeBlockItemList) {
94+ } else if (raw_node->kind == functionDecl) {
95+ if (containsChild (raw_node->layout_data , t1Token)) {
96+ return t1Func;
97+ } else if (containsChild (raw_node->layout_data , t2Token)) {
98+ return t2Func;
99+ } else if (containsChild (raw_node->layout_data , t3Token)) {
100+ return t3Func;
101+ }
102+ } else if (raw_node->kind == codeBlockItem) {
103+ if (containsChild (raw_node->layout_data , t1Func)) {
104+ return t1CodeBlockItem;
105+ } else if (containsChild (raw_node->layout_data , t2Func)) {
106+ return t2CodeBlockItem;
107+ } else if (containsChild (raw_node->layout_data , t3Func)) {
108+ return t3CodeBlockItem;
109+ }
110+ } else if (raw_node->kind == codeBlockItemList) {
65111 for (unsigned i = 0 , e = raw_node->layout_data .nodes_count ;
66112 i != e; ++i) {
67- nodeids .push_back (( int )( intptr_t ) raw_node->layout_data .nodes [i]);
113+ codeBlockItemIds .push_back (raw_node->layout_data .nodes [i]);
68114 }
69115 }
70116 return nullptr ;
71117 };
72- parse (source1, nodeHandler, nullptr );
73- EXPECT_EQ (t2NodeId, 2 );
74- ASSERT_NE (t2NodeLength, size_t (0 ));
75- EXPECT_EQ (nodeids, (std::vector<int >{1 , 2 }));
118+ parse (source1, nodeHandler, /* node_lookup=*/ nullptr );
119+ ASSERT_NE (t2CodeBlockItemLength, size_t (0 ));
120+ EXPECT_EQ (codeBlockItemIds, (std::vector<void *>{t1CodeBlockItem, t2CodeBlockItem, t3CodeBlockItem}));
76121
77- nodeids .clear ();
78- idcounter = 1000 ;
79- t2Offset = StringRef (source2).find (" \n func t2 " );
122+ codeBlockItemIds .clear ();
123+ size_t t2CodeBlockItemOffset = StringRef (source2). find ( " \n func t2 " ) ;
124+ size_t t3CodeBlockItemOffset = StringRef (source2).find (" \n func t3 " );
80125 swiftparse_node_lookup_t nodeLookup =
81126 ^swiftparse_lookup_result_t (size_t offset, swiftparse_syntax_kind_t kind) {
82- if (offset == t2Offset && kind == codeBlockItem) {
83- return { t2NodeLength, (void *)(intptr_t )t2NodeId };
84- } else {
85- return {0 , nullptr };
127+ if (kind == codeBlockItem) {
128+ if (offset == t2CodeBlockItemOffset) {
129+ return { t2CodeBlockItemLength, t2CodeBlockItem };
130+ } else if (offset == t3CodeBlockItemOffset) {
131+ return { t3CodeBlockItemLength, t3CodeBlockItem };
132+ }
86133 }
134+ return {0 , nullptr };
87135 };
88136
89137 parse (source2, nodeHandler, nodeLookup);
90- EXPECT_EQ (nodeids, (std::vector<int >{1001 , 2 }));
138+ // Assert that t2 and t3 get reused.
139+ EXPECT_EQ (codeBlockItemIds[1 ], t2CodeBlockItem);
140+ EXPECT_EQ (codeBlockItemIds[2 ], t3CodeBlockItem);
91141}
0 commit comments