-
Notifications
You must be signed in to change notification settings - Fork 10.5k
/
Copy pathSyntaxParserTests.cpp
141 lines (127 loc) · 5.24 KB
/
SyntaxParserTests.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift-c/SyntaxParser/SwiftSyntaxParser.h"
#include "swift/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
#include "swift/Syntax/Serialization/SyntaxSerialization.h"
#include <vector>
#include "gtest/gtest.h"
using namespace swift;
using namespace swift::syntax;
using namespace serialization;
static swiftparse_client_node_t
parse(StringRef source, swiftparse_node_handler_t node_handler,
swiftparse_node_lookup_t node_lookup) {
swiftparse_parser_t parser = swiftparse_parser_create();
swiftparse_parser_set_node_handler(parser, node_handler);
swiftparse_parser_set_node_lookup(parser, node_lookup);
swiftparse_client_node_t top = swiftparse_parse_string(parser, source.data(), source.size());
swiftparse_parser_dispose(parser);
return top;
}
static bool containsChild(swiftparse_layout_data_t layout_data, void *child) {
for (size_t i = 0; i < layout_data.nodes_count; i++) {
if (layout_data.nodes[i] == child) {
return true;
}
}
return false;
}
TEST(SwiftSyntaxParserTests, IncrementalParsing) {
StringRef source1 =
"func t1() { }\n"
"func t2() { }\n"
"func t3() { }\n";
StringRef source2 =
"func t1renamed() { }\n"
"func t2() { }\n"
"func t3() { }\n";
swiftparse_syntax_kind_t token = getNumericValue(SyntaxKind::Token);
swiftparse_syntax_kind_t functionDecl = getNumericValue(SyntaxKind::FunctionDecl);
swiftparse_syntax_kind_t codeBlockItem = getNumericValue(SyntaxKind::CodeBlockItem);
swiftparse_syntax_kind_t codeBlockItemList = getNumericValue(SyntaxKind::CodeBlockItemList);
// Set up a bunch of node ids that we can later use.
void *t1Token = &t1Token;
void *t1Func = &t1Func;
void *t1CodeBlockItem = &t1CodeBlockItem;
void *t2Token = &t2Token;
void *t2Func = &t2Func;
void *t2CodeBlockItem = &t2CodeBlockItem;
void *t3Token = &t3Token;
void *t3Func = &t3Func;
void *t3CodeBlockItem = &t3CodeBlockItem;
// Find the t1/t2/t3 tokens in the source
size_t t1TokenOffset = StringRef(source1).find("t1");
size_t t2TokenOffset = StringRef(source1).find("t2");
size_t t3TokenOffset = StringRef(source1).find("t3");
// The length of the t2/t3 code block items
size_t t2CodeBlockItemLength = 14;
size_t t3CodeBlockItemLength = 14;
// Collect the node ids of the code block items in this list and verify that
// t2 and t3 get reused after the edit from source1 to source2.
__block std::vector<void *> codeBlockItemIds;
swiftparse_node_handler_t nodeHandler =
^swiftparse_client_node_t(const swiftparse_syntax_node_t *raw_node) {
if (raw_node->kind == token) {
if (raw_node->token_data.range.offset == t1TokenOffset) {
return t1Token;
} else if (raw_node->token_data.range.offset == t2TokenOffset) {
return t2Token;
} else if (raw_node->token_data.range.offset == t3TokenOffset) {
return t3Token;
}
} else if (raw_node->kind == functionDecl) {
if (containsChild(raw_node->layout_data, t1Token)) {
return t1Func;
} else if (containsChild(raw_node->layout_data, t2Token)) {
return t2Func;
} else if (containsChild(raw_node->layout_data, t3Token)) {
return t3Func;
}
} else if (raw_node->kind == codeBlockItem) {
if (containsChild(raw_node->layout_data, t1Func)) {
return t1CodeBlockItem;
} else if (containsChild(raw_node->layout_data, t2Func)) {
return t2CodeBlockItem;
} else if (containsChild(raw_node->layout_data, t3Func)) {
return t3CodeBlockItem;
}
} else if (raw_node->kind == codeBlockItemList) {
for (unsigned i = 0, e = raw_node->layout_data.nodes_count;
i != e; ++i) {
codeBlockItemIds.push_back(raw_node->layout_data.nodes[i]);
}
}
return nullptr;
};
parse(source1, nodeHandler, /*node_lookup=*/nullptr);
ASSERT_NE(t2CodeBlockItemLength, size_t(0));
EXPECT_EQ(codeBlockItemIds, (std::vector<void *>{t1CodeBlockItem, t2CodeBlockItem, t3CodeBlockItem}));
codeBlockItemIds.clear();
size_t t2CodeBlockItemOffset = StringRef(source2).find("\nfunc t2");
size_t t3CodeBlockItemOffset = StringRef(source2).find("\nfunc t3");
swiftparse_node_lookup_t nodeLookup =
^swiftparse_lookup_result_t(size_t offset, swiftparse_syntax_kind_t kind) {
if (kind == codeBlockItem) {
if (offset == t2CodeBlockItemOffset) {
return { t2CodeBlockItemLength, t2CodeBlockItem };
} else if (offset == t3CodeBlockItemOffset) {
return { t3CodeBlockItemLength, t3CodeBlockItem };
}
}
return {0, nullptr};
};
parse(source2, nodeHandler, nodeLookup);
// Assert that t2 and t3 get reused.
EXPECT_EQ(codeBlockItemIds[1], t2CodeBlockItem);
EXPECT_EQ(codeBlockItemIds[2], t3CodeBlockItem);
}