comparison src/capnproto-0.6.0/c++/src/capnp/compiler/parser.c++ @ 62:0994c39f1e94

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