• 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), 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