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