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