1// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/compiler/backend/sexpression.h"
6
7#include <cmath>
8#include "platform/assert.h"
9#include "vm/unit_test.h"
10
11namespace dart {
12
13#define EXPECT_SEXP_PARSE_ERROR(sexp, parser, pos, message) \
14 do { \
15 if (sexp != nullptr) { \
16 dart::Expect(__FILE__, __LINE__) \
17 .Fail("parse unexpectedly succeeded for \"%s\"", parser.Input()); \
18 } \
19 EXPECT_EQ(pos, parser.error_pos()); \
20 EXPECT_STREQ(message, parser.error_message()); \
21 } while (false);
22
23#define EXPECT_SEXP_PARSE_SUCCESS(sexp, parser) \
24 do { \
25 if (sexp == nullptr) { \
26 EXPECT_NOTNULL(parser.error_message()); \
27 dart::Expect(__FILE__, __LINE__) \
28 .Fail("parse unexpectedly failed at \"%s\": %" Pd ": %s", \
29 parser.Input() + parser.error_pos(), parser.error_pos(), \
30 parser.error_message()); \
31 } \
32 } while (false);
33
34static const char* const shared_sexp_cstr =
35 "(def v0 (Constant 3) { type (CompileType 147 { nullable false, name "
36 "\"T{Smi}\"}), })";
37
38static void CheckDeserializedSExpParts(SExpression* sexp) {
39 EXPECT_NOTNULL(sexp);
40 EXPECT(sexp->IsList());
41 SExpList* list = sexp->AsList();
42 EXPECT_EQ(3, list->Length());
43 EXPECT_NOTNULL(list->At(0));
44 EXPECT(list->At(0)->IsSymbol());
45 EXPECT_STREQ("def", list->At(0)->AsSymbol()->value());
46 EXPECT_NOTNULL(list->At(1));
47 EXPECT(list->At(1)->IsSymbol());
48 EXPECT_STREQ("v0", list->At(1)->AsSymbol()->value());
49 EXPECT_NOTNULL(list->At(2));
50 EXPECT(list->At(2)->IsList());
51
52 SExpList* sublist = list->At(2)->AsList();
53 EXPECT_EQ(2, sublist->Length());
54 EXPECT_NOTNULL(sublist->At(0));
55 EXPECT(sublist->At(0)->IsSymbol());
56 EXPECT_STREQ("Constant", sublist->At(0)->AsSymbol()->value());
57 EXPECT_NOTNULL(sublist->At(1));
58 EXPECT(sublist->At(1)->IsInteger());
59 EXPECT_EQ(3, sublist->At(1)->AsInteger()->value());
60 EXPECT_EQ(0, sublist->ExtraLength());
61
62 EXPECT_EQ(1, list->ExtraLength());
63 EXPECT(list->ExtraHasKey("type"));
64 EXPECT(list->ExtraLookupValue("type")->IsList());
65
66 SExpList* ctype = list->ExtraLookupValue("type")->AsList();
67 EXPECT_EQ(2, ctype->Length());
68 EXPECT_NOTNULL(ctype->At(0));
69 EXPECT(ctype->At(0)->IsSymbol());
70 EXPECT_STREQ("CompileType", ctype->At(0)->AsSymbol()->value());
71 EXPECT_NOTNULL(ctype->At(1));
72 EXPECT(ctype->At(1)->IsInteger());
73 EXPECT_EQ(147, ctype->At(1)->AsInteger()->value());
74
75 EXPECT_EQ(2, ctype->ExtraLength());
76 EXPECT(ctype->ExtraHasKey("nullable"));
77 EXPECT(ctype->ExtraLookupValue("nullable")->IsBool());
78 EXPECT(!ctype->ExtraLookupValue("nullable")->AsBool()->value());
79 EXPECT(ctype->ExtraHasKey("name"));
80 EXPECT(ctype->ExtraLookupValue("name")->IsString());
81 EXPECT_STREQ(ctype->ExtraLookupValue("name")->AsString()->value(), "T{Smi}");
82}
83
84ISOLATE_UNIT_TEST_CASE(DeserializeSExp) {
85 Zone* const zone = Thread::Current()->zone();
86 SExpression* sexp = SExpression::FromCString(zone, shared_sexp_cstr);
87 CheckDeserializedSExpParts(sexp);
88
89 // Treating escaped backslash appropriately so string is terminated.
90 {
91 const char* const cstr = "(def v0 (Constant 3) { foo \"123\\\\\" })";
92 SExpParser parser(zone, cstr, strlen(cstr));
93 SExpression* const sexp = parser.Parse();
94 EXPECT_SEXP_PARSE_SUCCESS(sexp, parser);
95 EXPECT(sexp->IsList());
96 EXPECT_EQ(1, sexp->AsList()->ExtraLength());
97 EXPECT(sexp->AsList()->ExtraHasKey("foo"));
98 auto val = sexp->AsList()->ExtraLookupValue("foo");
99 EXPECT(val->IsString());
100 EXPECT_STREQ("123\\", val->AsString()->value());
101 }
102 // Valid unicode escapes are properly handled.
103 {
104 const char* const cstr =
105 "(def v0 (Constant 3) { foo \"\\u0001\\u0020\\u0054\" })";
106 SExpParser parser(zone, cstr, strlen(cstr));
107 SExpression* const sexp = parser.Parse();
108 EXPECT_SEXP_PARSE_SUCCESS(sexp, parser);
109 EXPECT(sexp->IsList());
110 EXPECT_EQ(1, sexp->AsList()->ExtraLength());
111 EXPECT(sexp->AsList()->ExtraHasKey("foo"));
112 auto val = sexp->AsList()->ExtraLookupValue("foo");
113 EXPECT(val->IsString());
114 EXPECT_STREQ("\x01 T", val->AsString()->value());
115 }
116}
117
118ISOLATE_UNIT_TEST_CASE(DeserializeSExpNumbers) {
119 Zone* const zone = Thread::Current()->zone();
120
121 // Negative integers are handled.
122 {
123 const char* const cstr = "(-4 -50 -1414243)";
124 SExpParser parser(zone, cstr, strlen(cstr));
125 SExpression* const sexp = parser.Parse();
126 EXPECT_SEXP_PARSE_SUCCESS(sexp, parser);
127 EXPECT(sexp->IsList());
128 auto list = sexp->AsList();
129 EXPECT_EQ(3, list->Length());
130 EXPECT_EQ(0, list->ExtraLength());
131 for (intptr_t i = 0; i < list->Length(); i++) {
132 EXPECT(list->At(i)->IsInteger());
133 EXPECT(list->At(i)->AsInteger()->value() < 0);
134 }
135 }
136
137 // Various decimal/exponent Doubles are appropriately handled.
138 {
139 const char* const cstr = "(1.05 0.05 .03 1e100 1e-100)";
140 SExpParser parser(zone, cstr, strlen(cstr));
141 SExpression* const sexp = parser.Parse();
142 EXPECT_SEXP_PARSE_SUCCESS(sexp, parser);
143 EXPECT(sexp->IsList());
144 auto list = sexp->AsList();
145 EXPECT_EQ(5, list->Length());
146 EXPECT_EQ(0, list->ExtraLength());
147 EXPECT(list->At(0)->IsDouble());
148 double val = list->At(0)->AsDouble()->value();
149 EXPECT(val > 1.04 && val < 1.06);
150 EXPECT(list->At(1)->IsDouble());
151 val = list->At(1)->AsDouble()->value();
152 EXPECT(val > 0.04 && val < 0.06);
153 EXPECT(list->At(2)->IsDouble());
154 val = list->At(2)->AsDouble()->value();
155 EXPECT(val > 0.02 && val < 0.04);
156 EXPECT(list->At(3)->IsDouble());
157 val = list->At(3)->AsDouble()->value();
158 EXPECT(val > 0.9e100 && val < 1.1e100);
159 EXPECT(list->At(4)->IsDouble());
160 val = list->At(4)->AsDouble()->value();
161 EXPECT(val > 0.9e-100 && val < 1.1e-100);
162 }
163
164 // Special Double symbols are appropriately handled.
165 {
166 const char* const cstr = "(NaN Infinity -Infinity)";
167 SExpParser parser(zone, cstr, strlen(cstr));
168 SExpression* const sexp = parser.Parse();
169 EXPECT_SEXP_PARSE_SUCCESS(sexp, parser);
170 EXPECT(sexp->IsList());
171 auto list = sexp->AsList();
172 EXPECT_EQ(3, list->Length());
173 EXPECT_EQ(0, list->ExtraLength());
174 EXPECT(list->At(0)->IsDouble());
175 double val = list->At(0)->AsDouble()->value();
176 EXPECT(isnan(val));
177 EXPECT(list->At(1)->IsDouble());
178 val = list->At(1)->AsDouble()->value();
179 EXPECT(val > 0.0);
180 EXPECT(isinf(val));
181 EXPECT(list->At(2)->IsDouble());
182 val = list->At(2)->AsDouble()->value();
183 EXPECT(val < 0.0);
184 EXPECT(isinf(val));
185 }
186}
187
188ISOLATE_UNIT_TEST_CASE(DeserializeSExpRoundTrip) {
189 Zone* const zone = Thread::Current()->zone();
190 SExpression* sexp = SExpression::FromCString(zone, shared_sexp_cstr);
191
192 TextBuffer buf(100);
193 sexp->SerializeTo(zone, &buf, "", 9999);
194 SExpression* round_trip = SExpression::FromCString(zone, buf.buffer());
195 CheckDeserializedSExpParts(round_trip);
196 EXPECT(sexp->Equals(round_trip));
197
198 char* const old_serialization = buf.Steal();
199 round_trip->SerializeTo(zone, &buf, "", 9999);
200 char* const new_serialization = buf.buffer();
201 EXPECT_STREQ(old_serialization, new_serialization);
202 free(old_serialization);
203}
204
205ISOLATE_UNIT_TEST_CASE(DeserializeSExpMapsJoined) {
206 Zone* const zone = Thread::Current()->zone();
207 // Same as shared_sexp_cstr except we split the map on the CompileType into
208 // two parts.
209 const char* const cstr =
210 "(def v0 (Constant 3) { type (CompileType { nullable false } 147 { name "
211 "\"T{Smi}\"}), })";
212 SExpression* sexp = SExpression::FromCString(zone, cstr);
213 CheckDeserializedSExpParts(sexp);
214}
215
216ISOLATE_UNIT_TEST_CASE(DeserializeSExpFailures) {
217 Zone* const zone = Thread::Current()->zone();
218 // Unterminated s-exp list
219 {
220 const char* const before_start = "(def v0 ";
221 const char* const after_start = "(Constant 3";
222 const char* const cstr =
223 OS::SCreate(zone, "%s%s", before_start, after_start);
224 const intptr_t start_pos = strlen(before_start);
225 const intptr_t error_pos = strlen(cstr);
226 SExpParser parser(zone, cstr, strlen(cstr));
227 SExpression* const sexp = parser.Parse();
228 const char* const expected_message =
229 OS::SCreate(zone, SExpParser::ErrorStrings::kOpenSExpList, start_pos);
230 EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
231 }
232 // Non-symbol label in map pair
233 {
234 const char* const before_error = "(def v0 (Constant 3) { ";
235 const intptr_t error_pos = strlen(before_error);
236 const char* const error = "3 4 })";
237 const char* const cstr = OS::SCreate(zone, "%s%s", before_error, error);
238 SExpParser parser(zone, cstr, strlen(cstr));
239 SExpression* const sexp = parser.Parse();
240 const char* const expected_message =
241 SExpParser::ErrorStrings::kNonSymbolLabel;
242 EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
243 }
244 // No values in a map pair
245 {
246 const char* const label = "foo";
247 const char* const before_error =
248 OS::SCreate(zone, "(def v0 (Constant 3) { %s ", label);
249 const intptr_t error_pos = strlen(before_error);
250 const char* const error = "})";
251 const char* const cstr = OS::SCreate(zone, "%s%s", before_error, error);
252 SExpParser parser(zone, cstr, strlen(cstr));
253 SExpression* const sexp = parser.Parse();
254 const char* const expected_message =
255 OS::SCreate(zone, SExpParser::ErrorStrings::kNoMapValue, label);
256 EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
257 }
258 // Multiple values in a map pair
259 {
260 const char* const label = "foo";
261 const char* const before_error =
262 OS::SCreate(zone, "(def v0 (Constant 3) { %s 4 ", label);
263 const intptr_t error_pos = strlen(before_error);
264 const char* const error = "5, })";
265 const char* const cstr = OS::SCreate(zone, "%s%s", before_error, error);
266 SExpParser parser(zone, cstr, strlen(cstr));
267 SExpression* const sexp = parser.Parse();
268 const char* const expected_message =
269 OS::SCreate(zone, SExpParser::ErrorStrings::kExtraMapValue, label);
270 EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
271 }
272 // Unterminated quoted string
273 {
274 const char* const before_string =
275 OS::SCreate(zone, "(def v0 (Constant 3) { foo ");
276 const intptr_t string_pos = strlen(before_string);
277 const char* const error = "\"abc })";
278 const char* const cstr = OS::SCreate(zone, "%s%s", before_string, error);
279 const intptr_t error_pos = strlen(cstr);
280 SExpParser parser(zone, cstr, strlen(cstr));
281 SExpression* const sexp = parser.Parse();
282 const char* const expected_message =
283 OS::SCreate(zone, SExpParser::ErrorStrings::kOpenString, string_pos);
284 EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
285 }
286 // Unterminated extra info map
287 {
288 const char* const before_map = "(def v0 (Constant 3) ";
289 const intptr_t map_pos = strlen(before_map);
290 const char* const map_start = "{ foo 3, ";
291 const char* const before_error =
292 OS::SCreate(zone, "%s%s", before_map, map_start);
293 const intptr_t error_pos = strlen(before_error);
294 const char* const error = ")";
295 const char* const cstr = OS::SCreate(zone, "%s%s", before_error, error);
296 SExpParser parser(zone, cstr, strlen(cstr));
297 SExpression* const sexp = parser.Parse();
298 const char* const expected_message =
299 OS::SCreate(zone, SExpParser::ErrorStrings::kOpenMap, map_pos);
300 EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
301 }
302 // Repeated extra info map label
303 {
304 const char* const label = "foo";
305 const char* const before_error =
306 OS::SCreate(zone, "(def v0 (Constant 3) { %s 3, ", label);
307 const intptr_t error_pos = strlen(before_error);
308 const char* const error = OS::SCreate(zone, "%s 4, })", label);
309 const char* const cstr = OS::SCreate(zone, "%s%s", before_error, error);
310 SExpParser parser(zone, cstr, strlen(cstr));
311 SExpression* const sexp = parser.Parse();
312 const char* const expected_message =
313 OS::SCreate(zone, SExpParser::ErrorStrings::kRepeatedMapLabel, label);
314 EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
315 }
316 // Unicode escape with non-hex digits.
317 {
318 const char* const before_error = "(def v0 (Constant 3) { foo \"123";
319 const intptr_t error_pos = strlen(before_error);
320 const char* const error = "\\u12FG\" })";
321 const char* const cstr = OS::SCreate(zone, "%s%s", before_error, error);
322 SExpParser parser(zone, cstr, strlen(cstr));
323 SExpression* const sexp = parser.Parse();
324 const char* const expected_message =
325 SExpParser::ErrorStrings::kBadUnicodeEscape;
326 EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
327 }
328 // Unicode escape with less than four hex digits.
329 {
330 const char* const before_error = "(def v0 (Constant 3) { foo \"123";
331 const intptr_t error_pos = strlen(before_error);
332 const char* const error = "\\u12\" })";
333 const char* const cstr = OS::SCreate(zone, "%s%s", before_error, error);
334 SExpParser parser(zone, cstr, strlen(cstr));
335 SExpression* const sexp = parser.Parse();
336 const char* const expected_message =
337 SExpParser::ErrorStrings::kBadUnicodeEscape;
338 EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
339 }
340 // Treating backslashed quote appropriately to detect unterminated string
341 {
342 const char* const before_string = "(def v0 (Constant 3) { foo ";
343 const intptr_t string_pos = strlen(before_string);
344 const char* const error = "\"123\\\" })";
345 const char* const cstr = OS::SCreate(zone, "%s%s", before_string, error);
346 const intptr_t error_pos = strlen(cstr);
347 SExpParser parser(zone, cstr, strlen(cstr));
348 SExpression* const sexp = parser.Parse();
349 const char* const expected_message =
350 OS::SCreate(zone, SExpParser::ErrorStrings::kOpenString, string_pos);
351 EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
352 }
353}
354
355} // namespace dart
356