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