• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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