1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "gn/parse_tree.h"
6
7 #include <stdint.h>
8
9 #include <memory>
10 #include <utility>
11
12 #include "gn/input_file.h"
13 #include "gn/scope.h"
14 #include "gn/test_with_scope.h"
15 #include "util/test/test.h"
16
TEST(ParseTree,Accessor)17 TEST(ParseTree, Accessor) {
18 TestWithScope setup;
19
20 // Make a pretend parse node with proper tracking that we can blame for the
21 // given value.
22 InputFile input_file(SourceFile("//foo"));
23 Token base_token(Location(&input_file, 1, 1), Token::IDENTIFIER, "a");
24 Token member_token(Location(&input_file, 1, 1), Token::IDENTIFIER, "b");
25
26 AccessorNode accessor;
27 accessor.set_base(base_token);
28
29 std::unique_ptr<IdentifierNode> member_identifier =
30 std::make_unique<IdentifierNode>(member_token);
31 accessor.set_member(std::move(member_identifier));
32
33 // The access should fail because a is not defined.
34 Err err;
35 Value result = accessor.Execute(setup.scope(), &err);
36 EXPECT_TRUE(err.has_error());
37 err = Err();
38 EXPECT_EQ(Value::NONE, result.type());
39
40 // Define a as a Scope. It should still fail because b isn't defined.
41 err = Err();
42 setup.scope()->SetValue(
43 "a", Value(nullptr, std::make_unique<Scope>(setup.scope())), nullptr);
44 result = accessor.Execute(setup.scope(), &err);
45 EXPECT_TRUE(err.has_error());
46 EXPECT_EQ(Value::NONE, result.type());
47
48 // Define b, accessor should succeed now.
49 const int64_t kBValue = 42;
50 err = Err();
51 setup.scope()
52 ->GetMutableValue("a", Scope::SEARCH_NESTED, false)
53 ->scope_value()
54 ->SetValue("b", Value(nullptr, kBValue), nullptr);
55 result = accessor.Execute(setup.scope(), &err);
56 EXPECT_FALSE(err.has_error());
57 ASSERT_EQ(Value::INTEGER, result.type());
58 EXPECT_EQ(kBValue, result.int_value());
59 }
60
TEST(ParseTree,SubscriptedAccess)61 TEST(ParseTree, SubscriptedAccess) {
62 TestWithScope setup;
63 Err err;
64 TestParseInput values(
65 "list = [ 2, 3 ]\n"
66 "scope = {\n"
67 " foo = 5\n"
68 " bar = 8\n"
69 "}\n"
70 "bar_key = \"bar\""
71 "second_element_idx = 1");
72 values.parsed()->Execute(setup.scope(), &err);
73
74 EXPECT_FALSE(err.has_error());
75
76 Value first = setup.ExecuteExpression("list[0]", &err);
77 EXPECT_FALSE(err.has_error());
78 EXPECT_EQ(first.type(), Value::INTEGER);
79 EXPECT_EQ(first.int_value(), 2);
80
81 Value second = setup.ExecuteExpression("list[second_element_idx]", &err);
82 EXPECT_FALSE(err.has_error());
83 EXPECT_EQ(second.type(), Value::INTEGER);
84 EXPECT_EQ(second.int_value(), 3);
85
86 Value foo = setup.ExecuteExpression("scope[\"foo\"]", &err);
87 EXPECT_FALSE(err.has_error());
88 EXPECT_EQ(foo.type(), Value::INTEGER);
89 EXPECT_EQ(foo.int_value(), 5);
90
91 Value bar = setup.ExecuteExpression("scope[bar_key]", &err);
92 EXPECT_FALSE(err.has_error());
93 EXPECT_EQ(bar.type(), Value::INTEGER);
94 EXPECT_EQ(bar.int_value(), 8);
95
96 Value invalid1 = setup.ExecuteExpression("scope[second_element_idx]", &err);
97 EXPECT_TRUE(err.has_error());
98 err = Err();
99 EXPECT_EQ(invalid1.type(), Value::NONE);
100
101 Value invalid2 = setup.ExecuteExpression("list[bar_key]", &err);
102 EXPECT_TRUE(err.has_error());
103 err = Err();
104 EXPECT_EQ(invalid2.type(), Value::NONE);
105
106 Value invalid3 = setup.ExecuteExpression("scope[\"baz\"]", &err);
107 EXPECT_TRUE(err.has_error());
108 err = Err();
109 EXPECT_EQ(invalid3.type(), Value::NONE);
110 }
111
TEST(ParseTree,BlockUnusedVars)112 TEST(ParseTree, BlockUnusedVars) {
113 TestWithScope setup;
114
115 // Printing both values should be OK.
116 //
117 // The crazy template definition here is a way to execute a block without
118 // defining a target. Templates require that both the target_name and the
119 // invoker be used, which is what the assertion statement inside the template
120 // does.
121 TestParseInput input_all_used(
122 "template(\"foo\") { assert(target_name != 0 && invoker != 0) }\n"
123 "foo(\"a\") {\n"
124 " a = 12\n"
125 " b = 13\n"
126 " print(\"$a $b\")\n"
127 "}");
128 EXPECT_FALSE(input_all_used.has_error());
129
130 Err err;
131 input_all_used.parsed()->Execute(setup.scope(), &err);
132 EXPECT_FALSE(err.has_error());
133
134 // Skipping one should throw an unused var error.
135 TestParseInput input_unused(
136 "foo(\"a\") {\n"
137 " a = 12\n"
138 " b = 13\n"
139 " print(\"$a\")\n"
140 "}");
141 EXPECT_FALSE(input_unused.has_error());
142
143 input_unused.parsed()->Execute(setup.scope(), &err);
144 EXPECT_TRUE(err.has_error());
145
146 // Also verify that the unused variable has the correct origin set. The
147 // origin will point to the value assigned to the variable (in this case, the
148 // "13" assigned to "b".
149 EXPECT_EQ(3, err.location().line_number());
150 EXPECT_EQ(7, err.location().column_number());
151 }
152
TEST(ParseTree,OriginForDereference)153 TEST(ParseTree, OriginForDereference) {
154 TestWithScope setup;
155 TestParseInput input(
156 "a = 6\n"
157 "get_target_outputs(a)");
158 EXPECT_FALSE(input.has_error());
159
160 Err err;
161 input.parsed()->Execute(setup.scope(), &err);
162 EXPECT_TRUE(err.has_error());
163
164 // The origin for the "not a string" error message should be where the value
165 // was dereferenced (the "a" on the second line).
166 EXPECT_EQ(2, err.location().line_number());
167 EXPECT_EQ(20, err.location().column_number());
168 }
169
TEST(ParseTree,SortRangeExtraction)170 TEST(ParseTree, SortRangeExtraction) {
171 TestWithScope setup;
172
173 // Ranges are [begin, end).
174
175 {
176 TestParseInput input(
177 "sources = [\n"
178 " \"a\",\n"
179 " \"b\",\n"
180 " \n"
181 " #\n"
182 " # Block\n"
183 " #\n"
184 " \n"
185 " \"c\","
186 " \"d\","
187 "]\n");
188 EXPECT_FALSE(input.has_error());
189 ASSERT_TRUE(input.parsed()->AsBlock());
190 ASSERT_TRUE(input.parsed()->AsBlock()->statements()[0]->AsBinaryOp());
191 const BinaryOpNode* binop =
192 input.parsed()->AsBlock()->statements()[0]->AsBinaryOp();
193 ASSERT_TRUE(binop->right()->AsList());
194 const ListNode* list = binop->right()->AsList();
195 EXPECT_EQ(5u, list->contents().size());
196 auto ranges = list->GetSortRanges();
197 ASSERT_EQ(2u, ranges.size());
198 EXPECT_EQ(0u, ranges[0].begin);
199 EXPECT_EQ(2u, ranges[0].end);
200 EXPECT_EQ(3u, ranges[1].begin);
201 EXPECT_EQ(5u, ranges[1].end);
202 }
203
204 {
205 TestParseInput input(
206 "sources = [\n"
207 " \"a\",\n"
208 " \"b\",\n"
209 " \n"
210 " # Attached comment.\n"
211 " \"c\","
212 " \"d\","
213 "]\n");
214 EXPECT_FALSE(input.has_error());
215 ASSERT_TRUE(input.parsed()->AsBlock());
216 ASSERT_TRUE(input.parsed()->AsBlock()->statements()[0]->AsBinaryOp());
217 const BinaryOpNode* binop =
218 input.parsed()->AsBlock()->statements()[0]->AsBinaryOp();
219 ASSERT_TRUE(binop->right()->AsList());
220 const ListNode* list = binop->right()->AsList();
221 EXPECT_EQ(4u, list->contents().size());
222 auto ranges = list->GetSortRanges();
223 ASSERT_EQ(2u, ranges.size());
224 EXPECT_EQ(0u, ranges[0].begin);
225 EXPECT_EQ(2u, ranges[0].end);
226 EXPECT_EQ(2u, ranges[1].begin);
227 EXPECT_EQ(4u, ranges[1].end);
228 }
229
230 {
231 TestParseInput input(
232 "sources = [\n"
233 " # At end of list.\n"
234 " \"zzzzzzzzzzz.cc\","
235 "]\n");
236 EXPECT_FALSE(input.has_error());
237 ASSERT_TRUE(input.parsed()->AsBlock());
238 ASSERT_TRUE(input.parsed()->AsBlock()->statements()[0]->AsBinaryOp());
239 const BinaryOpNode* binop =
240 input.parsed()->AsBlock()->statements()[0]->AsBinaryOp();
241 ASSERT_TRUE(binop->right()->AsList());
242 const ListNode* list = binop->right()->AsList();
243 EXPECT_EQ(1u, list->contents().size());
244 auto ranges = list->GetSortRanges();
245 ASSERT_EQ(1u, ranges.size());
246 EXPECT_EQ(0u, ranges[0].begin);
247 EXPECT_EQ(1u, ranges[0].end);
248 }
249
250 {
251 TestParseInput input(
252 "sources = [\n"
253 " # Block at start.\n"
254 " \n"
255 " \"z.cc\","
256 " \"y.cc\","
257 "]\n");
258 EXPECT_FALSE(input.has_error());
259 ASSERT_TRUE(input.parsed()->AsBlock());
260 ASSERT_TRUE(input.parsed()->AsBlock()->statements()[0]->AsBinaryOp());
261 const BinaryOpNode* binop =
262 input.parsed()->AsBlock()->statements()[0]->AsBinaryOp();
263 ASSERT_TRUE(binop->right()->AsList());
264 const ListNode* list = binop->right()->AsList();
265 EXPECT_EQ(3u, list->contents().size());
266 auto ranges = list->GetSortRanges();
267 ASSERT_EQ(1u, ranges.size());
268 EXPECT_EQ(1u, ranges[0].begin);
269 EXPECT_EQ(3u, ranges[0].end);
270 }
271 }
272
TEST(ParseTree,Integers)273 TEST(ParseTree, Integers) {
274 static const char* const kGood[] = {
275 "0",
276 "10",
277 "-54321",
278 "9223372036854775807", // INT64_MAX
279 "-9223372036854775808", // INT64_MIN
280 };
281 for (auto* s : kGood) {
282 TestParseInput input(std::string("x = ") + s);
283 EXPECT_FALSE(input.has_error());
284
285 TestWithScope setup;
286 Err err;
287 input.parsed()->Execute(setup.scope(), &err);
288 EXPECT_FALSE(err.has_error());
289 }
290
291 static const char* const kBad[] = {
292 "-0",
293 "010",
294 "-010",
295 "9223372036854775808", // INT64_MAX + 1
296 "-9223372036854775809", // INT64_MIN - 1
297 };
298 for (auto* s : kBad) {
299 TestParseInput input(std::string("x = ") + s);
300 EXPECT_FALSE(input.has_error());
301
302 TestWithScope setup;
303 Err err;
304 input.parsed()->Execute(setup.scope(), &err);
305 EXPECT_TRUE(err.has_error());
306 }
307 }
308