Mercurial > hg > sv-dependency-builds
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 |