1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
2 // Licensed under the MIT License:
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22 #if _WIN32
23 #include <kj/win32-api-version.h>
24 #endif
25
26 #include "parser.h"
27 #include "type-id.h"
28 #include <capnp/dynamic.h>
29 #include <kj/debug.h>
30 #include <kj/encoding.h>
31 #if !_MSC_VER
32 #include <unistd.h>
33 #endif
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37
38 #if _WIN32
39 #include <windows.h>
40 #include <wincrypt.h>
41 #undef CONST
42 #include <kj/windows-sanity.h>
43 #endif
44
45 namespace capnp {
46 namespace compiler {
47
generateRandomId()48 uint64_t generateRandomId() {
49 uint64_t result;
50
51 #if _WIN32
52 HCRYPTPROV handle;
53 KJ_ASSERT(CryptAcquireContextW(&handle, nullptr, nullptr,
54 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT));
55 KJ_DEFER(KJ_ASSERT(CryptReleaseContext(handle, 0)) {break;});
56
57 KJ_ASSERT(CryptGenRandom(handle, sizeof(result), reinterpret_cast<BYTE*>(&result)));
58
59 #else
60 int fd;
61 KJ_SYSCALL(fd = open("/dev/urandom", O_RDONLY));
62
63 ssize_t n;
64 KJ_SYSCALL(n = read(fd, &result, sizeof(result)), "/dev/urandom");
65 KJ_ASSERT(n == sizeof(result), "Incomplete read from /dev/urandom.", n);
66 #endif
67
68 return result | (1ull << 63);
69 }
70
parseFile(List<Statement>::Reader statements,ParsedFile::Builder result,ErrorReporter & errorReporter)71 void parseFile(List<Statement>::Reader statements, ParsedFile::Builder result,
72 ErrorReporter& errorReporter) {
73 CapnpParser parser(Orphanage::getForMessageContaining(result), errorReporter);
74
75 kj::Vector<Orphan<Declaration>> decls(statements.size());
76 kj::Vector<Orphan<Declaration::AnnotationApplication>> annotations;
77
78 auto fileDecl = result.getRoot();
79 fileDecl.setFile(VOID);
80
81 for (auto statement: statements) {
82 KJ_IF_MAYBE(decl, parser.parseStatement(statement, parser.getParsers().fileLevelDecl)) {
83 Declaration::Builder builder = decl->get();
84 switch (builder.which()) {
85 case Declaration::NAKED_ID:
86 if (fileDecl.getId().isUid()) {
87 errorReporter.addError(builder.getStartByte(), builder.getEndByte(),
88 "File can only have one ID.");
89 } else {
90 fileDecl.getId().adoptUid(builder.disownNakedId());
91 if (builder.hasDocComment()) {
92 fileDecl.adoptDocComment(builder.disownDocComment());
93 }
94 }
95 break;
96 case Declaration::NAKED_ANNOTATION:
97 annotations.add(builder.disownNakedAnnotation());
98 break;
99 default:
100 decls.add(kj::mv(*decl));
101 break;
102 }
103 }
104 }
105
106 if (fileDecl.getId().which() != Declaration::Id::UID) {
107 // We didn't see an ID. Generate one randomly for now.
108 uint64_t id = generateRandomId();
109 fileDecl.getId().initUid().setValue(id);
110
111 // Don't report missing ID if there was a parse error, because quite often the parse error
112 // prevents us from parsing the ID even though it is actually there.
113 if (!errorReporter.hadErrors()) {
114 errorReporter.addError(0, 0,
115 kj::str("File does not declare an ID. I've generated one for you. Add this line to "
116 "your file: @0x", kj::hex(id), ";"));
117 }
118 }
119
120 auto declsBuilder = fileDecl.initNestedDecls(decls.size());
121 for (size_t i = 0; i < decls.size(); i++) {
122 declsBuilder.adoptWithCaveats(i, kj::mv(decls[i]));
123 }
124
125 auto annotationsBuilder = fileDecl.initAnnotations(annotations.size());
126 for (size_t i = 0; i < annotations.size(); i++) {
127 annotationsBuilder.adoptWithCaveats(i, kj::mv(annotations[i]));
128 }
129 }
130
131 namespace p = kj::parse;
132
133 namespace {
134
135 // =======================================================================================
136
137 template <typename T>
138 struct Located {
139 T value;
140 uint32_t startByte;
141 uint32_t endByte;
142
143 template <typename Builder>
copyLocationTocapnp::compiler::__anonbd3fe9d30111::Located144 void copyLocationTo(Builder builder) {
145 builder.setStartByte(startByte);
146 builder.setEndByte(endByte);
147 }
148 template <typename Builder>
copyTocapnp::compiler::__anonbd3fe9d30111::Located149 void copyTo(Builder builder) {
150 builder.setValue(value);
151 copyLocationTo(builder);
152 }
153 template <typename Result>
asProtocapnp::compiler::__anonbd3fe9d30111::Located154 Orphan<Result> asProto(Orphanage orphanage) {
155 auto result = orphanage.newOrphan<Result>();
156 copyTo(result.get());
157 return result;
158 }
159 template <typename Other>
rewrapcapnp::compiler::__anonbd3fe9d30111::Located160 Located<kj::Decay<Other>> rewrap(Other&& other) {
161 return Located<Other>(kj::fwd<Other>(other), startByte, endByte);
162 }
163
Locatedcapnp::compiler::__anonbd3fe9d30111::Located164 Located(const T& value, uint32_t startByte, uint32_t endByte)
165 : value(value), startByte(startByte), endByte(endByte) {}
Locatedcapnp::compiler::__anonbd3fe9d30111::Located166 Located(T&& value, uint32_t startByte, uint32_t endByte)
167 : value(kj::mv(value)), startByte(startByte), endByte(endByte) {}
168 };
169
170 // =======================================================================================
171
172 template <typename T, Token::Which type, T (Token::Reader::*get)() const>
173 struct MatchTokenType {
operator ()capnp::compiler::__anonbd3fe9d30111::MatchTokenType174 kj::Maybe<Located<T>> operator()(Token::Reader token) const {
175 if (token.which() == type) {
176 return Located<T>((token.*get)(), token.getStartByte(), token.getEndByte());
177 } else {
178 return nullptr;
179 }
180 }
181 };
182
183 #define TOKEN_TYPE_PARSER(type, discrim, getter) \
184 p::transformOrReject(p::any, \
185 MatchTokenType<type, Token::discrim, &Token::Reader::getter>())
186
187 constexpr auto identifier = TOKEN_TYPE_PARSER(Text::Reader, IDENTIFIER, getIdentifier);
188 constexpr auto stringLiteral = TOKEN_TYPE_PARSER(Text::Reader, STRING_LITERAL, getStringLiteral);
189 constexpr auto binaryLiteral = TOKEN_TYPE_PARSER(Data::Reader, BINARY_LITERAL, getBinaryLiteral);
190 constexpr auto integerLiteral = TOKEN_TYPE_PARSER(uint64_t, INTEGER_LITERAL, getIntegerLiteral);
191 constexpr auto floatLiteral = TOKEN_TYPE_PARSER(double, FLOAT_LITERAL, getFloatLiteral);
192 constexpr auto operatorToken = TOKEN_TYPE_PARSER(Text::Reader, OPERATOR, getOperator);
193 constexpr auto rawParenthesizedList =
194 TOKEN_TYPE_PARSER(List<List<Token>>::Reader, PARENTHESIZED_LIST, getParenthesizedList);
195 constexpr auto rawBracketedList =
196 TOKEN_TYPE_PARSER(List<List<Token>>::Reader, BRACKETED_LIST, getBracketedList);
197
198 // =======================================================================================
199
200 class ExactString {
201 public:
ExactString(const char * expected)202 constexpr ExactString(const char* expected): expected(expected) {}
203
operator ()(Located<Text::Reader> && text) const204 kj::Maybe<kj::Tuple<>> operator()(Located<Text::Reader>&& text) const {
205 if (text.value == expected) {
206 return kj::Tuple<>();
207 } else {
208 return nullptr;
209 }
210 }
211
212 private:
213 const char* expected;
214 };
215
keyword(const char * expected)216 constexpr auto keyword(const char* expected)
217 -> decltype(p::transformOrReject(identifier, ExactString(expected))) {
218 return p::transformOrReject(identifier, ExactString(expected));
219 }
220
op(const char * expected)221 constexpr auto op(const char* expected)
222 -> decltype(p::transformOrReject(operatorToken, ExactString(expected))) {
223 return p::transformOrReject(operatorToken, ExactString(expected));
224 }
225
226 class LocatedExactString {
227 public:
LocatedExactString(const char * expected)228 constexpr LocatedExactString(const char* expected): expected(expected) {}
229
operator ()(Located<Text::Reader> && text) const230 kj::Maybe<Located<Text::Reader>> operator()(Located<Text::Reader>&& text) const {
231 if (text.value == expected) {
232 return kj::mv(text);
233 } else {
234 return nullptr;
235 }
236 }
237
238 private:
239 const char* expected;
240 };
241
locatedKeyword(const char * expected)242 constexpr auto locatedKeyword(const char* expected)
243 -> decltype(p::transformOrReject(identifier, LocatedExactString(expected))) {
244 return p::transformOrReject(identifier, LocatedExactString(expected));
245 }
246
247 // =======================================================================================
248
249 template <typename ItemParser>
250 class ParseListItems {
251 // Transformer that parses all items in the input token sequence list using the given parser.
252
253 public:
ParseListItems(ItemParser && itemParser,ErrorReporter & errorReporter)254 constexpr ParseListItems(ItemParser&& itemParser, ErrorReporter& errorReporter)
255 : itemParser(p::sequence(kj::fwd<ItemParser>(itemParser), p::endOfInput)),
256 errorReporter(errorReporter) {}
257
operator ()(Located<List<List<Token>>::Reader> && items) const258 Located<kj::Array<kj::Maybe<p::OutputType<ItemParser, CapnpParser::ParserInput>>>> operator()(
259 Located<List<List<Token>>::Reader>&& items) const {
260 auto result = kj::heapArray<kj::Maybe<p::OutputType<ItemParser, CapnpParser::ParserInput>>>(
261 items.value.size());
262 for (uint i = 0; i < items.value.size(); i++) {
263 auto item = items.value[i];
264 CapnpParser::ParserInput input(item.begin(), item.end());
265 result[i] = itemParser(input);
266 if (result[i] == nullptr) {
267 // Parsing failed. Report an error.
268 auto best = input.getBest();
269 if (best < item.end()) {
270 // Report error from the point where parsing failed to the end of the item.
271 errorReporter.addError(
272 best->getStartByte(), (item.end() - 1)->getEndByte(), "Parse error.");
273 } else if (item.size() > 0) {
274 // The item is non-empty and the parser consumed all of it before failing. Report an
275 // error for the whole thing.
276 errorReporter.addError(
277 item.begin()->getStartByte(), (item.end() - 1)->getEndByte(), "Parse error.");
278 } else {
279 // The item has no content.
280 // TODO(cleanup): We don't actually know the item's location, so we can only report
281 // an error across the whole list. Fix this.
282 errorReporter.addError(items.startByte, items.endByte, "Parse error: Empty list item.");
283 }
284 }
285 }
286 return Located<kj::Array<kj::Maybe<p::OutputType<ItemParser, CapnpParser::ParserInput>>>>(
287 kj::mv(result), items.startByte, items.endByte);
288 }
289
290 private:
291 decltype(p::sequence(kj::instance<ItemParser>(), p::endOfInput)) itemParser;
292 ErrorReporter& errorReporter;
293 };
294
295 template <typename ItemParser>
parenthesizedList(ItemParser && itemParser,ErrorReporter & errorReporter)296 constexpr auto parenthesizedList(ItemParser&& itemParser, ErrorReporter& errorReporter) -> decltype(
297 transform(rawParenthesizedList, ParseListItems<ItemParser>(
298 kj::fwd<ItemParser>(itemParser), errorReporter))) {
299 return transform(rawParenthesizedList, ParseListItems<ItemParser>(
300 kj::fwd<ItemParser>(itemParser), errorReporter));
301 }
302
303 template <typename ItemParser>
bracketedList(ItemParser && itemParser,ErrorReporter & errorReporter)304 constexpr auto bracketedList(ItemParser&& itemParser, ErrorReporter& errorReporter) -> decltype(
305 transform(rawBracketedList, ParseListItems<ItemParser>(
306 kj::fwd<ItemParser>(itemParser), errorReporter))) {
307 return transform(rawBracketedList, ParseListItems<ItemParser>(
308 kj::fwd<ItemParser>(itemParser), errorReporter));
309 }
310
311 // =======================================================================================
312
313 template <typename T>
arrayToList(Orphanage & orphanage,kj::Array<Orphan<T>> && elements)314 Orphan<List<T>> arrayToList(Orphanage& orphanage, kj::Array<Orphan<T>>&& elements) {
315 auto result = orphanage.newOrphan<List<T>>(elements.size());
316 auto builder = result.get();
317 for (size_t i = 0; i < elements.size(); i++) {
318 builder.adoptWithCaveats(i, kj::mv(elements[i]));
319 }
320 return kj::mv(result);
321 }
322
initGenericParams(Declaration::Builder builder,kj::Maybe<Located<kj::Array<kj::Maybe<Located<Text::Reader>>>>> && genericParameters)323 static void initGenericParams(Declaration::Builder builder,
324 kj::Maybe<Located<kj::Array<kj::Maybe<Located<Text::Reader>>>>>&& genericParameters) {
325 KJ_IF_MAYBE(p, genericParameters) {
326 auto params = builder.initParameters(p->value.size());
327 for (uint i: kj::indices(p->value)) {
328 KJ_IF_MAYBE(name, p->value[i]) {
329 auto param = params[i];
330 param.setName(name->value);
331 name->copyLocationTo(param);
332 }
333 }
334 }
335 }
336
initDecl(Declaration::Builder builder,Located<Text::Reader> && name,kj::Maybe<Orphan<LocatedInteger>> && id,kj::Maybe<Located<kj::Array<kj::Maybe<Located<Text::Reader>>>>> && genericParameters,kj::Array<Orphan<Declaration::AnnotationApplication>> && annotations)337 static Declaration::Builder initDecl(
338 Declaration::Builder builder, Located<Text::Reader>&& name,
339 kj::Maybe<Orphan<LocatedInteger>>&& id,
340 kj::Maybe<Located<kj::Array<kj::Maybe<Located<Text::Reader>>>>>&& genericParameters,
341 kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations) {
342 name.copyTo(builder.initName());
343 KJ_IF_MAYBE(i, id) {
344 builder.getId().adoptUid(kj::mv(*i));
345 }
346
347 initGenericParams(builder, kj::mv(genericParameters));
348
349 auto list = builder.initAnnotations(annotations.size());
350 for (uint i = 0; i < annotations.size(); i++) {
351 list.adoptWithCaveats(i, kj::mv(annotations[i]));
352 }
353 return builder;
354 }
355
initMemberDecl(Declaration::Builder builder,Located<Text::Reader> && name,Orphan<LocatedInteger> && ordinal,kj::Array<Orphan<Declaration::AnnotationApplication>> && annotations)356 static Declaration::Builder initMemberDecl(
357 Declaration::Builder builder, Located<Text::Reader>&& name,
358 Orphan<LocatedInteger>&& ordinal,
359 kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations) {
360 name.copyTo(builder.initName());
361 builder.getId().adoptOrdinal(kj::mv(ordinal));
362 auto list = builder.initAnnotations(annotations.size());
363 for (uint i = 0; i < annotations.size(); i++) {
364 list.adoptWithCaveats(i, kj::mv(annotations[i]));
365 }
366 return builder;
367 }
368
369 template <typename BuilderType>
initLocation(kj::parse::Span<typename List<Token>::Reader::Iterator> location,BuilderType builder)370 void initLocation(kj::parse::Span<typename List<Token>::Reader::Iterator> location,
371 BuilderType builder) {
372 if (location.begin() < location.end()) {
373 builder.setStartByte(location.begin()->getStartByte());
374 builder.setEndByte((location.end() - 1)->getEndByte());
375 }
376 }
377
378 } // namespace
379
380 // =======================================================================================
381
CapnpParser(Orphanage orphanageParam,ErrorReporter & errorReporterParam)382 CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterParam)
383 : orphanage(orphanageParam), errorReporter(errorReporterParam) {
384 auto& tupleElement = arena.copy(p::transform(
385 p::sequence(p::optional(p::sequence(identifier, op("="))), parsers.expression),
386 [this](kj::Maybe<Located<Text::Reader>>&& fieldName, Orphan<Expression>&& fieldValue)
387 -> Orphan<Expression::Param> {
388 auto result = orphanage.newOrphan<Expression::Param>();
389 auto builder = result.get();
390 KJ_IF_MAYBE(fn, fieldName) {
391 fn->copyTo(builder.initNamed());
392 } else {
393 builder.setUnnamed();
394 }
395 builder.adoptValue(kj::mv(fieldValue));
396 return kj::mv(result);
397 }));
398
399 auto& tuple = arena.copy<Parser<Located<Orphan<List<Expression::Param>>>>>(
400 arena.copy(p::transform(
401 parenthesizedList(tupleElement, errorReporter),
402 [this](Located<kj::Array<kj::Maybe<Orphan<Expression::Param>>>>&& elements)
403 -> Located<Orphan<List<Expression::Param>>> {
404 auto result = orphanage.newOrphan<List<Expression::Param>>(elements.value.size());
405 auto builder = result.get();
406 for (uint i: kj::indices(elements.value)) {
407 KJ_IF_MAYBE(e, elements.value[i]) {
408 builder.adoptWithCaveats(i, kj::mv(*e));
409 } else {
410 builder[i].initValue().setUnknown();
411 }
412 }
413 return elements.rewrap(kj::mv(result));
414 })));
415
416 parsers.expression = arena.copy(p::transform(
417 p::sequence(
418 // Base expression.
419 p::oneOf(
420 p::transform(integerLiteral,
421 [this](Located<uint64_t>&& value) -> Orphan<Expression> {
422 auto result = orphanage.newOrphan<Expression>();
423 auto builder = result.get();
424 builder.setPositiveInt(value.value);
425 value.copyLocationTo(builder);
426 return result;
427 }),
428 p::transform(p::sequence(op("-"), integerLiteral),
429 [this](Located<uint64_t>&& value) -> Orphan<Expression> {
430 auto result = orphanage.newOrphan<Expression>();
431 auto builder = result.get();
432 builder.setNegativeInt(value.value);
433 value.copyLocationTo(builder);
434 return result;
435 }),
436 p::transform(floatLiteral,
437 [this](Located<double>&& value) -> Orphan<Expression> {
438 auto result = orphanage.newOrphan<Expression>();
439 auto builder = result.get();
440 builder.setFloat(value.value);
441 value.copyLocationTo(builder);
442 return result;
443 }),
444 p::transform(p::sequence(op("-"), floatLiteral),
445 [this](Located<double>&& value) -> Orphan<Expression> {
446 auto result = orphanage.newOrphan<Expression>();
447 auto builder = result.get();
448 builder.setFloat(-value.value);
449 value.copyLocationTo(builder);
450 return result;
451 }),
452 p::transformWithLocation(p::sequence(op("-"), keyword("inf")),
453 [this](kj::parse::Span<List<Token>::Reader::Iterator> location)
454 -> Orphan<Expression> {
455 auto result = orphanage.newOrphan<Expression>();
456 auto builder = result.get();
457 builder.setFloat(-kj::inf());
458 initLocation(location, builder);
459 return result;
460 }),
461 p::transform(p::oneOrMore(stringLiteral),
462 [this](kj::Array<Located<Text::Reader>>&& value) -> Orphan<Expression> {
463 auto result = orphanage.newOrphan<Expression>();
464 auto builder = result.get();
465 builder.setString(kj::strArray(
466 KJ_MAP(part, value) { return part.value; }, ""));
467 builder.setStartByte(value.front().startByte);
468 builder.setEndByte(value.back().endByte);
469 return result;
470 }),
471 p::transform(binaryLiteral,
472 [this](Located<Data::Reader>&& value) -> Orphan<Expression> {
473 auto result = orphanage.newOrphan<Expression>();
474 auto builder = result.get();
475 builder.setBinary(value.value);
476 value.copyLocationTo(builder);
477 return result;
478 }),
479 p::transform(bracketedList(parsers.expression, errorReporter),
480 [this](Located<kj::Array<kj::Maybe<Orphan<Expression>>>>&& value)
481 -> Orphan<Expression> {
482 auto result = orphanage.newOrphan<Expression>();
483 auto builder = result.get();
484 auto listBuilder = builder.initList(value.value.size());
485 for (uint i = 0; i < value.value.size(); i++) {
486 KJ_IF_MAYBE(element, value.value[i]) {
487 listBuilder.adoptWithCaveats(i, kj::mv(*element));
488 }
489 }
490 value.copyLocationTo(builder);
491 return result;
492 }),
493 p::transform(tuple,
494 [this](Located<Orphan<List<Expression::Param>>>&& value)
495 -> Orphan<Expression> {
496 auto elements = value.value.get();
497
498 if (elements.size() == 1 && elements[0].isUnnamed()) {
499 // Single-value tuple is just a value.
500 return elements[0].disownValue();
501 } else {
502 auto result = orphanage.newOrphan<Expression>();
503 auto builder = result.get();
504 builder.adoptTuple(kj::mv(value.value));
505 value.copyLocationTo(builder);
506 return result;
507 }
508 }),
509 p::transformWithLocation(p::sequence(keyword("import"), stringLiteral),
510 [this](kj::parse::Span<List<Token>::Reader::Iterator> location,
511 Located<Text::Reader>&& filename) -> Orphan<Expression> {
512 auto result = orphanage.newOrphan<Expression>();
513 auto builder = result.get();
514 initLocation(location, builder);
515 filename.copyTo(builder.initImport());
516 return result;
517 }),
518 p::transformWithLocation(p::sequence(keyword("embed"), stringLiteral),
519 [this](kj::parse::Span<List<Token>::Reader::Iterator> location,
520 Located<Text::Reader>&& filename) -> Orphan<Expression> {
521 auto result = orphanage.newOrphan<Expression>();
522 auto builder = result.get();
523 initLocation(location, builder);
524 filename.copyTo(builder.initEmbed());
525 return result;
526 }),
527 p::transformWithLocation(p::sequence(op("."), identifier),
528 [this](kj::parse::Span<List<Token>::Reader::Iterator> location,
529 Located<Text::Reader>&& name) -> Orphan<Expression> {
530 auto result = orphanage.newOrphan<Expression>();
531 auto builder = result.get();
532 initLocation(location, builder);
533 name.copyTo(builder.initAbsoluteName());
534 return result;
535 }),
536 p::transform(identifier,
537 [this](Located<Text::Reader>&& name) -> Orphan<Expression> {
538 auto result = orphanage.newOrphan<Expression>();
539 auto builder = result.get();
540 name.copyTo(builder.initRelativeName());
541 name.copyLocationTo(builder);
542 return result;
543 })),
544 // Suffixes, e.g. ".member" or "(param1, param2)".
545 p::many(p::oneOf(
546 p::transformWithLocation(p::sequence(op("."), identifier),
547 [this](kj::parse::Span<List<Token>::Reader::Iterator> location,
548 Located<Text::Reader>&& name) -> Orphan<Expression> {
549 auto result = orphanage.newOrphan<Expression>();
550 auto builder = result.get();
551 initLocation(location, builder);
552 name.copyTo(builder.initMember().initName());
553 return result;
554 }),
555 p::transform(tuple,
556 [this](Located<Orphan<List<Expression::Param>>>&& params) -> Orphan<Expression> {
557 auto result = orphanage.newOrphan<Expression>();
558 auto builder = result.get();
559 params.copyLocationTo(builder);
560 builder.initApplication().adoptParams(kj::mv(params.value));
561 return result;
562 })))),
563 [](Orphan<Expression>&& base, kj::Array<Orphan<Expression>>&& suffixes)
564 -> Orphan<Expression> {
565 // Apply all the suffixes to the base expression.
566 uint startByte = base.getReader().getStartByte();
567 for (auto& suffix: suffixes) {
568 auto builder = suffix.get();
569 if (builder.isApplication()) {
570 builder.getApplication().adoptFunction(kj::mv(base));
571 } else if (builder.isMember()) {
572 builder.getMember().adoptParent(kj::mv(base));
573 } else {
574 KJ_FAIL_ASSERT("Unknown suffix?", (uint)builder.which());
575 }
576 builder.setStartByte(startByte);
577 base = kj::mv(suffix);
578 }
579 return kj::mv(base);
580 }));
581
582 parsers.annotation = arena.copy(p::transform(
583 p::sequence(op("$"), parsers.expression),
584 [this](Orphan<Expression>&& expression)
585 -> Orphan<Declaration::AnnotationApplication> {
586 auto result = orphanage.newOrphan<Declaration::AnnotationApplication>();
587 auto builder = result.get();
588
589 auto exp = expression.get();
590 if (exp.isApplication()) {
591 // Oops, this annotation specifies the value, but we parsed it as an application on
592 // the preceding expression. Pull it back apart.
593 auto app = exp.getApplication();
594 builder.adoptName(app.disownFunction());
595 auto params = app.getParams();
596 if (params.size() == 1 && params[0].isUnnamed()) {
597 // Params has a single unnamed element, so reduce it to a simple value rather than
598 // a tuple.
599 builder.getValue().adoptExpression(params[0].disownValue());
600 } else {
601 // Params is not a single unnamed element, so it's a tuple.
602 builder.getValue().initExpression().adoptTuple(app.disownParams());
603 }
604 } else {
605 // The annotation has no value.
606 builder.adoptName(kj::mv(expression));
607 builder.getValue().setNone();
608 }
609
610 return result;
611 }));
612
613 parsers.uid = arena.copy(p::transform(
614 p::sequence(op("@"), integerLiteral),
615 [this](Located<uint64_t>&& value) {
616 if (value.value < (1ull << 63)) {
617 errorReporter.addError(value.startByte, value.endByte,
618 "Invalid ID. Please generate a new one with 'capnpc -i'.");
619 }
620 return value.asProto<LocatedInteger>(orphanage);
621 }));
622
623 parsers.ordinal = arena.copy(p::transform(
624 p::sequence(op("@"), integerLiteral),
625 [this](Located<uint64_t>&& value) {
626 if (value.value >= 65536) {
627 errorReporter.addError(value.startByte, value.endByte,
628 "Ordinals cannot be greater than 65535.");
629 }
630 return value.asProto<LocatedInteger>(orphanage);
631 }));
632
633 // -----------------------------------------------------------------
634
635 parsers.usingDecl = arena.copy(p::transform(
636 p::sequence(keyword("using"), p::optional(p::sequence(identifier, op("="))),
637 parsers.expression),
638 [this](kj::Maybe<Located<Text::Reader>>&& name, Orphan<Expression>&& target)
639 -> DeclParserResult {
640 auto decl = orphanage.newOrphan<Declaration>();
641 auto builder = decl.get();
642 KJ_IF_MAYBE(n, name) {
643 n->copyTo(builder.initName());
644 } else {
645 auto targetReader = target.getReader();
646 if (targetReader.isMember()) {
647 builder.setName(targetReader.getMember().getName());
648 } else {
649 errorReporter.addErrorOn(targetReader,
650 "'using' declaration without '=' must specify a named declaration from a "
651 "different scope.");
652 }
653 }
654 // no id, no annotations for using decl
655 builder.initUsing().adoptTarget(kj::mv(target));
656 return DeclParserResult(kj::mv(decl));
657 }));
658
659 parsers.constDecl = arena.copy(p::transform(
660 p::sequence(keyword("const"), identifier, p::optional(parsers.uid),
661 op(":"), parsers.expression,
662 op("="), parsers.expression,
663 p::many(parsers.annotation)),
664 [this](Located<Text::Reader>&& name, kj::Maybe<Orphan<LocatedInteger>>&& id,
665 Orphan<Expression>&& type, Orphan<Expression>&& value,
666 kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations)
667 -> DeclParserResult {
668 auto decl = orphanage.newOrphan<Declaration>();
669 auto builder =
670 initDecl(decl.get(), kj::mv(name), kj::mv(id), nullptr,
671 kj::mv(annotations)).initConst();
672 builder.adoptType(kj::mv(type));
673 builder.adoptValue(kj::mv(value));
674 return DeclParserResult(kj::mv(decl));
675 }));
676
677 parsers.enumDecl = arena.copy(p::transform(
678 p::sequence(keyword("enum"), identifier, p::optional(parsers.uid),
679 p::many(parsers.annotation)),
680 [this](Located<Text::Reader>&& name, kj::Maybe<Orphan<LocatedInteger>>&& id,
681 kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations)
682 -> DeclParserResult {
683 auto decl = orphanage.newOrphan<Declaration>();
684 initDecl(decl.get(), kj::mv(name), kj::mv(id), nullptr, kj::mv(annotations)).setEnum();
685 return DeclParserResult(kj::mv(decl), parsers.enumLevelDecl);
686 }));
687
688 parsers.enumerantDecl = arena.copy(p::transform(
689 p::sequence(identifier, parsers.ordinal, p::many(parsers.annotation)),
690 [this](Located<Text::Reader>&& name, Orphan<LocatedInteger>&& ordinal,
691 kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations)
692 -> DeclParserResult {
693 auto decl = orphanage.newOrphan<Declaration>();
694 initMemberDecl(decl.get(), kj::mv(name), kj::mv(ordinal), kj::mv(annotations))
695 .setEnumerant();
696 return DeclParserResult(kj::mv(decl));
697 }));
698
699 parsers.structDecl = arena.copy(p::transform(
700 p::sequence(keyword("struct"), identifier, p::optional(parsers.uid),
701 p::optional(parenthesizedList(identifier, errorReporter)),
702 p::many(parsers.annotation)),
703 [this](Located<Text::Reader>&& name, kj::Maybe<Orphan<LocatedInteger>>&& id,
704 kj::Maybe<Located<kj::Array<kj::Maybe<Located<Text::Reader>>>>>&& genericParameters,
705 kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations)
706 -> DeclParserResult {
707 auto decl = orphanage.newOrphan<Declaration>();
708 initDecl(decl.get(), kj::mv(name), kj::mv(id), kj::mv(genericParameters),
709 kj::mv(annotations)).setStruct();
710 return DeclParserResult(kj::mv(decl), parsers.structLevelDecl);
711 }));
712
713 parsers.fieldDecl = arena.copy(p::transform(
714 p::sequence(identifier, parsers.ordinal, op(":"), parsers.expression,
715 p::optional(p::sequence(op("="), parsers.expression)),
716 p::many(parsers.annotation)),
717 [this](Located<Text::Reader>&& name, Orphan<LocatedInteger>&& ordinal,
718 Orphan<Expression>&& type, kj::Maybe<Orphan<Expression>>&& defaultValue,
719 kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations)
720 -> DeclParserResult {
721 auto decl = orphanage.newOrphan<Declaration>();
722 auto builder =
723 initMemberDecl(decl.get(), kj::mv(name), kj::mv(ordinal), kj::mv(annotations))
724 .initField();
725 builder.adoptType(kj::mv(type));
726 KJ_IF_MAYBE(val, defaultValue) {
727 builder.getDefaultValue().adoptValue(kj::mv(*val));
728 } else {
729 builder.getDefaultValue().setNone();
730 }
731 return DeclParserResult(kj::mv(decl));
732 }));
733
734 // Parse an ordinal followed by an optional colon, or no ordinal but require a colon.
735 auto& ordinalOrColon = arena.copy(p::oneOf(
736 p::transform(p::sequence(parsers.ordinal, p::optional(op("!")), p::optional(op(":"))),
737 [](Orphan<LocatedInteger>&& ordinal,
738 kj::Maybe<kj::Tuple<>> exclamation,
739 kj::Maybe<kj::Tuple<>> colon)
740 -> kj::Tuple<kj::Maybe<Orphan<LocatedInteger>>, bool, bool> {
741 return kj::tuple(kj::mv(ordinal), exclamation == nullptr, colon == nullptr);
742 }),
743 p::transform(op(":"),
744 []() -> kj::Tuple<kj::Maybe<Orphan<LocatedInteger>>, bool, bool> {
745 return kj::tuple(nullptr, false, false);
746 })));
747
748 parsers.unionDecl = arena.copy(p::transform(
749 // The first branch of this oneOf() matches named unions. The second branch matches unnamed
750 // unions and generates dummy values for the parse results.
751 p::oneOf(
752 p::sequence(
753 identifier, ordinalOrColon,
754 keyword("union"), p::many(parsers.annotation)),
755 p::transformWithLocation(p::sequence(keyword("union"), p::endOfInput),
756 [](kj::parse::Span<List<Token>::Reader::Iterator> location) {
757 return kj::tuple(
758 Located<Text::Reader>("", location.begin()->getStartByte(),
759 location.begin()->getEndByte()),
760 kj::Maybe<Orphan<LocatedInteger>>(nullptr),
761 false, false,
762 kj::Array<Orphan<Declaration::AnnotationApplication>>(nullptr));
763 })),
764 [this](Located<Text::Reader>&& name,
765 kj::Maybe<Orphan<LocatedInteger>>&& ordinal,
766 bool missingExclamation, bool missingColon,
767 kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations)
768 -> DeclParserResult {
769 if (missingExclamation) {
770 errorReporter.addErrorOn(KJ_ASSERT_NONNULL(ordinal).getReader(),
771 "As of Cap'n Proto v0.3, it is no longer necessary to assign numbers to "
772 "unions. However, removing the number will break binary compatibility. "
773 "If this is an old protocol and you need to retain compatibility, please "
774 "add an exclamation point after the number to indicate that it is really "
775 "needed, e.g. `foo @1! :union {`. If this is a new protocol or compatibility "
776 "doesn't matter, just remove the @n entirely. Sorry for the inconvenience, "
777 "and thanks for being an early adopter! :)");
778 }
779 if (missingColon) {
780 errorReporter.addErrorOn(KJ_ASSERT_NONNULL(ordinal).getReader(),
781 "As of Cap'n Proto v0.3, the 'union' keyword should be prefixed with a colon "
782 "for named unions, e.g. `foo :union {`.");
783 }
784
785 auto decl = orphanage.newOrphan<Declaration>();
786 auto builder = decl.get();
787 name.copyTo(builder.initName());
788 KJ_IF_MAYBE(ord, ordinal) {
789 builder.getId().adoptOrdinal(kj::mv(*ord));
790 } else {
791 builder.getId().setUnspecified();
792 }
793 auto list = builder.initAnnotations(annotations.size());
794 for (uint i = 0; i < annotations.size(); i++) {
795 list.adoptWithCaveats(i, kj::mv(annotations[i]));
796 }
797 builder.setUnion();
798 return DeclParserResult(kj::mv(decl), parsers.structLevelDecl);
799 }));
800
801 parsers.groupDecl = arena.copy(p::transform(
802 p::sequence(identifier, op(":"), keyword("group"), p::many(parsers.annotation)),
803 [this](Located<Text::Reader>&& name,
804 kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations)
805 -> DeclParserResult {
806 auto decl = orphanage.newOrphan<Declaration>();
807 auto builder = decl.get();
808 name.copyTo(builder.getName());
809 builder.getId().setUnspecified();
810 auto list = builder.initAnnotations(annotations.size());
811 for (uint i = 0; i < annotations.size(); i++) {
812 list.adoptWithCaveats(i, kj::mv(annotations[i]));
813 }
814 builder.setGroup();
815 return DeclParserResult(kj::mv(decl), parsers.structLevelDecl);
816 }));
817
818 parsers.interfaceDecl = arena.copy(p::transform(
819 p::sequence(keyword("interface"), identifier, p::optional(parsers.uid),
820 p::optional(parenthesizedList(identifier, errorReporter)),
821 p::optional(p::sequence(
822 keyword("extends"), parenthesizedList(parsers.expression, errorReporter))),
823 p::many(parsers.annotation)),
824 [this](Located<Text::Reader>&& name, kj::Maybe<Orphan<LocatedInteger>>&& id,
825 kj::Maybe<Located<kj::Array<kj::Maybe<Located<Text::Reader>>>>>&& genericParameters,
826 kj::Maybe<Located<kj::Array<kj::Maybe<Orphan<Expression>>>>>&& superclasses,
827 kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations)
828 -> DeclParserResult {
829 auto decl = orphanage.newOrphan<Declaration>();
830 auto builder = initDecl(
831 decl.get(), kj::mv(name), kj::mv(id), kj::mv(genericParameters),
832 kj::mv(annotations)).initInterface();
833 KJ_IF_MAYBE(s, superclasses) {
834 auto superclassesBuilder = builder.initSuperclasses(s->value.size());
835 for (uint i: kj::indices(s->value)) {
836 KJ_IF_MAYBE(superclass, s->value[i]) {
837 superclassesBuilder.adoptWithCaveats(i, kj::mv(*superclass));
838 }
839 }
840 }
841 return DeclParserResult(kj::mv(decl), parsers.interfaceLevelDecl);
842 }));
843
844 parsers.param = arena.copy(p::transformWithLocation(
845 p::sequence(identifier, op(":"), parsers.expression,
846 p::optional(p::sequence(op("="), parsers.expression)),
847 p::many(parsers.annotation)),
848 [this](kj::parse::Span<List<Token>::Reader::Iterator> location,
849 Located<Text::Reader>&& name, Orphan<Expression>&& type,
850 kj::Maybe<Orphan<Expression>>&& defaultValue,
851 kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations)
852 -> Orphan<Declaration::Param> {
853 auto result = orphanage.newOrphan<Declaration::Param>();
854 auto builder = result.get();
855
856 initLocation(location, builder);
857
858 name.copyTo(builder.initName());
859 builder.adoptType(kj::mv(type));
860 builder.adoptAnnotations(arrayToList(orphanage, kj::mv(annotations)));
861 KJ_IF_MAYBE(val, defaultValue) {
862 builder.getDefaultValue().adoptValue(kj::mv(*val));
863 } else {
864 builder.getDefaultValue().setNone();
865 }
866
867 return kj::mv(result);
868 }));
869
870 auto& paramList = arena.copy(p::oneOf(
871 p::transform(parenthesizedList(parsers.param, errorReporter),
872 [this](Located<kj::Array<kj::Maybe<Orphan<Declaration::Param>>>>&& params)
873 -> Orphan<Declaration::ParamList> {
874 auto decl = orphanage.newOrphan<Declaration::ParamList>();
875 auto builder = decl.get();
876 params.copyLocationTo(builder);
877 auto listBuilder = builder.initNamedList(params.value.size());
878 for (uint i: kj::indices(params.value)) {
879 KJ_IF_MAYBE(param, params.value[i]) {
880 listBuilder.adoptWithCaveats(i, kj::mv(*param));
881 }
882 }
883 return decl;
884 }),
885 p::transform(locatedKeyword("stream"),
886 [this](Located<Text::Reader>&& kw) -> Orphan<Declaration::ParamList> {
887 auto decl = orphanage.newOrphan<Declaration::ParamList>();
888 auto builder = decl.get();
889 kw.copyLocationTo(builder);
890 builder.setStream();
891 return decl;
892 }),
893 p::transform(parsers.expression,
894 [this](Orphan<Expression>&& name) -> Orphan<Declaration::ParamList> {
895 auto decl = orphanage.newOrphan<Declaration::ParamList>();
896 auto builder = decl.get();
897 auto nameReader = name.getReader();
898 builder.setStartByte(nameReader.getStartByte());
899 builder.setEndByte(nameReader.getEndByte());
900 builder.adoptType(kj::mv(name));
901 return decl;
902 })));
903
904 parsers.methodDecl = arena.copy(p::transform(
905 p::sequence(identifier, parsers.ordinal,
906 p::optional(bracketedList(identifier, errorReporter)),
907 paramList,
908 p::optional(p::sequence(op("->"), paramList)),
909 p::many(parsers.annotation)),
910 [this](Located<Text::Reader>&& name, Orphan<LocatedInteger>&& ordinal,
911 kj::Maybe<Located<kj::Array<kj::Maybe<Located<Text::Reader>>>>>&& genericParams,
912 Orphan<Declaration::ParamList>&& params,
913 kj::Maybe<Orphan<Declaration::ParamList>>&& results,
914 kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations)
915 -> DeclParserResult {
916 auto decl = orphanage.newOrphan<Declaration>();
917 auto nodeBuilder = initMemberDecl(
918 decl.get(), kj::mv(name), kj::mv(ordinal), kj::mv(annotations));
919
920 initGenericParams(nodeBuilder, kj::mv(genericParams));
921
922 auto builder = nodeBuilder.initMethod();
923
924 builder.adoptParams(kj::mv(params));
925
926 KJ_IF_MAYBE(r, results) {
927 builder.getResults().adoptExplicit(kj::mv(*r));
928 } else {
929 builder.getResults().setNone();
930 }
931
932 return DeclParserResult(kj::mv(decl));
933 }));
934
935 auto& annotationTarget = arena.copy(p::oneOf(
936 identifier,
937 p::transformWithLocation(op("*"),
938 [](kj::parse::Span<List<Token>::Reader::Iterator> location) {
939 // Hacky...
940 return Located<Text::Reader>("*",
941 location.begin()->getStartByte(),
942 location.begin()->getEndByte());
943 })));
944
945 parsers.annotationDecl = arena.copy(p::transform(
946 p::sequence(keyword("annotation"), identifier, p::optional(parsers.uid),
947 parenthesizedList(annotationTarget, errorReporter),
948 op(":"), parsers.expression,
949 p::many(parsers.annotation)),
950 [this](Located<Text::Reader>&& name, kj::Maybe<Orphan<LocatedInteger>>&& id,
951 Located<kj::Array<kj::Maybe<Located<Text::Reader>>>>&& targets,
952 Orphan<Expression>&& type,
953 kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations)
954 -> DeclParserResult {
955 auto decl = orphanage.newOrphan<Declaration>();
956 auto builder =
957 initDecl(decl.get(), kj::mv(name), kj::mv(id), nullptr,
958 kj::mv(annotations)).initAnnotation();
959 builder.adoptType(kj::mv(type));
960 DynamicStruct::Builder dynamicBuilder = builder;
961 for (auto& maybeTarget: targets.value) {
962 KJ_IF_MAYBE(target, maybeTarget) {
963 if (target->value == "*") {
964 // Set all.
965 if (targets.value.size() > 1) {
966 errorReporter.addError(target->startByte, target->endByte,
967 "Wildcard should not be specified together with other targets.");
968 }
969
970 for (auto field: dynamicBuilder.getSchema().getFields()) {
971 if (field.getProto().getName().startsWith("targets")) {
972 dynamicBuilder.set(field, true);
973 }
974 }
975 } else {
976 if (target->value.size() == 0 || target->value.size() >= 32 ||
977 target->value[0] < 'a' || target->value[0] > 'z') {
978 errorReporter.addError(target->startByte, target->endByte,
979 "Not a valid annotation target.");
980 } else {
981 char buffer[64];
982 strcpy(buffer, "targets");
983 strcat(buffer, target->value.cStr());
984 buffer[strlen("targets")] += 'A' - 'a';
985 KJ_IF_MAYBE(field, dynamicBuilder.getSchema().findFieldByName(buffer)) {
986 if (dynamicBuilder.get(*field).as<bool>()) {
987 errorReporter.addError(target->startByte, target->endByte,
988 "Duplicate target specification.");
989 }
990 dynamicBuilder.set(*field, true);
991 } else {
992 errorReporter.addError(target->startByte, target->endByte,
993 "Not a valid annotation target.");
994 }
995 }
996 }
997 }
998 }
999 return DeclParserResult(kj::mv(decl));
1000 }));
1001
1002 // -----------------------------------------------------------------
1003
1004 auto& nakedId = arena.copy(p::transform(parsers.uid,
1005 [this](Orphan<LocatedInteger>&& value) -> DeclParserResult {
1006 auto decl = orphanage.newOrphan<Declaration>();
1007 decl.get().adoptNakedId(kj::mv(value));
1008 return DeclParserResult(kj::mv(decl));
1009 }));
1010
1011 auto& nakedAnnotation = arena.copy(p::transform(parsers.annotation,
1012 [this](Orphan<Declaration::AnnotationApplication>&& value) -> DeclParserResult {
1013 auto decl = orphanage.newOrphan<Declaration>();
1014 decl.get().adoptNakedAnnotation(kj::mv(value));
1015 return DeclParserResult(kj::mv(decl));
1016 }));
1017
1018 // -----------------------------------------------------------------
1019
1020 parsers.genericDecl = arena.copy(p::oneOf(
1021 parsers.usingDecl, parsers.constDecl, parsers.annotationDecl,
1022 parsers.enumDecl, parsers.structDecl, parsers.interfaceDecl));
1023 parsers.fileLevelDecl = arena.copy(p::oneOf(
1024 parsers.genericDecl, nakedId, nakedAnnotation));
1025 parsers.enumLevelDecl = arena.copy(p::oneOf(parsers.enumerantDecl));
1026 parsers.structLevelDecl = arena.copy(p::oneOf(
1027 parsers.unionDecl, parsers.fieldDecl, parsers.groupDecl, parsers.genericDecl));
1028 parsers.interfaceLevelDecl = arena.copy(p::oneOf(
1029 parsers.methodDecl, parsers.genericDecl));
1030 }
1031
~CapnpParser()1032 CapnpParser::~CapnpParser() noexcept(false) {}
1033
parseStatement(Statement::Reader statement,const DeclParser & parser)1034 kj::Maybe<Orphan<Declaration>> CapnpParser::parseStatement(
1035 Statement::Reader statement, const DeclParser& parser) {
1036 auto fullParser = p::sequence(parser, p::endOfInput);
1037
1038 auto tokens = statement.getTokens();
1039 ParserInput parserInput(tokens.begin(), tokens.end());
1040
1041 KJ_IF_MAYBE(output, fullParser(parserInput)) {
1042 auto builder = output->decl.get();
1043
1044 if (statement.hasDocComment()) {
1045 builder.setDocComment(statement.getDocComment());
1046 }
1047
1048 builder.setStartByte(statement.getStartByte());
1049 builder.setEndByte(statement.getEndByte());
1050
1051 switch (statement.which()) {
1052 case Statement::LINE:
1053 if (output->memberParser != nullptr) {
1054 errorReporter.addError(statement.getStartByte(), statement.getEndByte(),
1055 "This statement should end with a block, not a semicolon.");
1056 }
1057 break;
1058
1059 case Statement::BLOCK:
1060 KJ_IF_MAYBE(memberParser, output->memberParser) {
1061 auto memberStatements = statement.getBlock();
1062 kj::Vector<Orphan<Declaration>> members(memberStatements.size());
1063 for (auto memberStatement: memberStatements) {
1064 KJ_IF_MAYBE(member, parseStatement(memberStatement, *memberParser)) {
1065 members.add(kj::mv(*member));
1066 }
1067 }
1068 builder.adoptNestedDecls(arrayToList(orphanage, members.releaseAsArray()));
1069 } else {
1070 errorReporter.addError(statement.getStartByte(), statement.getEndByte(),
1071 "This statement should end with a semicolon, not a block.");
1072 }
1073 break;
1074 }
1075
1076 return kj::mv(output->decl);
1077
1078 } else {
1079 // Parse error. Figure out where to report it.
1080 auto best = parserInput.getBest();
1081 uint32_t bestByte;
1082
1083 if (best != tokens.end()) {
1084 bestByte = best->getStartByte();
1085 } else if (tokens.end() != tokens.begin()) {
1086 bestByte = (tokens.end() - 1)->getEndByte();
1087 } else {
1088 bestByte = statement.getStartByte();
1089 }
1090
1091 errorReporter.addError(bestByte, bestByte, "Parse error.");
1092 return nullptr;
1093 }
1094 }
1095
1096 // =======================================================================================
1097
1098 static const char HEXDIGITS[] = "0123456789abcdef";
1099
stringLiteralStringTree(kj::StringPtr chars)1100 static kj::StringTree stringLiteralStringTree(kj::StringPtr chars) {
1101 return kj::strTree('"', kj::encodeCEscape(chars), '"');
1102 }
1103
binaryLiteralStringTree(Data::Reader data)1104 static kj::StringTree binaryLiteralStringTree(Data::Reader data) {
1105 kj::Vector<char> escaped(data.size() * 3);
1106
1107 for (byte b: data) {
1108 escaped.add(HEXDIGITS[b % 16]);
1109 escaped.add(HEXDIGITS[b / 16]);
1110 escaped.add(' ');
1111 }
1112
1113 escaped.removeLast();
1114 return kj::strTree("0x\"", escaped, '"');
1115 }
1116
1117 static kj::StringTree expressionStringTree(Expression::Reader exp);
1118
tupleLiteral(List<Expression::Param>::Reader params)1119 static kj::StringTree tupleLiteral(List<Expression::Param>::Reader params) {
1120 auto parts = kj::heapArrayBuilder<kj::StringTree>(params.size());
1121 for (auto param: params) {
1122 auto part = expressionStringTree(param.getValue());
1123 if (param.isNamed()) {
1124 part = kj::strTree(param.getNamed().getValue(), " = ", kj::mv(part));
1125 }
1126 parts.add(kj::mv(part));
1127 }
1128 return kj::strTree("( ", kj::StringTree(parts.finish(), ", "), " )");
1129 }
1130
expressionStringTree(Expression::Reader exp)1131 static kj::StringTree expressionStringTree(Expression::Reader exp) {
1132 switch (exp.which()) {
1133 case Expression::UNKNOWN:
1134 return kj::strTree("<parse error>");
1135 case Expression::POSITIVE_INT:
1136 return kj::strTree(exp.getPositiveInt());
1137 case Expression::NEGATIVE_INT:
1138 return kj::strTree('-', exp.getNegativeInt());
1139 case Expression::FLOAT:
1140 return kj::strTree(exp.getFloat());
1141 case Expression::STRING:
1142 return stringLiteralStringTree(exp.getString());
1143 case Expression::BINARY:
1144 return binaryLiteralStringTree(exp.getBinary());
1145 case Expression::RELATIVE_NAME:
1146 return kj::strTree(exp.getRelativeName().getValue());
1147 case Expression::ABSOLUTE_NAME:
1148 return kj::strTree('.', exp.getAbsoluteName().getValue());
1149 case Expression::IMPORT:
1150 return kj::strTree("import ", stringLiteralStringTree(exp.getImport().getValue()));
1151 case Expression::EMBED:
1152 return kj::strTree("embed ", stringLiteralStringTree(exp.getEmbed().getValue()));
1153
1154 case Expression::LIST: {
1155 auto list = exp.getList();
1156 auto parts = kj::heapArrayBuilder<kj::StringTree>(list.size());
1157 for (auto element: list) {
1158 parts.add(expressionStringTree(element));
1159 }
1160 return kj::strTree("[ ", kj::StringTree(parts.finish(), ", "), " ]");
1161 }
1162
1163 case Expression::TUPLE:
1164 return tupleLiteral(exp.getTuple());
1165
1166 case Expression::APPLICATION: {
1167 auto app = exp.getApplication();
1168 return kj::strTree(expressionStringTree(app.getFunction()),
1169 '(', tupleLiteral(app.getParams()), ')');
1170 }
1171
1172 case Expression::MEMBER: {
1173 auto member = exp.getMember();
1174 return kj::strTree(expressionStringTree(member.getParent()), '.',
1175 member.getName().getValue());
1176 }
1177 }
1178
1179 KJ_UNREACHABLE;
1180 }
1181
expressionString(Expression::Reader name)1182 kj::String expressionString(Expression::Reader name) {
1183 return expressionStringTree(name).flatten();
1184 }
1185
1186 } // namespace compiler
1187 } // namespace capnp
1188