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