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 "node-translator.h"
23#include "parser.h" // only for generateGroupId()
24#include <capnp/serialize.h>
25#include <kj/debug.h>
26#include <kj/arena.h>
27#include <kj/encoding.h>
28#include <set>
29#include <map>
30#include <stdlib.h>
31
32namespace capnp {
33namespace compiler {
34
35bool shouldDetectIssue344() {
36 return getenv("CAPNP_IGNORE_ISSUE_344") == nullptr;
37}
38
39class NodeTranslator::StructLayout {
40 // Massive, disgusting class which implements the layout algorithm, which decides the offset
41 // for each field.
42
43public:
44 template <typename UIntType>
45 struct HoleSet {
46 inline HoleSet(): holes{0, 0, 0, 0, 0, 0} {}
47
48 // Represents a set of "holes" within a segment of allocated space, up to one hole of each
49 // power-of-two size between 1 bit and 32 bits.
50 //
51 // The amount of "used" space in a struct's data segment can always be represented as a
52 // combination of a word count and a HoleSet. The HoleSet represents the space lost to
53 // "padding".
54 //
55 // There can never be more than one hole of any particular size. Why is this? Well, consider
56 // that every data field has a power-of-two size, every field must be aligned to a multiple of
57 // its size, and the maximum size of a single field is 64 bits. If we need to add a new field
58 // of N bits, there are two possibilities:
59 // 1. A hole of size N or larger exists. In this case, we find the smallest hole that is at
60 // least N bits. Let's say that that hole has size M. We allocate the first N bits of the
61 // hole to the new field. The remaining M - N bits become a series of holes of sizes N*2,
62 // N*4, ..., M / 2. We know no holes of these sizes existed before because we chose M to be
63 // the smallest available hole larger than N. So, there is still no more than one hole of
64 // each size, and no hole larger than any hole that existed previously.
65 // 2. No hole equal or larger N exists. In that case we extend the data section's size by one
66 // word, creating a new 64-bit hole at the end. We then allocate N bits from it, creating
67 // a series of holes between N and 64 bits, as described in point (1). Thus, again, there
68 // is still at most one hole of each size, and the largest hole is 32 bits.
69
70 UIntType holes[6];
71 // The offset of each hole as a multiple of its size. A value of zero indicates that no hole
72 // exists. Notice that it is impossible for any actual hole to have an offset of zero, because
73 // the first field allocated is always placed at the very beginning of the section. So either
74 // the section has a size of zero (in which case there are no holes), or offset zero is
75 // already allocated and therefore cannot be a hole.
76
77 kj::Maybe<UIntType> tryAllocate(UIntType lgSize) {
78 // Try to find space for a field of size 2^lgSize within the set of holes. If found,
79 // remove it from the holes, and return its offset (as a multiple of its size). If there
80 // is no such space, returns zero (no hole can be at offset zero, as explained above).
81
82 if (lgSize >= kj::size(holes)) {
83 return nullptr;
84 } else if (holes[lgSize] != 0) {
85 UIntType result = holes[lgSize];
86 holes[lgSize] = 0;
87 return result;
88 } else {
89 KJ_IF_MAYBE(next, tryAllocate(lgSize + 1)) {
90 UIntType result = *next * 2;
91 holes[lgSize] = result + 1;
92 return result;
93 } else {
94 return nullptr;
95 }
96 }
97 }
98
99 uint assertHoleAndAllocate(UIntType lgSize) {
100 KJ_ASSERT(holes[lgSize] != 0);
101 uint result = holes[lgSize];
102 holes[lgSize] = 0;
103 return result;
104 }
105
106 void addHolesAtEnd(UIntType lgSize, UIntType offset,
107 UIntType limitLgSize = sizeof(HoleSet::holes) / sizeof(HoleSet::holes[0])) {
108 // Add new holes of progressively larger sizes in the range [lgSize, limitLgSize) starting
109 // from the given offset. The idea is that you just allocated an lgSize-sized field from
110 // an limitLgSize-sized space, such as a newly-added word on the end of the data segment.
111
112 KJ_DREQUIRE(limitLgSize <= kj::size(holes));
113
114 while (lgSize < limitLgSize) {
115 KJ_DREQUIRE(holes[lgSize] == 0);
116 KJ_DREQUIRE(offset % 2 == 1);
117 holes[lgSize] = offset;
118 ++lgSize;
119 offset = (offset + 1) / 2;
120 }
121 }
122
123 bool tryExpand(UIntType oldLgSize, uint oldOffset, uint expansionFactor) {
124 // Try to expand the value at the given location by combining it with subsequent holes, so
125 // as to expand the location to be 2^expansionFactor times the size that it started as.
126 // (In other words, the new lgSize is oldLgSize + expansionFactor.)
127
128 if (expansionFactor == 0) {
129 // No expansion requested.
130 return true;
131 }
132 if (holes[oldLgSize] != oldOffset + 1) {
133 // The space immediately after the location is not a hole.
134 return false;
135 }
136
137 // We can expand the location by one factor by combining it with a hole. Try to further
138 // expand from there to the number of factors requested.
139 if (tryExpand(oldLgSize + 1, oldOffset >> 1, expansionFactor - 1)) {
140 // Success. Consume the hole.
141 holes[oldLgSize] = 0;
142 return true;
143 } else {
144 return false;
145 }
146 }
147
148 kj::Maybe<uint> smallestAtLeast(uint size) {
149 // Return the size of the smallest hole that is equal to or larger than the given size.
150
151 for (uint i = size; i < kj::size(holes); i++) {
152 if (holes[i] != 0) {
153 return i;
154 }
155 }
156 return nullptr;
157 }
158
159 uint getFirstWordUsed() {
160 // Computes the lg of the amount of space used in the first word of the section.
161
162 // If there is a 32-bit hole with a 32-bit offset, no more than the first 32 bits are used.
163 // If no more than the first 32 bits are used, and there is a 16-bit hole with a 16-bit
164 // offset, then no more than the first 16 bits are used. And so on.
165 for (uint i = kj::size(holes); i > 0; i--) {
166 if (holes[i - 1] != 1) {
167 return i;
168 }
169 }
170 return 0;
171 }
172 };
173
174 struct StructOrGroup {
175 // Abstract interface for scopes in which fields can be added.
176
177 virtual void addVoid() = 0;
178 virtual uint addData(uint lgSize) = 0;
179 virtual uint addPointer() = 0;
180 virtual bool tryExpandData(uint oldLgSize, uint oldOffset, uint expansionFactor) = 0;
181 // Try to expand the given previously-allocated space by 2^expansionFactor. Succeeds --
182 // returning true -- if the following space happens to be empty, making this expansion possible.
183 // Otherwise, returns false.
184 };
185
186 struct Top: public StructOrGroup {
187 uint dataWordCount = 0;
188 uint pointerCount = 0;
189 // Size of the struct so far.
190
191 HoleSet<uint> holes;
192
193 void addVoid() override {}
194
195 uint addData(uint lgSize) override {
196 KJ_IF_MAYBE(hole, holes.tryAllocate(lgSize)) {
197 return *hole;
198 } else {
199 uint offset = dataWordCount++ << (6 - lgSize);
200 holes.addHolesAtEnd(lgSize, offset + 1);
201 return offset;
202 }
203 }
204
205 uint addPointer() override {
206 return pointerCount++;
207 }
208
209 bool tryExpandData(uint oldLgSize, uint oldOffset, uint expansionFactor) override {
210 return holes.tryExpand(oldLgSize, oldOffset, expansionFactor);
211 }
212
213 Top() = default;
214 KJ_DISALLOW_COPY(Top);
215 };
216
217 struct Union {
218 struct DataLocation {
219 uint lgSize;
220 uint offset;
221
222 bool tryExpandTo(Union& u, uint newLgSize) {
223 if (newLgSize <= lgSize) {
224 return true;
225 } else if (u.parent.tryExpandData(lgSize, offset, newLgSize - lgSize)) {
226 offset >>= (newLgSize - lgSize);
227 lgSize = newLgSize;
228 return true;
229 } else {
230 return false;
231 }
232 }
233 };
234
235 StructOrGroup& parent;
236 uint groupCount = 0;
237 kj::Maybe<uint> discriminantOffset;
238 kj::Vector<DataLocation> dataLocations;
239 kj::Vector<uint> pointerLocations;
240
241 inline Union(StructOrGroup& parent): parent(parent) {}
242 KJ_DISALLOW_COPY(Union);
243
244 uint addNewDataLocation(uint lgSize) {
245 // Add a whole new data location to the union with the given size.
246
247 uint offset = parent.addData(lgSize);
248 dataLocations.add(DataLocation { lgSize, offset });
249 return offset;
250 }
251
252 uint addNewPointerLocation() {
253 // Add a whole new pointer location to the union with the given size.
254
255 return pointerLocations.add(parent.addPointer());
256 }
257
258 void newGroupAddingFirstMember() {
259 if (++groupCount == 2) {
260 addDiscriminant();
261 }
262 }
263
264 bool addDiscriminant() {
265 if (discriminantOffset == nullptr) {
266 discriminantOffset = parent.addData(4); // 2^4 = 16 bits
267 return true;
268 } else {
269 return false;
270 }
271 }
272 };
273
274 struct Group final: public StructOrGroup {
275 public:
276 class DataLocationUsage {
277 public:
278 DataLocationUsage(): isUsed(false) {}
279 explicit DataLocationUsage(uint lgSize): isUsed(true), lgSizeUsed(lgSize) {}
280
281 kj::Maybe<uint> smallestHoleAtLeast(Union::DataLocation& location, uint lgSize) {
282 // Find the smallest single hole that is at least the given size. This is used to find the
283 // optimal place to allocate each field -- it is placed in the smallest slot where it fits,
284 // to reduce fragmentation. Returns the size of the hole, if found.
285
286 if (!isUsed) {
287 // The location is effectively one big hole.
288 if (lgSize <= location.lgSize) {
289 return location.lgSize;
290 } else {
291 return nullptr;
292 }
293 } else if (lgSize >= lgSizeUsed) {
294 // Requested size is at least our current usage, so clearly won't fit in any current
295 // holes, but if the location's size is larger than what we're using, we'd be able to
296 // expand.
297 if (lgSize < location.lgSize) {
298 return lgSize;
299 } else {
300 return nullptr;
301 }
302 } else KJ_IF_MAYBE(result, holes.smallestAtLeast(lgSize)) {
303 // There's a hole.
304 return *result;
305 } else {
306 // The requested size is smaller than what we're already using, but there are no holes
307 // available. If we could double our size, then we could allocate in the new space.
308
309 if (lgSizeUsed < location.lgSize) {
310 // We effectively create a new hole the same size as the current usage.
311 return lgSizeUsed;
312 } else {
313 return nullptr;
314 }
315 }
316 }
317
318 uint allocateFromHole(Group& group, Union::DataLocation& location, uint lgSize) {
319 // Allocate the given space from an existing hole, given smallestHoleAtLeast() already
320 // returned non-null indicating such a hole exists.
321
322 uint result;
323
324 if (!isUsed) {
325 // The location is totally unused, so just allocate from the beginning.
326 KJ_DASSERT(lgSize <= location.lgSize, "Did smallestHoleAtLeast() really find a hole?");
327 result = 0;
328 isUsed = true;
329 lgSizeUsed = lgSize;
330 } else if (lgSize >= lgSizeUsed) {
331 // Requested size is at least our current usage, so clearly won't fit in any holes.
332 // We must expand to double the requested size, and return the second half.
333 KJ_DASSERT(lgSize < location.lgSize, "Did smallestHoleAtLeast() really find a hole?");
334 holes.addHolesAtEnd(lgSizeUsed, 1, lgSize);
335 lgSizeUsed = lgSize + 1;
336 result = 1;
337 } else KJ_IF_MAYBE(hole, holes.tryAllocate(lgSize)) {
338 // Found a hole.
339 result = *hole;
340 } else {
341 // The requested size is smaller than what we're using so far, but didn't fit in a
342 // hole. We should double our "used" size, then allocate from the new space.
343 KJ_DASSERT(lgSizeUsed < location.lgSize,
344 "Did smallestHoleAtLeast() really find a hole?");
345 result = 1 << (lgSizeUsed - lgSize);
346 holes.addHolesAtEnd(lgSize, result + 1, lgSizeUsed);
347 lgSizeUsed += 1;
348 }
349
350 // Adjust the offset according to the location's offset before returning.
351 uint locationOffset = location.offset << (location.lgSize - lgSize);
352 return locationOffset + result;
353 }
354
355 kj::Maybe<uint> tryAllocateByExpanding(
356 Group& group, Union::DataLocation& location, uint lgSize) {
357 // Attempt to allocate the given size by requesting that the parent union expand this
358 // location to fit. This is used if smallestHoleAtLeast() already determined that there
359 // are no holes that would fit, so we don't bother checking that.
360
361 if (!isUsed) {
362 if (location.tryExpandTo(group.parent, lgSize)) {
363 isUsed = true;
364 lgSizeUsed = lgSize;
365 return location.offset << (location.lgSize - lgSize);
366 } else {
367 return nullptr;
368 }
369 } else {
370 uint newSize = kj::max(lgSizeUsed, lgSize) + 1;
371 if (tryExpandUsage(group, location, newSize, true)) {
372 uint result = KJ_ASSERT_NONNULL(holes.tryAllocate(lgSize));
373 uint locationOffset = location.offset << (location.lgSize - lgSize);
374 return locationOffset + result;
375 } else {
376 return nullptr;
377 }
378 }
379 }
380
381 bool tryExpand(Group& group, Union::DataLocation& location,
382 uint oldLgSize, uint oldOffset, uint expansionFactor) {
383 if (oldOffset == 0 && lgSizeUsed == oldLgSize) {
384 // This location contains exactly the requested data, so just expand the whole thing.
385 return tryExpandUsage(group, location, oldLgSize + expansionFactor, false);
386 } else {
387 // This location contains the requested data plus other stuff. Therefore the data cannot
388 // possibly expand past the end of the space we've already marked used without either
389 // overlapping with something else or breaking alignment rules. We only have to combine
390 // it with holes.
391 return holes.tryExpand(oldLgSize, oldOffset, expansionFactor);
392 }
393 }
394
395 private:
396 bool isUsed;
397 // Whether or not this location has been used at all by the group.
398
399 uint8_t lgSizeUsed;
400 // Amount of space from the location which is "used". This is the minimum size needed to
401 // cover all allocated space. Only meaningful if `isUsed` is true.
402
403 HoleSet<uint8_t> holes;
404 // Indicates holes present in the space designated by `lgSizeUsed`. The offsets in this
405 // HoleSet are relative to the beginning of this particular data location, not the beginning
406 // of the struct.
407
408 bool tryExpandUsage(Group& group, Union::DataLocation& location, uint desiredUsage,
409 bool newHoles) {
410 if (desiredUsage > location.lgSize) {
411 // Need to expand the underlying slot.
412 if (!location.tryExpandTo(group.parent, desiredUsage)) {
413 return false;
414 }
415 }
416
417 // Underlying slot is big enough, so expand our size and update holes.
418 if (newHoles) {
419 holes.addHolesAtEnd(lgSizeUsed, 1, desiredUsage);
420 } else if (shouldDetectIssue344()) {
421 // Unfortunately, Cap'n Proto 0.5.x and below would always call addHolesAtEnd(), which
422 // was the wrong thing to do when called from tryExpand(), which itself is only called
423 // in cases involving unions nested in other unions. The bug could lead to multiple
424 // fields in a group incorrectly being assigned overlapping offsets. Although the bug
425 // is now fixed by adding the `newHoles` parameter, this silently breaks
426 // backwards-compatibilty with affected schemas. Therefore, for now, we throw an
427 // exception to alert developers of the problem.
428 //
429 // TODO(cleanup): Once sufficient time has elapsed, remove this assert.
430 KJ_FAIL_ASSERT("Bad news: Cap'n Proto 0.5.x and previous contained a bug which would cause this schema to be compiled incorrectly. Please see: https://github.com/sandstorm-io/capnproto/issues/344");
431 }
432 lgSizeUsed = desiredUsage;
433 return true;
434 }
435 };
436
437 Union& parent;
438
439 kj::Vector<DataLocationUsage> parentDataLocationUsage;
440 // Vector corresponding to the parent union's `dataLocations`, indicating how much of each
441 // location has already been allocated.
442
443 uint parentPointerLocationUsage = 0;
444 // Number of parent's pointer locations that have been used by this group.
445
446 bool hasMembers = false;
447
448 inline Group(Union& parent): parent(parent) {}
449 KJ_DISALLOW_COPY(Group);
450
451 void addMember() {
452 if (!hasMembers) {
453 hasMembers = true;
454 parent.newGroupAddingFirstMember();
455 }
456 }
457
458 void addVoid() override {
459 addMember();
460
461 // Make sure that if this is a member of a union which is in turn a member of another union,
462 // that we let the outer union know that a field is being added, even though it is a
463 // zero-size field. This is important because the union needs to allocate its discriminant
464 // just before its second member is added.
465 parent.parent.addVoid();
466 }
467
468 uint addData(uint lgSize) override {
469 addMember();
470
471 uint bestSize = kj::maxValue;
472 kj::Maybe<uint> bestLocation = nullptr;
473
474 for (uint i = 0; i < parent.dataLocations.size(); i++) {
475 // If we haven't seen this DataLocation yet, add a corresponding DataLocationUsage.
476 if (parentDataLocationUsage.size() == i) {
477 parentDataLocationUsage.add();
478 }
479
480 auto& usage = parentDataLocationUsage[i];
481 KJ_IF_MAYBE(hole, usage.smallestHoleAtLeast(parent.dataLocations[i], lgSize)) {
482 if (*hole < bestSize) {
483 bestSize = *hole;
484 bestLocation = i;
485 }
486 }
487 }
488
489 KJ_IF_MAYBE(best, bestLocation) {
490 return parentDataLocationUsage[*best].allocateFromHole(
491 *this, parent.dataLocations[*best], lgSize);
492 }
493
494 // There are no holes at all in the union big enough to fit this field. Go back through all
495 // of the locations and attempt to expand them to fit.
496 for (uint i = 0; i < parent.dataLocations.size(); i++) {
497 KJ_IF_MAYBE(result, parentDataLocationUsage[i].tryAllocateByExpanding(
498 *this, parent.dataLocations[i], lgSize)) {
499 return *result;
500 }
501 }
502
503 // Couldn't find any space in the existing locations, so add a new one.
504 uint result = parent.addNewDataLocation(lgSize);
505 parentDataLocationUsage.add(lgSize);
506 return result;
507 }
508
509 uint addPointer() override {
510 addMember();
511
512 if (parentPointerLocationUsage < parent.pointerLocations.size()) {
513 return parent.pointerLocations[parentPointerLocationUsage++];
514 } else {
515 parentPointerLocationUsage++;
516 return parent.addNewPointerLocation();
517 }
518 }
519
520 bool tryExpandData(uint oldLgSize, uint oldOffset, uint expansionFactor) override {
521 bool mustFail = false;
522 if (oldLgSize + expansionFactor > 6 ||
523 (oldOffset & ((1 << expansionFactor) - 1)) != 0) {
524 // Expansion is not possible because the new size is too large or the offset is not
525 // properly-aligned.
526
527 // Unfortunately, Cap'n Proto 0.5.x and prior forgot to "return false" here, instead
528 // continuing to execute the rest of the method. In most cases, the method failed later
529 // on, causing no harm. But, in cases where the method later succeeded, it probably
530 // led to bogus layouts. We cannot simply add the return statement now as this would
531 // silently break backwards-compatibility with affected schemas. Instead, we detect the
532 // problem and throw an exception.
533 //
534 // TODO(cleanup): Once sufficient time has elapsed, switch to "return false;" here.
535 if (shouldDetectIssue344()) {
536 mustFail = true;
537 } else {
538 return false;
539 }
540 }
541
542 for (uint i = 0; i < parentDataLocationUsage.size(); i++) {
543 auto& location = parent.dataLocations[i];
544 if (location.lgSize >= oldLgSize &&
545 oldOffset >> (location.lgSize - oldLgSize) == location.offset) {
546 // The location we're trying to expand is a subset of this data location.
547 auto& usage = parentDataLocationUsage[i];
548
549 // Adjust the offset to be only within this location.
550 uint localOldOffset = oldOffset - (location.offset << (location.lgSize - oldLgSize));
551
552 // Try to expand.
553 bool result = usage.tryExpand(
554 *this, location, oldLgSize, localOldOffset, expansionFactor);
555 if (mustFail && result) {
556 KJ_FAIL_ASSERT("Bad news: Cap'n Proto 0.5.x and previous contained a bug which would cause this schema to be compiled incorrectly. Please see: https://github.com/sandstorm-io/capnproto/issues/344");
557 }
558 return result;
559 }
560 }
561
562 KJ_FAIL_ASSERT("Tried to expand field that was never allocated.");
563 return false;
564 }
565 };
566
567 Top& getTop() { return top; }
568
569private:
570 Top top;
571};
572
573// =======================================================================================
574
575class NodeTranslator::BrandedDecl {
576 // Represents a declaration possibly with generic parameter bindings.
577 //
578 // TODO(cleaup): This is too complicated to live here. We should refactor this class and
579 // BrandScope out into their own file, independent of NodeTranslator.
580
581public:
582 inline BrandedDecl(Resolver::ResolvedDecl decl,
583 kj::Own<NodeTranslator::BrandScope>&& brand,
584 Expression::Reader source)
585 : brand(kj::mv(brand)), source(source) {
586 body.init<Resolver::ResolvedDecl>(kj::mv(decl));
587 }
588 inline BrandedDecl(Resolver::ResolvedParameter variable, Expression::Reader source)
589 : source(source) {
590 body.init<Resolver::ResolvedParameter>(kj::mv(variable));
591 }
592 inline BrandedDecl(decltype(nullptr)) {}
593
594 static BrandedDecl implicitMethodParam(uint index) {
595 // Get a BrandedDecl referring to an implicit method parameter.
596 // (As a hack, we internally represent this as a ResolvedParameter. Sorry.)
597 return BrandedDecl(Resolver::ResolvedParameter { 0, index }, Expression::Reader());
598 }
599
600 BrandedDecl(BrandedDecl& other);
601 BrandedDecl(BrandedDecl&& other) = default;
602
603 BrandedDecl& operator=(BrandedDecl& other);
604 BrandedDecl& operator=(BrandedDecl&& other) = default;
605
606 // TODO(cleanup): A lot of the methods below are actually only called within compileAsType(),
607 // which was originally a method on NodeTranslator, but now is a method here and thus doesn't
608 // need these to be public. We should privatize most of these.
609
610 kj::Maybe<BrandedDecl> applyParams(kj::Array<BrandedDecl> params, Expression::Reader subSource);
611 // Treat the declaration as a generic and apply it to the given parameter list.
612
613 kj::Maybe<BrandedDecl> getMember(kj::StringPtr memberName, Expression::Reader subSource);
614 // Get a member of this declaration.
615
616 kj::Maybe<Declaration::Which> getKind();
617 // Returns the kind of declaration, or null if this is an unbound generic variable.
618
619 template <typename InitBrandFunc>
620 uint64_t getIdAndFillBrand(InitBrandFunc&& initBrand);
621 // Returns the type ID of this node. `initBrand` is a zero-arg functor which returns
622 // schema::Brand::Builder; this will be called if this decl has brand bindings, and
623 // the returned builder filled in to reflect those bindings.
624 //
625 // It is an error to call this when `getKind()` returns null.
626
627 kj::Maybe<BrandedDecl&> getListParam();
628 // Only if the kind is BUILTIN_LIST: Get the list's type parameter.
629
630 Resolver::ResolvedParameter asVariable();
631 // If this is an unbound generic variable (i.e. `getKind()` returns null), return information
632 // about the variable.
633 //
634 // It is an error to call this when `getKind()` does not return null.
635
636 bool compileAsType(ErrorReporter& errorReporter, schema::Type::Builder target);
637 // Compile this decl to a schema::Type.
638
639 inline void addError(ErrorReporter& errorReporter, kj::StringPtr message) {
640 errorReporter.addErrorOn(source, message);
641 }
642
643 Resolver::ResolveResult asResolveResult(uint64_t scopeId, schema::Brand::Builder brandBuilder);
644 // Reverse this into a ResolveResult. If necessary, use `brandBuilder` to fill in
645 // ResolvedDecl.brand.
646
647 kj::String toString();
648 kj::String toDebugString();
649
650private:
651 Resolver::ResolveResult body;
652 kj::Own<NodeTranslator::BrandScope> brand; // null if parameter
653 Expression::Reader source;
654};
655
656class NodeTranslator::BrandScope: public kj::Refcounted {
657 // Tracks the brand parameter bindings affecting the current scope. For example, if we are
658 // interpreting the type expression "Foo(Text).Bar", we would start with the current scopes
659 // BrandScope, create a new child BrandScope representing "Foo", add the "(Text)" parameter
660 // bindings to it, then create a further child scope for "Bar". Thus the BrandScope for Bar
661 // knows that Foo's parameter list has been bound to "(Text)".
662 //
663 // TODO(cleanup): This is too complicated to live here. We should refactor this class and
664 // BrandedDecl out into their own file, independent of NodeTranslator.
665
666public:
667 BrandScope(ErrorReporter& errorReporter, uint64_t startingScopeId,
668 uint startingScopeParamCount, Resolver& startingScope)
669 : errorReporter(errorReporter), parent(nullptr), leafId(startingScopeId),
670 leafParamCount(startingScopeParamCount), inherited(true) {
671 // Create all lexical parent scopes, all with no brand bindings.
672 KJ_IF_MAYBE(p, startingScope.getParent()) {
673 parent = kj::refcounted<BrandScope>(
674 errorReporter, p->id, p->genericParamCount, *p->resolver);
675 }
676 }
677
678 bool isGeneric() {
679 if (leafParamCount > 0) return true;
680
681 KJ_IF_MAYBE(p, parent) {
682 return p->get()->isGeneric();
683 } else {
684 return false;
685 }
686 }
687
688 kj::Own<BrandScope> push(uint64_t typeId, uint paramCount) {
689 return kj::refcounted<BrandScope>(kj::addRef(*this), typeId, paramCount);
690 }
691
692 kj::Maybe<kj::Own<BrandScope>> setParams(
693 kj::Array<BrandedDecl> params, Declaration::Which genericType, Expression::Reader source) {
694 if (this->params.size() != 0) {
695 errorReporter.addErrorOn(source, "Double-application of generic parameters.");
696 return nullptr;
697 } else if (params.size() > leafParamCount) {
698 if (leafParamCount == 0) {
699 errorReporter.addErrorOn(source, "Declaration does not accept generic parameters.");
700 } else {
701 errorReporter.addErrorOn(source, "Too many generic parameters.");
702 }
703 return nullptr;
704 } else if (params.size() < leafParamCount) {
705 errorReporter.addErrorOn(source, "Not enough generic parameters.");
706 return nullptr;
707 } else {
708 if (genericType != Declaration::BUILTIN_LIST) {
709 for (auto& param: params) {
710 KJ_IF_MAYBE(kind, param.getKind()) {
711 switch (*kind) {
712 case Declaration::BUILTIN_LIST:
713 case Declaration::BUILTIN_TEXT:
714 case Declaration::BUILTIN_DATA:
715 case Declaration::BUILTIN_ANY_POINTER:
716 case Declaration::STRUCT:
717 case Declaration::INTERFACE:
718 break;
719
720 default:
721 param.addError(errorReporter,
722 "Sorry, only pointer types can be used as generic parameters.");
723 break;
724 }
725 }
726 }
727 }
728
729 return kj::refcounted<BrandScope>(*this, kj::mv(params));
730 }
731 }
732
733 kj::Own<BrandScope> pop(uint64_t newLeafId) {
734 if (leafId == newLeafId) {
735 return kj::addRef(*this);
736 }
737 KJ_IF_MAYBE(p, parent) {
738 return (*p)->pop(newLeafId);
739 } else {
740 // Looks like we're moving into a whole top-level scope.
741 return kj::refcounted<BrandScope>(errorReporter, newLeafId);
742 }
743 }
744
745 kj::Maybe<BrandedDecl> lookupParameter(Resolver& resolver, uint64_t scopeId, uint index) {
746 // Returns null if the param should be inherited from the client scope.
747
748 if (scopeId == leafId) {
749 if (index < params.size()) {
750 return params[index];
751 } else if (inherited) {
752 return nullptr;
753 } else {
754 // Unbound and not inherited, so return AnyPointer.
755 auto decl = resolver.resolveBuiltin(Declaration::BUILTIN_ANY_POINTER);
756 return BrandedDecl(decl,
757 evaluateBrand(resolver, decl, List<schema::Brand::Scope>::Reader()),
758 Expression::Reader());
759 }
760 } else KJ_IF_MAYBE(p, parent) {
761 return p->get()->lookupParameter(resolver, scopeId, index);
762 } else {
763 KJ_FAIL_REQUIRE("scope is not a parent");
764 }
765 }
766
767 kj::Maybe<kj::ArrayPtr<BrandedDecl>> getParams(uint64_t scopeId) {
768 // Returns null if params at the requested scope should be inherited from the client scope.
769
770 if (scopeId == leafId) {
771 if (inherited) {
772 return nullptr;
773 } else {
774 return params.asPtr();
775 }
776 } else KJ_IF_MAYBE(p, parent) {
777 return p->get()->getParams(scopeId);
778 } else {
779 KJ_FAIL_REQUIRE("scope is not a parent");
780 }
781 }
782
783 template <typename InitBrandFunc>
784 void compile(InitBrandFunc&& initBrand) {
785 kj::Vector<BrandScope*> levels;
786 BrandScope* ptr = this;
787 for (;;) {
788 if (ptr->params.size() > 0 || (ptr->inherited && ptr->leafParamCount > 0)) {
789 levels.add(ptr);
790 }
791 KJ_IF_MAYBE(p, ptr->parent) {
792 ptr = *p;
793 } else {
794 break;
795 }
796 }
797
798 if (levels.size() > 0) {
799 auto scopes = initBrand().initScopes(levels.size());
800 for (uint i: kj::indices(levels)) {
801 auto scope = scopes[i];
802 scope.setScopeId(levels[i]->leafId);
803
804 if (levels[i]->inherited) {
805 scope.setInherit();
806 } else {
807 auto bindings = scope.initBind(levels[i]->params.size());
808 for (uint j: kj::indices(bindings)) {
809 levels[i]->params[j].compileAsType(errorReporter, bindings[j].initType());
810 }
811 }
812 }
813 }
814 }
815
816 kj::Maybe<NodeTranslator::BrandedDecl> compileDeclExpression(
817 Expression::Reader source, Resolver& resolver,
818 ImplicitParams implicitMethodParams);
819
820 NodeTranslator::BrandedDecl interpretResolve(
821 Resolver& resolver, Resolver::ResolveResult& result, Expression::Reader source);
822
823 kj::Own<NodeTranslator::BrandScope> evaluateBrand(
824 Resolver& resolver, Resolver::ResolvedDecl decl,
825 List<schema::Brand::Scope>::Reader brand, uint index = 0);
826
827 BrandedDecl decompileType(Resolver& resolver, schema::Type::Reader type);
828
829 inline uint64_t getScopeId() { return leafId; }
830
831private:
832 ErrorReporter& errorReporter;
833 kj::Maybe<kj::Own<NodeTranslator::BrandScope>> parent;
834 uint64_t leafId; // zero = this is the root
835 uint leafParamCount; // number of generic parameters on this leaf
836 bool inherited;
837 kj::Array<BrandedDecl> params;
838
839 BrandScope(kj::Own<NodeTranslator::BrandScope> parent, uint64_t leafId, uint leafParamCount)
840 : errorReporter(parent->errorReporter),
841 parent(kj::mv(parent)), leafId(leafId), leafParamCount(leafParamCount),
842 inherited(false) {}
843 BrandScope(BrandScope& base, kj::Array<BrandedDecl> params)
844 : errorReporter(base.errorReporter),
845 leafId(base.leafId), leafParamCount(base.leafParamCount),
846 inherited(false), params(kj::mv(params)) {
847 KJ_IF_MAYBE(p, base.parent) {
848 parent = kj::addRef(**p);
849 }
850 }
851 BrandScope(ErrorReporter& errorReporter, uint64_t scopeId)
852 : errorReporter(errorReporter), leafId(scopeId), leafParamCount(0), inherited(false) {}
853
854 template <typename T, typename... Params>
855 friend kj::Own<T> kj::refcounted(Params&&... params);
856};
857
858NodeTranslator::BrandedDecl::BrandedDecl(BrandedDecl& other)
859 : body(other.body),
860 source(other.source) {
861 if (body.is<Resolver::ResolvedDecl>()) {
862 brand = kj::addRef(*other.brand);
863 }
864}
865
866NodeTranslator::BrandedDecl& NodeTranslator::BrandedDecl::operator=(BrandedDecl& other) {
867 body = other.body;
868 source = other.source;
869 if (body.is<Resolver::ResolvedDecl>()) {
870 brand = kj::addRef(*other.brand);
871 }
872 return *this;
873}
874
875kj::Maybe<NodeTranslator::BrandedDecl> NodeTranslator::BrandedDecl::applyParams(
876 kj::Array<BrandedDecl> params, Expression::Reader subSource) {
877 if (body.is<Resolver::ResolvedParameter>()) {
878 return nullptr;
879 } else {
880 return brand->setParams(kj::mv(params), body.get<Resolver::ResolvedDecl>().kind, subSource)
881 .map([&](kj::Own<BrandScope>&& scope) {
882 BrandedDecl result = *this;
883 result.brand = kj::mv(scope);
884 result.source = subSource;
885 return result;
886 });
887 }
888}
889
890kj::Maybe<NodeTranslator::BrandedDecl> NodeTranslator::BrandedDecl::getMember(
891 kj::StringPtr memberName, Expression::Reader subSource) {
892 if (body.is<Resolver::ResolvedParameter>()) {
893 return nullptr;
894 } else KJ_IF_MAYBE(r, body.get<Resolver::ResolvedDecl>().resolver->resolveMember(memberName)) {
895 return brand->interpretResolve(*body.get<Resolver::ResolvedDecl>().resolver, *r, subSource);
896 } else {
897 return nullptr;
898 }
899}
900
901kj::Maybe<Declaration::Which> NodeTranslator::BrandedDecl::getKind() {
902 if (body.is<Resolver::ResolvedParameter>()) {
903 return nullptr;
904 } else {
905 return body.get<Resolver::ResolvedDecl>().kind;
906 }
907}
908
909template <typename InitBrandFunc>
910uint64_t NodeTranslator::BrandedDecl::getIdAndFillBrand(InitBrandFunc&& initBrand) {
911 KJ_REQUIRE(body.is<Resolver::ResolvedDecl>());
912
913 brand->compile(kj::fwd<InitBrandFunc>(initBrand));
914 return body.get<Resolver::ResolvedDecl>().id;
915}
916
917kj::Maybe<NodeTranslator::BrandedDecl&> NodeTranslator::BrandedDecl::getListParam() {
918 KJ_REQUIRE(body.is<Resolver::ResolvedDecl>());
919
920 auto& decl = body.get<Resolver::ResolvedDecl>();
921 KJ_REQUIRE(decl.kind == Declaration::BUILTIN_LIST);
922
923 auto params = KJ_ASSERT_NONNULL(brand->getParams(decl.id));
924 if (params.size() != 1) {
925 return nullptr;
926 } else {
927 return params[0];
928 }
929}
930
931NodeTranslator::Resolver::ResolvedParameter NodeTranslator::BrandedDecl::asVariable() {
932 KJ_REQUIRE(body.is<Resolver::ResolvedParameter>());
933
934 return body.get<Resolver::ResolvedParameter>();
935}
936
937bool NodeTranslator::BrandedDecl::compileAsType(
938 ErrorReporter& errorReporter, schema::Type::Builder target) {
939 KJ_IF_MAYBE(kind, getKind()) {
940 switch (*kind) {
941 case Declaration::ENUM: {
942 auto enum_ = target.initEnum();
943 enum_.setTypeId(getIdAndFillBrand([&]() { return enum_.initBrand(); }));
944 return true;
945 }
946
947 case Declaration::STRUCT: {
948 auto struct_ = target.initStruct();
949 struct_.setTypeId(getIdAndFillBrand([&]() { return struct_.initBrand(); }));
950 return true;
951 }
952
953 case Declaration::INTERFACE: {
954 auto interface = target.initInterface();
955 interface.setTypeId(getIdAndFillBrand([&]() { return interface.initBrand(); }));
956 return true;
957 }
958
959 case Declaration::BUILTIN_LIST: {
960 auto elementType = target.initList().initElementType();
961
962 KJ_IF_MAYBE(param, getListParam()) {
963 if (!param->compileAsType(errorReporter, elementType)) {
964 return false;
965 }
966 } else {
967 addError(errorReporter, "'List' requires exactly one parameter.");
968 return false;
969 }
970
971 if (elementType.isAnyPointer()) {
972 addError(errorReporter, "'List(AnyPointer)' is not supported.");
973 // Seeing List(AnyPointer) later can mess things up, so change the type to Void.
974 elementType.setVoid();
975 return false;
976 }
977
978 return true;
979 }
980
981 case Declaration::BUILTIN_VOID: target.setVoid(); return true;
982 case Declaration::BUILTIN_BOOL: target.setBool(); return true;
983 case Declaration::BUILTIN_INT8: target.setInt8(); return true;
984 case Declaration::BUILTIN_INT16: target.setInt16(); return true;
985 case Declaration::BUILTIN_INT32: target.setInt32(); return true;
986 case Declaration::BUILTIN_INT64: target.setInt64(); return true;
987 case Declaration::BUILTIN_U_INT8: target.setUint8(); return true;
988 case Declaration::BUILTIN_U_INT16: target.setUint16(); return true;
989 case Declaration::BUILTIN_U_INT32: target.setUint32(); return true;
990 case Declaration::BUILTIN_U_INT64: target.setUint64(); return true;
991 case Declaration::BUILTIN_FLOAT32: target.setFloat32(); return true;
992 case Declaration::BUILTIN_FLOAT64: target.setFloat64(); return true;
993 case Declaration::BUILTIN_TEXT: target.setText(); return true;
994 case Declaration::BUILTIN_DATA: target.setData(); return true;
995
996 case Declaration::BUILTIN_OBJECT:
997 addError(errorReporter,
998 "As of Cap'n Proto 0.4, 'Object' has been renamed to 'AnyPointer'. Sorry for the "
999 "inconvenience, and thanks for being an early adopter. :)");
1000 // fallthrough
1001 case Declaration::BUILTIN_ANY_POINTER:
1002 target.initAnyPointer().initUnconstrained().setAnyKind();
1003 return true;
1004 case Declaration::BUILTIN_ANY_STRUCT:
1005 target.initAnyPointer().initUnconstrained().setStruct();
1006 return true;
1007 case Declaration::BUILTIN_ANY_LIST:
1008 target.initAnyPointer().initUnconstrained().setList();
1009 return true;
1010 case Declaration::BUILTIN_CAPABILITY:
1011 target.initAnyPointer().initUnconstrained().setCapability();
1012 return true;
1013
1014 case Declaration::FILE:
1015 case Declaration::USING:
1016 case Declaration::CONST:
1017 case Declaration::ENUMERANT:
1018 case Declaration::FIELD:
1019 case Declaration::UNION:
1020 case Declaration::GROUP:
1021 case Declaration::METHOD:
1022 case Declaration::ANNOTATION:
1023 case Declaration::NAKED_ID:
1024 case Declaration::NAKED_ANNOTATION:
1025 addError(errorReporter, kj::str("'", toString(), "' is not a type."));
1026 return false;
1027 }
1028
1029 KJ_UNREACHABLE;
1030 } else {
1031 // Oh, this is a type variable.
1032 auto var = asVariable();
1033 if (var.id == 0) {
1034 // This is actually a method implicit parameter.
1035 auto builder = target.initAnyPointer().initImplicitMethodParameter();
1036 builder.setParameterIndex(var.index);
1037 return true;
1038 } else {
1039 auto builder = target.initAnyPointer().initParameter();
1040 builder.setScopeId(var.id);
1041 builder.setParameterIndex(var.index);
1042 return true;
1043 }
1044 }
1045}
1046
1047NodeTranslator::Resolver::ResolveResult NodeTranslator::BrandedDecl::asResolveResult(
1048 uint64_t scopeId, schema::Brand::Builder brandBuilder) {
1049 auto result = body;
1050 if (result.is<Resolver::ResolvedDecl>()) {
1051 // May need to compile our context as the "brand".
1052
1053 result.get<Resolver::ResolvedDecl>().scopeId = scopeId;
1054
1055 getIdAndFillBrand([&]() {
1056 result.get<Resolver::ResolvedDecl>().brand = brandBuilder.asReader();
1057 return brandBuilder;
1058 });
1059 }
1060 return result;
1061}
1062
1063static kj::String expressionString(Expression::Reader name); // defined later
1064
1065kj::String NodeTranslator::BrandedDecl::toString() {
1066 return expressionString(source);
1067}
1068
1069kj::String NodeTranslator::BrandedDecl::toDebugString() {
1070 if (body.is<Resolver::ResolvedParameter>()) {
1071 auto variable = body.get<Resolver::ResolvedParameter>();
1072 return kj::str("variable(", variable.id, ", ", variable.index, ")");
1073 } else {
1074 auto decl = body.get<Resolver::ResolvedDecl>();
1075 return kj::str("decl(", decl.id, ", ", (uint)decl.kind, "')");
1076 }
1077}
1078
1079NodeTranslator::BrandedDecl NodeTranslator::BrandScope::interpretResolve(
1080 Resolver& resolver, Resolver::ResolveResult& result, Expression::Reader source) {
1081 if (result.is<Resolver::ResolvedDecl>()) {
1082 auto& decl = result.get<Resolver::ResolvedDecl>();
1083
1084 auto scope = pop(decl.scopeId);
1085 KJ_IF_MAYBE(brand, decl.brand) {
1086 scope = scope->evaluateBrand(resolver, decl, brand->getScopes());
1087 } else {
1088 scope = scope->push(decl.id, decl.genericParamCount);
1089 }
1090
1091 return BrandedDecl(decl, kj::mv(scope), source);
1092 } else {
1093 auto& param = result.get<Resolver::ResolvedParameter>();
1094 KJ_IF_MAYBE(p, lookupParameter(resolver, param.id, param.index)) {
1095 return *p;
1096 } else {
1097 return BrandedDecl(param, source);
1098 }
1099 }
1100}
1101
1102kj::Own<NodeTranslator::BrandScope> NodeTranslator::BrandScope::evaluateBrand(
1103 Resolver& resolver, Resolver::ResolvedDecl decl,
1104 List<schema::Brand::Scope>::Reader brand, uint index) {
1105 auto result = kj::refcounted<BrandScope>(errorReporter, decl.id);
1106 result->leafParamCount = decl.genericParamCount;
1107
1108 // Fill in `params`.
1109 if (index < brand.size()) {
1110 auto nextScope = brand[index];
1111 if (decl.id == nextScope.getScopeId()) {
1112 // Initialize our parameters.
1113
1114 switch (nextScope.which()) {
1115 case schema::Brand::Scope::BIND: {
1116 auto bindings = nextScope.getBind();
1117 auto params = kj::heapArrayBuilder<BrandedDecl>(bindings.size());
1118 for (auto binding: bindings) {
1119 switch (binding.which()) {
1120 case schema::Brand::Binding::UNBOUND: {
1121 // Build an AnyPointer-equivalent.
1122 auto anyPointerDecl = resolver.resolveBuiltin(Declaration::BUILTIN_ANY_POINTER);
1123 params.add(BrandedDecl(anyPointerDecl,
1124 kj::refcounted<BrandScope>(errorReporter, anyPointerDecl.scopeId),
1125 Expression::Reader()));
1126 break;
1127 }
1128
1129 case schema::Brand::Binding::TYPE:
1130 // Reverse this schema::Type back into a BrandedDecl.
1131 params.add(decompileType(resolver, binding.getType()));
1132 break;
1133 }
1134 }
1135 result->params = params.finish();
1136 break;
1137 }
1138
1139 case schema::Brand::Scope::INHERIT:
1140 KJ_IF_MAYBE(p, getParams(decl.id)) {
1141 result->params = kj::heapArray(*p);
1142 } else {
1143 result->inherited = true;
1144 }
1145 break;
1146 }
1147
1148 // Parent should start one level deeper in the list.
1149 ++index;
1150 }
1151 }
1152
1153 // Fill in `parent`.
1154 KJ_IF_MAYBE(parent, decl.resolver->getParent()) {
1155 result->parent = evaluateBrand(resolver, *parent, brand, index);
1156 }
1157
1158 return result;
1159}
1160
1161NodeTranslator::BrandedDecl NodeTranslator::BrandScope::decompileType(
1162 Resolver& resolver, schema::Type::Reader type) {
1163 auto builtin = [&](Declaration::Which which) -> BrandedDecl {
1164 auto decl = resolver.resolveBuiltin(which);
1165 return BrandedDecl(decl,
1166 evaluateBrand(resolver, decl, List<schema::Brand::Scope>::Reader()),
1167 Expression::Reader());
1168 };
1169
1170 switch (type.which()) {
1171 case schema::Type::VOID: return builtin(Declaration::BUILTIN_VOID);
1172 case schema::Type::BOOL: return builtin(Declaration::BUILTIN_BOOL);
1173 case schema::Type::INT8: return builtin(Declaration::BUILTIN_INT8);
1174 case schema::Type::INT16: return builtin(Declaration::BUILTIN_INT16);
1175 case schema::Type::INT32: return builtin(Declaration::BUILTIN_INT32);
1176 case schema::Type::INT64: return builtin(Declaration::BUILTIN_INT64);
1177 case schema::Type::UINT8: return builtin(Declaration::BUILTIN_U_INT8);
1178 case schema::Type::UINT16: return builtin(Declaration::BUILTIN_U_INT16);
1179 case schema::Type::UINT32: return builtin(Declaration::BUILTIN_U_INT32);
1180 case schema::Type::UINT64: return builtin(Declaration::BUILTIN_U_INT64);
1181 case schema::Type::FLOAT32: return builtin(Declaration::BUILTIN_FLOAT32);
1182 case schema::Type::FLOAT64: return builtin(Declaration::BUILTIN_FLOAT64);
1183 case schema::Type::TEXT: return builtin(Declaration::BUILTIN_TEXT);
1184 case schema::Type::DATA: return builtin(Declaration::BUILTIN_DATA);
1185
1186 case schema::Type::ENUM: {
1187 auto enumType = type.getEnum();
1188 Resolver::ResolvedDecl decl = resolver.resolveId(enumType.getTypeId());
1189 return BrandedDecl(decl,
1190 evaluateBrand(resolver, decl, enumType.getBrand().getScopes()),
1191 Expression::Reader());
1192 }
1193
1194 case schema::Type::INTERFACE: {
1195 auto interfaceType = type.getInterface();
1196 Resolver::ResolvedDecl decl = resolver.resolveId(interfaceType.getTypeId());
1197 return BrandedDecl(decl,
1198 evaluateBrand(resolver, decl, interfaceType.getBrand().getScopes()),
1199 Expression::Reader());
1200 }
1201
1202 case schema::Type::STRUCT: {
1203 auto structType = type.getStruct();
1204 Resolver::ResolvedDecl decl = resolver.resolveId(structType.getTypeId());
1205 return BrandedDecl(decl,
1206 evaluateBrand(resolver, decl, structType.getBrand().getScopes()),
1207 Expression::Reader());
1208 }
1209
1210 case schema::Type::LIST: {
1211 auto elementType = decompileType(resolver, type.getList().getElementType());
1212 return KJ_ASSERT_NONNULL(builtin(Declaration::BUILTIN_LIST)
1213 .applyParams(kj::heapArray(&elementType, 1), Expression::Reader()));
1214 }
1215
1216 case schema::Type::ANY_POINTER: {
1217 auto anyPointer = type.getAnyPointer();
1218 switch (anyPointer.which()) {
1219 case schema::Type::AnyPointer::UNCONSTRAINED:
1220 return builtin(Declaration::BUILTIN_ANY_POINTER);
1221
1222 case schema::Type::AnyPointer::PARAMETER: {
1223 auto param = anyPointer.getParameter();
1224 auto id = param.getScopeId();
1225 uint index = param.getParameterIndex();
1226 KJ_IF_MAYBE(binding, lookupParameter(resolver, id, index)) {
1227 return *binding;
1228 } else {
1229 return BrandedDecl(Resolver::ResolvedParameter {id, index}, Expression::Reader());
1230 }
1231 }
1232
1233 case schema::Type::AnyPointer::IMPLICIT_METHOD_PARAMETER:
1234 KJ_FAIL_ASSERT("Alias pointed to implicit method type parameter?");
1235 }
1236
1237 KJ_UNREACHABLE;
1238 }
1239 }
1240
1241 KJ_UNREACHABLE;
1242}
1243
1244kj::Maybe<NodeTranslator::BrandedDecl> NodeTranslator::BrandScope::compileDeclExpression(
1245 Expression::Reader source, Resolver& resolver,
1246 ImplicitParams implicitMethodParams) {
1247 switch (source.which()) {
1248 case Expression::UNKNOWN:
1249 // Error reported earlier.
1250 return nullptr;
1251
1252 case Expression::POSITIVE_INT:
1253 case Expression::NEGATIVE_INT:
1254 case Expression::FLOAT:
1255 case Expression::STRING:
1256 case Expression::BINARY:
1257 case Expression::LIST:
1258 case Expression::TUPLE:
1259 case Expression::EMBED:
1260 errorReporter.addErrorOn(source, "Expected name.");
1261 return nullptr;
1262
1263 case Expression::RELATIVE_NAME: {
1264 auto name = source.getRelativeName();
1265 auto nameValue = name.getValue();
1266
1267 // Check implicit method params first.
1268 for (auto i: kj::indices(implicitMethodParams.params)) {
1269 if (implicitMethodParams.params[i].getName() == nameValue) {
1270 if (implicitMethodParams.scopeId == 0) {
1271 return BrandedDecl::implicitMethodParam(i);
1272 } else {
1273 return BrandedDecl(Resolver::ResolvedParameter {
1274 implicitMethodParams.scopeId, static_cast<uint16_t>(i) },
1275 Expression::Reader());
1276 }
1277 }
1278 }
1279
1280 KJ_IF_MAYBE(r, resolver.resolve(nameValue)) {
1281 return interpretResolve(resolver, *r, source);
1282 } else {
1283 errorReporter.addErrorOn(name, kj::str("Not defined: ", nameValue));
1284 return nullptr;
1285 }
1286 }
1287
1288 case Expression::ABSOLUTE_NAME: {
1289 auto name = source.getAbsoluteName();
1290 KJ_IF_MAYBE(r, resolver.getTopScope().resolver->resolveMember(name.getValue())) {
1291 return interpretResolve(resolver, *r, source);
1292 } else {
1293 errorReporter.addErrorOn(name, kj::str("Not defined: ", name.getValue()));
1294 return nullptr;
1295 }
1296 }
1297
1298 case Expression::IMPORT: {
1299 auto filename = source.getImport();
1300 KJ_IF_MAYBE(decl, resolver.resolveImport(filename.getValue())) {
1301 // Import is always a root scope, so create a fresh BrandScope.
1302 return BrandedDecl(*decl, kj::refcounted<BrandScope>(
1303 errorReporter, decl->id, decl->genericParamCount, *decl->resolver), source);
1304 } else {
1305 errorReporter.addErrorOn(filename, kj::str("Import failed: ", filename.getValue()));
1306 return nullptr;
1307 }
1308 }
1309
1310 case Expression::APPLICATION: {
1311 auto app = source.getApplication();
1312 KJ_IF_MAYBE(decl, compileDeclExpression(app.getFunction(), resolver, implicitMethodParams)) {
1313 // Compile all params.
1314 auto params = app.getParams();
1315 auto compiledParams = kj::heapArrayBuilder<BrandedDecl>(params.size());
1316 bool paramFailed = false;
1317 for (auto param: params) {
1318 if (param.isNamed()) {
1319 errorReporter.addErrorOn(param.getNamed(), "Named parameter not allowed here.");
1320 }
1321
1322 KJ_IF_MAYBE(d, compileDeclExpression(param.getValue(), resolver, implicitMethodParams)) {
1323 compiledParams.add(kj::mv(*d));
1324 } else {
1325 // Param failed to compile. Error was already reported.
1326 paramFailed = true;
1327 }
1328 };
1329
1330 if (paramFailed) {
1331 return kj::mv(*decl);
1332 }
1333
1334 // Add the parameters to the brand.
1335 KJ_IF_MAYBE(applied, decl->applyParams(compiledParams.finish(), source)) {
1336 return kj::mv(*applied);
1337 } else {
1338 // Error already reported. Ignore parameters.
1339 return kj::mv(*decl);
1340 }
1341 } else {
1342 // error already reported
1343 return nullptr;
1344 }
1345 }
1346
1347 case Expression::MEMBER: {
1348 auto member = source.getMember();
1349 KJ_IF_MAYBE(decl, compileDeclExpression(member.getParent(), resolver, implicitMethodParams)) {
1350 auto name = member.getName();
1351 KJ_IF_MAYBE(memberDecl, decl->getMember(name.getValue(), source)) {
1352 return kj::mv(*memberDecl);
1353 } else {
1354 errorReporter.addErrorOn(name, kj::str(
1355 "'", expressionString(member.getParent()),
1356 "' has no member named '", name.getValue(), "'"));
1357 return nullptr;
1358 }
1359 } else {
1360 // error already reported
1361 return nullptr;
1362 }
1363 }
1364 }
1365
1366 KJ_UNREACHABLE;
1367}
1368
1369// =======================================================================================
1370
1371NodeTranslator::NodeTranslator(
1372 Resolver& resolver, ErrorReporter& errorReporter,
1373 const Declaration::Reader& decl, Orphan<schema::Node> wipNodeParam,
1374 bool compileAnnotations)
1375 : resolver(resolver), errorReporter(errorReporter),
1376 orphanage(Orphanage::getForMessageContaining(wipNodeParam.get())),
1377 compileAnnotations(compileAnnotations),
1378 localBrand(kj::refcounted<BrandScope>(
1379 errorReporter, wipNodeParam.getReader().getId(),
1380 decl.getParameters().size(), resolver)),
1381 wipNode(kj::mv(wipNodeParam)),
1382 sourceInfo(orphanage.newOrphan<schema::Node::SourceInfo>()) {
1383 compileNode(decl, wipNode.get());
1384}
1385
1386NodeTranslator::~NodeTranslator() noexcept(false) {}
1387
1388NodeTranslator::NodeSet NodeTranslator::getBootstrapNode() {
1389 auto sourceInfos = kj::heapArrayBuilder<schema::Node::SourceInfo::Reader>(
1390 1 + groups.size() + paramStructs.size());
1391 sourceInfos.add(sourceInfo.getReader());
1392 for (auto& group: groups) {
1393 sourceInfos.add(group.sourceInfo.getReader());
1394 }
1395 for (auto& paramStruct: paramStructs) {
1396 sourceInfos.add(paramStruct.sourceInfo.getReader());
1397 }
1398
1399 auto nodeReader = wipNode.getReader();
1400 if (nodeReader.isInterface()) {
1401 return NodeSet {
1402 nodeReader,
1403 KJ_MAP(g, paramStructs) { return g.node.getReader(); },
1404 sourceInfos.finish()
1405 };
1406 } else {
1407 return NodeSet {
1408 nodeReader,
1409 KJ_MAP(g, groups) { return g.node.getReader(); },
1410 sourceInfos.finish()
1411 };
1412 }
1413}
1414
1415NodeTranslator::NodeSet NodeTranslator::finish() {
1416 // Careful about iteration here: compileFinalValue() may actually add more elements to
1417 // `unfinishedValues`, invalidating iterators in the process.
1418 for (size_t i = 0; i < unfinishedValues.size(); i++) {
1419 auto& value = unfinishedValues[i];
1420 compileValue(value.source, value.type, value.typeScope, value.target, false);
1421 }
1422
1423 return getBootstrapNode();
1424}
1425
1426class NodeTranslator::DuplicateNameDetector {
1427public:
1428 inline explicit DuplicateNameDetector(ErrorReporter& errorReporter)
1429 : errorReporter(errorReporter) {}
1430 void check(List<Declaration>::Reader nestedDecls, Declaration::Which parentKind);
1431
1432private:
1433 ErrorReporter& errorReporter;
1434 std::map<kj::StringPtr, LocatedText::Reader> names;
1435};
1436
1437void NodeTranslator::compileNode(Declaration::Reader decl, schema::Node::Builder builder) {
1438 DuplicateNameDetector(errorReporter)
1439 .check(decl.getNestedDecls(), decl.which());
1440
1441 auto genericParams = decl.getParameters();
1442 if (genericParams.size() > 0) {
1443 auto paramsBuilder = builder.initParameters(genericParams.size());
1444 for (auto i: kj::indices(genericParams)) {
1445 paramsBuilder[i].setName(genericParams[i].getName());
1446 }
1447 }
1448
1449 builder.setIsGeneric(localBrand->isGeneric());
1450
1451 kj::StringPtr targetsFlagName;
1452
1453 switch (decl.which()) {
1454 case Declaration::FILE:
1455 targetsFlagName = "targetsFile";
1456 break;
1457 case Declaration::CONST:
1458 compileConst(decl.getConst(), builder.initConst());
1459 targetsFlagName = "targetsConst";
1460 break;
1461 case Declaration::ANNOTATION:
1462 compileAnnotation(decl.getAnnotation(), builder.initAnnotation());
1463 targetsFlagName = "targetsAnnotation";
1464 break;
1465 case Declaration::ENUM:
1466 compileEnum(decl.getEnum(), decl.getNestedDecls(), builder);
1467 targetsFlagName = "targetsEnum";
1468 break;
1469 case Declaration::STRUCT:
1470 compileStruct(decl.getStruct(), decl.getNestedDecls(), builder);
1471 targetsFlagName = "targetsStruct";
1472 break;
1473 case Declaration::INTERFACE:
1474 compileInterface(decl.getInterface(), decl.getNestedDecls(), builder);
1475 targetsFlagName = "targetsInterface";
1476 break;
1477
1478 default:
1479 KJ_FAIL_REQUIRE("This Declaration is not a node.");
1480 break;
1481 }
1482
1483 builder.adoptAnnotations(compileAnnotationApplications(decl.getAnnotations(), targetsFlagName));
1484
1485 auto di = sourceInfo.get();
1486 di.setId(wipNode.getReader().getId());
1487 if (decl.hasDocComment()) {
1488 di.setDocComment(decl.getDocComment());
1489 }
1490}
1491
1492static kj::StringPtr getExpressionTargetName(Expression::Reader exp) {
1493 kj::StringPtr targetName;
1494 switch (exp.which()) {
1495 case Expression::ABSOLUTE_NAME:
1496 return exp.getAbsoluteName().getValue();
1497 case Expression::RELATIVE_NAME:
1498 return exp.getRelativeName().getValue();
1499 case Expression::APPLICATION:
1500 return getExpressionTargetName(exp.getApplication().getFunction());
1501 case Expression::MEMBER:
1502 return exp.getMember().getName().getValue();
1503 default:
1504 return nullptr;
1505 }
1506}
1507
1508void NodeTranslator::DuplicateNameDetector::check(
1509 List<Declaration>::Reader nestedDecls, Declaration::Which parentKind) {
1510 for (auto decl: nestedDecls) {
1511 {
1512 auto name = decl.getName();
1513 auto nameText = name.getValue();
1514 auto insertResult = names.insert(std::make_pair(nameText, name));
1515 if (!insertResult.second) {
1516 if (nameText.size() == 0 && decl.isUnion()) {
1517 errorReporter.addErrorOn(
1518 name, kj::str("An unnamed union is already defined in this scope."));
1519 errorReporter.addErrorOn(
1520 insertResult.first->second, kj::str("Previously defined here."));
1521 } else {
1522 errorReporter.addErrorOn(
1523 name, kj::str("'", nameText, "' is already defined in this scope."));
1524 errorReporter.addErrorOn(
1525 insertResult.first->second, kj::str("'", nameText, "' previously defined here."));
1526 }
1527 }
1528
1529 switch (decl.which()) {
1530 case Declaration::USING: {
1531 kj::StringPtr targetName = getExpressionTargetName(decl.getUsing().getTarget());
1532 if (targetName.size() > 0 && targetName[0] >= 'a' && targetName[0] <= 'z') {
1533 // Target starts with lower-case letter, so alias should too.
1534 if (nameText.size() > 0 && (nameText[0] < 'a' || nameText[0] > 'z')) {
1535 errorReporter.addErrorOn(name,
1536 "Non-type names must begin with a lower-case letter.");
1537 }
1538 } else {
1539 // Target starts with capital or is not named (probably, an import). Require
1540 // capitalization.
1541 if (nameText.size() > 0 && (nameText[0] < 'A' || nameText[0] > 'Z')) {
1542 errorReporter.addErrorOn(name,
1543 "Type names must begin with a capital letter.");
1544 }
1545 }
1546 break;
1547 }
1548
1549 case Declaration::ENUM:
1550 case Declaration::STRUCT:
1551 case Declaration::INTERFACE:
1552 if (nameText.size() > 0 && (nameText[0] < 'A' || nameText[0] > 'Z')) {
1553 errorReporter.addErrorOn(name,
1554 "Type names must begin with a capital letter.");
1555 }
1556 break;
1557
1558 case Declaration::CONST:
1559 case Declaration::ANNOTATION:
1560 case Declaration::ENUMERANT:
1561 case Declaration::METHOD:
1562 case Declaration::FIELD:
1563 case Declaration::UNION:
1564 case Declaration::GROUP:
1565 if (nameText.size() > 0 && (nameText[0] < 'a' || nameText[0] > 'z')) {
1566 errorReporter.addErrorOn(name,
1567 "Non-type names must begin with a lower-case letter.");
1568 }
1569 break;
1570
1571 default:
1572 KJ_ASSERT(nameText.size() == 0, "Don't know what naming rules to enforce for node type.",
1573 (uint)decl.which());
1574 break;
1575 }
1576
1577 if (nameText.findFirst('_') != nullptr) {
1578 errorReporter.addErrorOn(name,
1579 "Cap'n Proto declaration names should use camelCase and must not contain "
1580 "underscores. (Code generators may convert names to the appropriate style for the "
1581 "target language.)");
1582 }
1583 }
1584
1585 switch (decl.which()) {
1586 case Declaration::USING:
1587 case Declaration::CONST:
1588 case Declaration::ENUM:
1589 case Declaration::STRUCT:
1590 case Declaration::INTERFACE:
1591 case Declaration::ANNOTATION:
1592 switch (parentKind) {
1593 case Declaration::FILE:
1594 case Declaration::STRUCT:
1595 case Declaration::INTERFACE:
1596 // OK.
1597 break;
1598 default:
1599 errorReporter.addErrorOn(decl, "This kind of declaration doesn't belong here.");
1600 break;
1601 }
1602 break;
1603
1604 case Declaration::ENUMERANT:
1605 if (parentKind != Declaration::ENUM) {
1606 errorReporter.addErrorOn(decl, "Enumerants can only appear in enums.");
1607 }
1608 break;
1609 case Declaration::METHOD:
1610 if (parentKind != Declaration::INTERFACE) {
1611 errorReporter.addErrorOn(decl, "Methods can only appear in interfaces.");
1612 }
1613 break;
1614 case Declaration::FIELD:
1615 case Declaration::UNION:
1616 case Declaration::GROUP:
1617 switch (parentKind) {
1618 case Declaration::STRUCT:
1619 case Declaration::UNION:
1620 case Declaration::GROUP:
1621 // OK.
1622 break;
1623 default:
1624 errorReporter.addErrorOn(decl, "This declaration can only appear in structs.");
1625 break;
1626 }
1627
1628 // Struct members may have nested decls. We need to check those here, because no one else
1629 // is going to do it.
1630 if (decl.getName().getValue().size() == 0) {
1631 // Unnamed union. Check members as if they are in the same scope.
1632 check(decl.getNestedDecls(), decl.which());
1633 } else {
1634 // Children are in their own scope.
1635 DuplicateNameDetector(errorReporter)
1636 .check(decl.getNestedDecls(), decl.which());
1637 }
1638
1639 break;
1640
1641 default:
1642 errorReporter.addErrorOn(decl, "This kind of declaration doesn't belong here.");
1643 break;
1644 }
1645 }
1646}
1647
1648void NodeTranslator::compileConst(Declaration::Const::Reader decl,
1649 schema::Node::Const::Builder builder) {
1650 auto typeBuilder = builder.initType();
1651 if (compileType(decl.getType(), typeBuilder, noImplicitParams())) {
1652 compileBootstrapValue(decl.getValue(), typeBuilder.asReader(), builder.initValue());
1653 }
1654}
1655
1656void NodeTranslator::compileAnnotation(Declaration::Annotation::Reader decl,
1657 schema::Node::Annotation::Builder builder) {
1658 compileType(decl.getType(), builder.initType(), noImplicitParams());
1659
1660 // Dynamically copy over the values of all of the "targets" members.
1661 DynamicStruct::Reader src = decl;
1662 DynamicStruct::Builder dst = builder;
1663 for (auto srcField: src.getSchema().getFields()) {
1664 kj::StringPtr fieldName = srcField.getProto().getName();
1665 if (fieldName.startsWith("targets")) {
1666 auto dstField = dst.getSchema().getFieldByName(fieldName);
1667 dst.set(dstField, src.get(srcField));
1668 }
1669 }
1670}
1671
1672class NodeTranslator::DuplicateOrdinalDetector {
1673public:
1674 DuplicateOrdinalDetector(ErrorReporter& errorReporter): errorReporter(errorReporter) {}
1675
1676 void check(LocatedInteger::Reader ordinal) {
1677 if (ordinal.getValue() < expectedOrdinal) {
1678 errorReporter.addErrorOn(ordinal, "Duplicate ordinal number.");
1679 KJ_IF_MAYBE(last, lastOrdinalLocation) {
1680 errorReporter.addErrorOn(
1681 *last, kj::str("Ordinal @", last->getValue(), " originally used here."));
1682 // Don't report original again.
1683 lastOrdinalLocation = nullptr;
1684 }
1685 } else if (ordinal.getValue() > expectedOrdinal) {
1686 errorReporter.addErrorOn(ordinal,
1687 kj::str("Skipped ordinal @", expectedOrdinal, ". Ordinals must be sequential with no "
1688 "holes."));
1689 expectedOrdinal = ordinal.getValue() + 1;
1690 } else {
1691 ++expectedOrdinal;
1692 lastOrdinalLocation = ordinal;
1693 }
1694 }
1695
1696private:
1697 ErrorReporter& errorReporter;
1698 uint expectedOrdinal = 0;
1699 kj::Maybe<LocatedInteger::Reader> lastOrdinalLocation;
1700};
1701
1702void NodeTranslator::compileEnum(Void decl,
1703 List<Declaration>::Reader members,
1704 schema::Node::Builder builder) {
1705 // maps ordinal -> (code order, declaration)
1706 std::multimap<uint, std::pair<uint, Declaration::Reader>> enumerants;
1707
1708 uint codeOrder = 0;
1709 for (auto member: members) {
1710 if (member.isEnumerant()) {
1711 enumerants.insert(
1712 std::make_pair(member.getId().getOrdinal().getValue(),
1713 std::make_pair(codeOrder++, member)));
1714 }
1715 }
1716
1717 auto list = builder.initEnum().initEnumerants(enumerants.size());
1718 auto sourceInfoList = sourceInfo.get().initMembers(enumerants.size());
1719 uint i = 0;
1720 DuplicateOrdinalDetector dupDetector(errorReporter);
1721
1722 for (auto& entry: enumerants) {
1723 uint codeOrder = entry.second.first;
1724 Declaration::Reader enumerantDecl = entry.second.second;
1725
1726 dupDetector.check(enumerantDecl.getId().getOrdinal());
1727
1728 if (enumerantDecl.hasDocComment()) {
1729 sourceInfoList[i].setDocComment(enumerantDecl.getDocComment());
1730 }
1731
1732 auto enumerantBuilder = list[i++];
1733 enumerantBuilder.setName(enumerantDecl.getName().getValue());
1734 enumerantBuilder.setCodeOrder(codeOrder);
1735 enumerantBuilder.adoptAnnotations(compileAnnotationApplications(
1736 enumerantDecl.getAnnotations(), "targetsEnumerant"));
1737 }
1738}
1739
1740// -------------------------------------------------------------------
1741
1742class NodeTranslator::StructTranslator {
1743public:
1744 explicit StructTranslator(NodeTranslator& translator, ImplicitParams implicitMethodParams)
1745 : translator(translator), errorReporter(translator.errorReporter),
1746 implicitMethodParams(implicitMethodParams) {}
1747 KJ_DISALLOW_COPY(StructTranslator);
1748
1749 void translate(Void decl, List<Declaration>::Reader members, schema::Node::Builder builder,
1750 schema::Node::SourceInfo::Builder sourceInfo) {
1751 // Build the member-info-by-ordinal map.
1752 MemberInfo root(builder, sourceInfo);
1753 traverseTopOrGroup(members, root, layout.getTop());
1754 translateInternal(root, builder);
1755 }
1756
1757 void translate(List<Declaration::Param>::Reader params, schema::Node::Builder builder,
1758 schema::Node::SourceInfo::Builder sourceInfo) {
1759 // Build a struct from a method param / result list.
1760 MemberInfo root(builder, sourceInfo);
1761 traverseParams(params, root, layout.getTop());
1762 translateInternal(root, builder);
1763 }
1764
1765private:
1766 NodeTranslator& translator;
1767 ErrorReporter& errorReporter;
1768 ImplicitParams implicitMethodParams;
1769 StructLayout layout;
1770 kj::Arena arena;
1771
1772 struct NodeSourceInfoBuilderPair {
1773 schema::Node::Builder node;
1774 schema::Node::SourceInfo::Builder sourceInfo;
1775 };
1776
1777 struct FieldSourceInfoBuilderPair {
1778 schema::Field::Builder field;
1779 schema::Node::SourceInfo::Member::Builder sourceInfo;
1780 };
1781
1782 struct MemberInfo {
1783 MemberInfo* parent;
1784 // The MemberInfo for the parent scope.
1785
1786 uint codeOrder;
1787 // Code order within the parent.
1788
1789 uint index = 0;
1790 // Index within the parent.
1791
1792 uint childCount = 0;
1793 // Number of children this member has.
1794
1795 uint childInitializedCount = 0;
1796 // Number of children whose `schema` member has been initialized. This initialization happens
1797 // while walking the fields in ordinal order.
1798
1799 uint unionDiscriminantCount = 0;
1800 // Number of children who are members of the scope's union and have had their discriminant
1801 // value decided.
1802
1803 bool isInUnion;
1804 // Whether or not this field is in the parent's union.
1805
1806 kj::StringPtr name;
1807 Declaration::Id::Reader declId;
1808 Declaration::Which declKind;
1809 bool isParam = false;
1810 bool hasDefaultValue = false; // if declKind == FIELD
1811 Expression::Reader fieldType; // if declKind == FIELD
1812 Expression::Reader fieldDefaultValue; // if declKind == FIELD && hasDefaultValue
1813 List<Declaration::AnnotationApplication>::Reader declAnnotations;
1814 uint startByte = 0;
1815 uint endByte = 0;
1816 // Information about the field declaration. We don't use Declaration::Reader because it might
1817 // have come from a Declaration::Param instead.
1818
1819 kj::Maybe<Text::Reader> docComment = nullptr;
1820
1821 kj::Maybe<schema::Field::Builder> schema;
1822 // Schema for the field. Initialized when getSchema() is first called.
1823
1824 schema::Node::Builder node;
1825 schema::Node::SourceInfo::Builder sourceInfo;
1826 // If it's a group, or the top-level struct.
1827
1828 union {
1829 StructLayout::StructOrGroup* fieldScope;
1830 // If this member is a field, the scope of that field. This will be used to assign an
1831 // offset for the field when going through in ordinal order.
1832
1833 StructLayout::Union* unionScope;
1834 // If this member is a union, or it is a group or top-level struct containing an unnamed
1835 // union, this is the union. This will be used to assign a discriminant offset when the
1836 // union's ordinal comes up (if the union has an explicit ordinal), as well as to finally
1837 // copy over the discriminant offset to the schema.
1838 };
1839
1840 inline explicit MemberInfo(schema::Node::Builder node,
1841 schema::Node::SourceInfo::Builder sourceInfo)
1842 : parent(nullptr), codeOrder(0), isInUnion(false), node(node), sourceInfo(sourceInfo),
1843 unionScope(nullptr) {}
1844 inline MemberInfo(MemberInfo& parent, uint codeOrder,
1845 const Declaration::Reader& decl,
1846 StructLayout::StructOrGroup& fieldScope,
1847 bool isInUnion)
1848 : parent(&parent), codeOrder(codeOrder), isInUnion(isInUnion),
1849 name(decl.getName().getValue()), declId(decl.getId()), declKind(Declaration::FIELD),
1850 declAnnotations(decl.getAnnotations()),
1851 startByte(decl.getStartByte()), endByte(decl.getEndByte()),
1852 node(nullptr), sourceInfo(nullptr), fieldScope(&fieldScope) {
1853 KJ_REQUIRE(decl.which() == Declaration::FIELD);
1854 auto fieldDecl = decl.getField();
1855 fieldType = fieldDecl.getType();
1856 if (fieldDecl.getDefaultValue().isValue()) {
1857 hasDefaultValue = true;
1858 fieldDefaultValue = fieldDecl.getDefaultValue().getValue();
1859 }
1860 if (decl.hasDocComment()) {
1861 docComment = decl.getDocComment();
1862 }
1863 }
1864 inline MemberInfo(MemberInfo& parent, uint codeOrder,
1865 const Declaration::Param::Reader& decl,
1866 StructLayout::StructOrGroup& fieldScope,
1867 bool isInUnion)
1868 : parent(&parent), codeOrder(codeOrder), isInUnion(isInUnion),
1869 name(decl.getName().getValue()), declKind(Declaration::FIELD), isParam(true),
1870 declAnnotations(decl.getAnnotations()),
1871 startByte(decl.getStartByte()), endByte(decl.getEndByte()),
1872 node(nullptr), sourceInfo(nullptr), fieldScope(&fieldScope) {
1873 fieldType = decl.getType();
1874 if (decl.getDefaultValue().isValue()) {
1875 hasDefaultValue = true;
1876 fieldDefaultValue = decl.getDefaultValue().getValue();
1877 }
1878 }
1879 inline MemberInfo(MemberInfo& parent, uint codeOrder,
1880 const Declaration::Reader& decl,
1881 NodeSourceInfoBuilderPair builderPair,
1882 bool isInUnion)
1883 : parent(&parent), codeOrder(codeOrder), isInUnion(isInUnion),
1884 name(decl.getName().getValue()), declId(decl.getId()), declKind(decl.which()),
1885 declAnnotations(decl.getAnnotations()),
1886 startByte(decl.getStartByte()), endByte(decl.getEndByte()),
1887 node(builderPair.node), sourceInfo(builderPair.sourceInfo), unionScope(nullptr) {
1888 KJ_REQUIRE(decl.which() != Declaration::FIELD);
1889 if (decl.hasDocComment()) {
1890 docComment = decl.getDocComment();
1891 }
1892 }
1893
1894 schema::Field::Builder getSchema() {
1895 KJ_IF_MAYBE(result, schema) {
1896 return *result;
1897 } else {
1898 index = parent->childInitializedCount;
1899 auto builderPair = parent->addMemberSchema();
1900 auto builder = builderPair.field;
1901 if (isInUnion) {
1902 builder.setDiscriminantValue(parent->unionDiscriminantCount++);
1903 }
1904 builder.setName(name);
1905 builder.setCodeOrder(codeOrder);
1906
1907 KJ_IF_MAYBE(dc, docComment) {
1908 builderPair.sourceInfo.setDocComment(*dc);
1909 }
1910
1911 schema = builder;
1912 return builder;
1913 }
1914 }
1915
1916 FieldSourceInfoBuilderPair addMemberSchema() {
1917 // Get the schema builder for the child member at the given index. This lazily/dynamically
1918 // builds the builder tree.
1919
1920 KJ_REQUIRE(childInitializedCount < childCount);
1921
1922 auto structNode = node.getStruct();
1923 if (!structNode.hasFields()) {
1924 if (parent != nullptr) {
1925 getSchema(); // Make sure field exists in parent once the first child is added.
1926 }
1927 FieldSourceInfoBuilderPair result {
1928 structNode.initFields(childCount)[childInitializedCount],
1929 sourceInfo.initMembers(childCount)[childInitializedCount]
1930 };
1931 ++childInitializedCount;
1932 return result;
1933 } else {
1934 FieldSourceInfoBuilderPair result {
1935 structNode.getFields()[childInitializedCount],
1936 sourceInfo.getMembers()[childInitializedCount]
1937 };
1938 ++childInitializedCount;
1939 return result;
1940 }
1941 }
1942
1943 void finishGroup() {
1944 if (unionScope != nullptr) {
1945 unionScope->addDiscriminant(); // if it hasn't happened already
1946 auto structNode = node.getStruct();
1947 structNode.setDiscriminantCount(unionDiscriminantCount);
1948 structNode.setDiscriminantOffset(KJ_ASSERT_NONNULL(unionScope->discriminantOffset));
1949 }
1950
1951 if (parent != nullptr) {
1952 uint64_t groupId = generateGroupId(parent->node.getId(), index);
1953 node.setId(groupId);
1954 node.setScopeId(parent->node.getId());
1955 getSchema().initGroup().setTypeId(groupId);
1956
1957 sourceInfo.setId(groupId);
1958 KJ_IF_MAYBE(dc, docComment) {
1959 sourceInfo.setDocComment(*dc);
1960 }
1961 }
1962 }
1963 };
1964
1965 std::multimap<uint, MemberInfo*> membersByOrdinal;
1966 // Every member that has an explicit ordinal goes into this map. We then iterate over the map
1967 // to assign field offsets (or discriminant offsets for unions).
1968
1969 kj::Vector<MemberInfo*> allMembers;
1970 // All members, including ones that don't have ordinals.
1971
1972 void traverseUnion(const Declaration::Reader& decl,
1973 List<Declaration>::Reader members, MemberInfo& parent,
1974 StructLayout::Union& layout, uint& codeOrder) {
1975 if (members.size() < 2) {
1976 errorReporter.addErrorOn(decl, "Union must have at least two members.");
1977 }
1978
1979 for (auto member: members) {
1980 kj::Maybe<uint> ordinal;
1981 MemberInfo* memberInfo = nullptr;
1982
1983 switch (member.which()) {
1984 case Declaration::FIELD: {
1985 parent.childCount++;
1986 // For layout purposes, pretend this field is enclosed in a one-member group.
1987 StructLayout::Group& singletonGroup =
1988 arena.allocate<StructLayout::Group>(layout);
1989 memberInfo = &arena.allocate<MemberInfo>(parent, codeOrder++, member, singletonGroup,
1990 true);
1991 allMembers.add(memberInfo);
1992 ordinal = member.getId().getOrdinal().getValue();
1993 break;
1994 }
1995
1996 case Declaration::UNION:
1997 if (member.getName().getValue() == "") {
1998 errorReporter.addErrorOn(member, "Unions cannot contain unnamed unions.");
1999 } else {
2000 parent.childCount++;
2001
2002 // For layout purposes, pretend this union is enclosed in a one-member group.
2003 StructLayout::Group& singletonGroup =
2004 arena.allocate<StructLayout::Group>(layout);
2005 StructLayout::Union& unionLayout = arena.allocate<StructLayout::Union>(singletonGroup);
2006
2007 memberInfo = &arena.allocate<MemberInfo>(
2008 parent, codeOrder++, member,
2009 newGroupNode(parent.node, member.getName().getValue()),
2010 true);
2011 allMembers.add(memberInfo);
2012 memberInfo->unionScope = &unionLayout;
2013 uint subCodeOrder = 0;
2014 traverseUnion(member, member.getNestedDecls(), *memberInfo, unionLayout, subCodeOrder);
2015 if (member.getId().isOrdinal()) {
2016 ordinal = member.getId().getOrdinal().getValue();
2017 }
2018 }
2019 break;
2020
2021 case Declaration::GROUP: {
2022 parent.childCount++;
2023 StructLayout::Group& group = arena.allocate<StructLayout::Group>(layout);
2024 memberInfo = &arena.allocate<MemberInfo>(
2025 parent, codeOrder++, member,
2026 newGroupNode(parent.node, member.getName().getValue()),
2027 true);
2028 allMembers.add(memberInfo);
2029 traverseGroup(member.getNestedDecls(), *memberInfo, group);
2030 break;
2031 }
2032
2033 default:
2034 // Ignore others.
2035 break;
2036 }
2037
2038 KJ_IF_MAYBE(o, ordinal) {
2039 membersByOrdinal.insert(std::make_pair(*o, memberInfo));
2040 }
2041 }
2042 }
2043
2044 void traverseGroup(List<Declaration>::Reader members, MemberInfo& parent,
2045 StructLayout::StructOrGroup& layout) {
2046 if (members.size() < 1) {
2047 errorReporter.addError(parent.startByte, parent.endByte,
2048 "Group must have at least one member.");
2049 }
2050
2051 traverseTopOrGroup(members, parent, layout);
2052 }
2053
2054 void traverseTopOrGroup(List<Declaration>::Reader members, MemberInfo& parent,
2055 StructLayout::StructOrGroup& layout) {
2056 uint codeOrder = 0;
2057
2058 for (auto member: members) {
2059 kj::Maybe<uint> ordinal;
2060 MemberInfo* memberInfo = nullptr;
2061
2062 switch (member.which()) {
2063 case Declaration::FIELD: {
2064 parent.childCount++;
2065 memberInfo = &arena.allocate<MemberInfo>(
2066 parent, codeOrder++, member, layout, false);
2067 allMembers.add(memberInfo);
2068 ordinal = member.getId().getOrdinal().getValue();
2069 break;
2070 }
2071
2072 case Declaration::UNION: {
2073 StructLayout::Union& unionLayout = arena.allocate<StructLayout::Union>(layout);
2074
2075 uint independentSubCodeOrder = 0;
2076 uint* subCodeOrder = &independentSubCodeOrder;
2077 if (member.getName().getValue() == "") {
2078 memberInfo = &parent;
2079 subCodeOrder = &codeOrder;
2080 } else {
2081 parent.childCount++;
2082 memberInfo = &arena.allocate<MemberInfo>(
2083 parent, codeOrder++, member,
2084 newGroupNode(parent.node, member.getName().getValue()),
2085 false);
2086 allMembers.add(memberInfo);
2087 }
2088 memberInfo->unionScope = &unionLayout;
2089 traverseUnion(member, member.getNestedDecls(), *memberInfo, unionLayout, *subCodeOrder);
2090 if (member.getId().isOrdinal()) {
2091 ordinal = member.getId().getOrdinal().getValue();
2092 }
2093 break;
2094 }
2095
2096 case Declaration::GROUP:
2097 parent.childCount++;
2098 memberInfo = &arena.allocate<MemberInfo>(
2099 parent, codeOrder++, member,
2100 newGroupNode(parent.node, member.getName().getValue()),
2101 false);
2102 allMembers.add(memberInfo);
2103
2104 // Members of the group are laid out just like they were members of the parent, so we
2105 // just pass along the parent layout.
2106 traverseGroup(member.getNestedDecls(), *memberInfo, layout);
2107
2108 // No ordinal for groups.
2109 break;
2110
2111 default:
2112 // Ignore others.
2113 break;
2114 }
2115
2116 KJ_IF_MAYBE(o, ordinal) {
2117 membersByOrdinal.insert(std::make_pair(*o, memberInfo));
2118 }
2119 }
2120 }
2121
2122 void traverseParams(List<Declaration::Param>::Reader params, MemberInfo& parent,
2123 StructLayout::StructOrGroup& layout) {
2124 for (uint i: kj::indices(params)) {
2125 auto param = params[i];
2126 parent.childCount++;
2127 MemberInfo* memberInfo = &arena.allocate<MemberInfo>(parent, i, param, layout, false);
2128 allMembers.add(memberInfo);
2129 membersByOrdinal.insert(std::make_pair(i, memberInfo));
2130 }
2131 }
2132
2133 NodeSourceInfoBuilderPair newGroupNode(schema::Node::Reader parent, kj::StringPtr name) {
2134 AuxNode aux {
2135 translator.orphanage.newOrphan<schema::Node>(),
2136 translator.orphanage.newOrphan<schema::Node::SourceInfo>()
2137 };
2138 auto node = aux.node.get();
2139 auto sourceInfo = aux.sourceInfo.get();
2140
2141 // We'll set the ID and scope ID later.
2142 node.setDisplayName(kj::str(parent.getDisplayName(), '.', name));
2143 node.setDisplayNamePrefixLength(node.getDisplayName().size() - name.size());
2144 node.setIsGeneric(parent.getIsGeneric());
2145 node.initStruct().setIsGroup(true);
2146
2147 // The remaining contents of node.struct will be filled in later.
2148
2149 translator.groups.add(kj::mv(aux));
2150 return { node, sourceInfo };
2151 }
2152
2153 void translateInternal(MemberInfo& root, schema::Node::Builder builder) {
2154 auto structBuilder = builder.initStruct();
2155
2156 // Go through each member in ordinal order, building each member schema.
2157 DuplicateOrdinalDetector dupDetector(errorReporter);
2158 for (auto& entry: membersByOrdinal) {
2159 MemberInfo& member = *entry.second;
2160
2161 // Make sure the exceptions added relating to
2162 // https://github.com/sandstorm-io/capnproto/issues/344 identify the affected field.
2163 KJ_CONTEXT(member.name);
2164
2165 if (member.declId.isOrdinal()) {
2166 dupDetector.check(member.declId.getOrdinal());
2167 }
2168
2169 schema::Field::Builder fieldBuilder = member.getSchema();
2170 fieldBuilder.getOrdinal().setExplicit(entry.first);
2171
2172 switch (member.declKind) {
2173 case Declaration::FIELD: {
2174 auto slot = fieldBuilder.initSlot();
2175 auto typeBuilder = slot.initType();
2176 if (translator.compileType(member.fieldType, typeBuilder, implicitMethodParams)) {
2177 if (member.hasDefaultValue) {
2178 if (member.isParam &&
2179 member.fieldDefaultValue.isRelativeName() &&
2180 member.fieldDefaultValue.getRelativeName().getValue() == "null") {
2181 // special case: parameter set null
2182 switch (typeBuilder.which()) {
2183 case schema::Type::TEXT:
2184 case schema::Type::DATA:
2185 case schema::Type::LIST:
2186 case schema::Type::STRUCT:
2187 case schema::Type::INTERFACE:
2188 case schema::Type::ANY_POINTER:
2189 break;
2190 default:
2191 errorReporter.addErrorOn(member.fieldDefaultValue.getRelativeName(),
2192 "Only pointer parameters can declare their default as 'null'.");
2193 break;
2194 }
2195 translator.compileDefaultDefaultValue(typeBuilder, slot.initDefaultValue());
2196 } else {
2197 translator.compileBootstrapValue(member.fieldDefaultValue,
2198 typeBuilder, slot.initDefaultValue());
2199 }
2200 slot.setHadExplicitDefault(true);
2201 } else {
2202 translator.compileDefaultDefaultValue(typeBuilder, slot.initDefaultValue());
2203 }
2204 } else {
2205 translator.compileDefaultDefaultValue(typeBuilder, slot.initDefaultValue());
2206 }
2207
2208 int lgSize = -1;
2209 switch (typeBuilder.which()) {
2210 case schema::Type::VOID: lgSize = -1; break;
2211 case schema::Type::BOOL: lgSize = 0; break;
2212 case schema::Type::INT8: lgSize = 3; break;
2213 case schema::Type::INT16: lgSize = 4; break;
2214 case schema::Type::INT32: lgSize = 5; break;
2215 case schema::Type::INT64: lgSize = 6; break;
2216 case schema::Type::UINT8: lgSize = 3; break;
2217 case schema::Type::UINT16: lgSize = 4; break;
2218 case schema::Type::UINT32: lgSize = 5; break;
2219 case schema::Type::UINT64: lgSize = 6; break;
2220 case schema::Type::FLOAT32: lgSize = 5; break;
2221 case schema::Type::FLOAT64: lgSize = 6; break;
2222
2223 case schema::Type::TEXT: lgSize = -2; break;
2224 case schema::Type::DATA: lgSize = -2; break;
2225 case schema::Type::LIST: lgSize = -2; break;
2226 case schema::Type::ENUM: lgSize = 4; break;
2227 case schema::Type::STRUCT: lgSize = -2; break;
2228 case schema::Type::INTERFACE: lgSize = -2; break;
2229 case schema::Type::ANY_POINTER: lgSize = -2; break;
2230 }
2231
2232 if (lgSize == -2) {
2233 // pointer
2234 slot.setOffset(member.fieldScope->addPointer());
2235 } else if (lgSize == -1) {
2236 // void
2237 member.fieldScope->addVoid();
2238 slot.setOffset(0);
2239 } else {
2240 slot.setOffset(member.fieldScope->addData(lgSize));
2241 }
2242 break;
2243 }
2244
2245 case Declaration::UNION:
2246 if (!member.unionScope->addDiscriminant()) {
2247 errorReporter.addErrorOn(member.declId.getOrdinal(),
2248 "Union ordinal, if specified, must be greater than no more than one of its "
2249 "member ordinals (i.e. there can only be one field retroactively unionized).");
2250 }
2251 break;
2252
2253 case Declaration::GROUP:
2254 KJ_FAIL_ASSERT("Groups don't have ordinals.");
2255 break;
2256
2257 default:
2258 KJ_FAIL_ASSERT("Unexpected member type.");
2259 break;
2260 }
2261 }
2262
2263 // OK, we should have built all the members. Now go through and make sure the discriminant
2264 // offsets have been copied over to the schemas and annotations have been applied.
2265 root.finishGroup();
2266 for (auto member: allMembers) {
2267 kj::StringPtr targetsFlagName;
2268 if (member->isParam) {
2269 targetsFlagName = "targetsParam";
2270 } else {
2271 switch (member->declKind) {
2272 case Declaration::FIELD:
2273 targetsFlagName = "targetsField";
2274 break;
2275
2276 case Declaration::UNION:
2277 member->finishGroup();
2278 targetsFlagName = "targetsUnion";
2279 break;
2280
2281 case Declaration::GROUP:
2282 member->finishGroup();
2283 targetsFlagName = "targetsGroup";
2284 break;
2285
2286 default:
2287 KJ_FAIL_ASSERT("Unexpected member type.");
2288 break;
2289 }
2290 }
2291
2292 member->getSchema().adoptAnnotations(translator.compileAnnotationApplications(
2293 member->declAnnotations, targetsFlagName));
2294 }
2295
2296 // And fill in the sizes.
2297 structBuilder.setDataWordCount(layout.getTop().dataWordCount);
2298 structBuilder.setPointerCount(layout.getTop().pointerCount);
2299 structBuilder.setPreferredListEncoding(schema::ElementSize::INLINE_COMPOSITE);
2300
2301 for (auto& group: translator.groups) {
2302 auto groupBuilder = group.node.get().getStruct();
2303 groupBuilder.setDataWordCount(structBuilder.getDataWordCount());
2304 groupBuilder.setPointerCount(structBuilder.getPointerCount());
2305 groupBuilder.setPreferredListEncoding(structBuilder.getPreferredListEncoding());
2306 }
2307 }
2308};
2309
2310void NodeTranslator::compileStruct(Void decl, List<Declaration>::Reader members,
2311 schema::Node::Builder builder) {
2312 StructTranslator(*this, noImplicitParams()).translate(decl, members, builder, sourceInfo.get());
2313}
2314
2315// -------------------------------------------------------------------
2316
2317static kj::String expressionString(Expression::Reader name);
2318
2319void NodeTranslator::compileInterface(Declaration::Interface::Reader decl,
2320 List<Declaration>::Reader members,
2321 schema::Node::Builder builder) {
2322 auto interfaceBuilder = builder.initInterface();
2323
2324 auto superclassesDecl = decl.getSuperclasses();
2325 auto superclassesBuilder = interfaceBuilder.initSuperclasses(superclassesDecl.size());
2326 for (uint i: kj::indices(superclassesDecl)) {
2327 auto superclass = superclassesDecl[i];
2328
2329 KJ_IF_MAYBE(decl, compileDeclExpression(superclass, noImplicitParams())) {
2330 KJ_IF_MAYBE(kind, decl->getKind()) {
2331 if (*kind == Declaration::INTERFACE) {
2332 auto s = superclassesBuilder[i];
2333 s.setId(decl->getIdAndFillBrand([&]() { return s.initBrand(); }));
2334 } else {
2335 decl->addError(errorReporter, kj::str(
2336 "'", decl->toString(), "' is not an interface."));
2337 }
2338 } else {
2339 // A variable?
2340 decl->addError(errorReporter, kj::str(
2341 "'", decl->toString(), "' is an unbound generic parameter. Currently we don't support "
2342 "extending these."));
2343 }
2344 }
2345 }
2346
2347 // maps ordinal -> (code order, declaration)
2348 std::multimap<uint, std::pair<uint, Declaration::Reader>> methods;
2349
2350 uint codeOrder = 0;
2351 for (auto member: members) {
2352 if (member.isMethod()) {
2353 methods.insert(
2354 std::make_pair(member.getId().getOrdinal().getValue(),
2355 std::make_pair(codeOrder++, member)));
2356 }
2357 }
2358
2359 auto list = interfaceBuilder.initMethods(methods.size());
2360 auto sourceInfoList = sourceInfo.get().initMembers(methods.size());
2361 uint i = 0;
2362 DuplicateOrdinalDetector dupDetector(errorReporter);
2363
2364 for (auto& entry: methods) {
2365 uint codeOrder = entry.second.first;
2366 Declaration::Reader methodDecl = entry.second.second;
2367 auto methodReader = methodDecl.getMethod();
2368
2369 auto ordinalDecl = methodDecl.getId().getOrdinal();
2370 dupDetector.check(ordinalDecl);
2371 uint16_t ordinal = ordinalDecl.getValue();
2372
2373 if (methodDecl.hasDocComment()) {
2374 sourceInfoList[i].setDocComment(methodDecl.getDocComment());
2375 }
2376
2377 auto methodBuilder = list[i++];
2378 methodBuilder.setName(methodDecl.getName().getValue());
2379 methodBuilder.setCodeOrder(codeOrder);
2380
2381 auto implicits = methodDecl.getParameters();
2382 auto implicitsBuilder = methodBuilder.initImplicitParameters(implicits.size());
2383 for (auto i: kj::indices(implicits)) {
2384 implicitsBuilder[i].setName(implicits[i].getName());
2385 }
2386
2387 methodBuilder.setParamStructType(compileParamList(
2388 methodDecl.getName().getValue(), ordinal, false,
2389 methodReader.getParams(), implicits,
2390 [&]() { return methodBuilder.initParamBrand(); }));
2391
2392 auto results = methodReader.getResults();
2393 Declaration::ParamList::Reader resultList;
2394 if (results.isExplicit()) {
2395 resultList = results.getExplicit();
2396 } else {
2397 // We just stick with `resultList` uninitialized, which is equivalent to the default
2398 // instance. This works because `namedList` is the default kind of ParamList, and it will
2399 // default to an empty list.
2400 }
2401 methodBuilder.setResultStructType(compileParamList(
2402 methodDecl.getName().getValue(), ordinal, true,
2403 resultList, implicits,
2404 [&]() { return methodBuilder.initResultBrand(); }));
2405
2406 methodBuilder.adoptAnnotations(compileAnnotationApplications(
2407 methodDecl.getAnnotations(), "targetsMethod"));
2408 }
2409}
2410
2411template <typename InitBrandFunc>
2412uint64_t NodeTranslator::compileParamList(
2413 kj::StringPtr methodName, uint16_t ordinal, bool isResults,
2414 Declaration::ParamList::Reader paramList,
2415 typename List<Declaration::BrandParameter>::Reader implicitParams,
2416 InitBrandFunc&& initBrand) {
2417 switch (paramList.which()) {
2418 case Declaration::ParamList::NAMED_LIST: {
2419 auto newStruct = orphanage.newOrphan<schema::Node>();
2420 auto newSourceInfo = orphanage.newOrphan<schema::Node::SourceInfo>();
2421 auto builder = newStruct.get();
2422 auto parent = wipNode.getReader();
2423
2424 kj::String typeName = kj::str(methodName, isResults ? "$Results" : "$Params");
2425
2426 builder.setId(generateMethodParamsId(parent.getId(), ordinal, isResults));
2427 builder.setDisplayName(kj::str(parent.getDisplayName(), '.', typeName));
2428 builder.setDisplayNamePrefixLength(builder.getDisplayName().size() - typeName.size());
2429 builder.setIsGeneric(parent.getIsGeneric() || implicitParams.size() > 0);
2430 builder.setScopeId(0); // detached struct type
2431
2432 builder.initStruct();
2433
2434 // Note that the struct we create here has a brand parameter list mirrioring the method's
2435 // implicit parameter list. Of course, fields inside the struct using the method's implicit
2436 // params as types actually need to refer to them as regular params, so we create an
2437 // ImplicitParams with a scopeId here.
2438 StructTranslator(*this, ImplicitParams { builder.getId(), implicitParams })
2439 .translate(paramList.getNamedList(), builder, newSourceInfo.get());
2440 uint64_t id = builder.getId();
2441 paramStructs.add(AuxNode { kj::mv(newStruct), kj::mv(newSourceInfo) });
2442
2443 auto brand = localBrand->push(builder.getId(), implicitParams.size());
2444
2445 if (implicitParams.size() > 0) {
2446 auto implicitDecls = kj::heapArrayBuilder<BrandedDecl>(implicitParams.size());
2447 auto implicitBuilder = builder.initParameters(implicitParams.size());
2448
2449 for (auto i: kj::indices(implicitParams)) {
2450 auto param = implicitParams[i];
2451 implicitDecls.add(BrandedDecl::implicitMethodParam(i));
2452 implicitBuilder[i].setName(param.getName());
2453 }
2454
2455 brand->setParams(implicitDecls.finish(), Declaration::STRUCT, Expression::Reader());
2456 }
2457
2458 brand->compile(initBrand);
2459 return id;
2460 }
2461 case Declaration::ParamList::TYPE:
2462 KJ_IF_MAYBE(target, compileDeclExpression(
2463 paramList.getType(), ImplicitParams { 0, implicitParams })) {
2464 KJ_IF_MAYBE(kind, target->getKind()) {
2465 if (*kind == Declaration::STRUCT) {
2466 return target->getIdAndFillBrand(kj::fwd<InitBrandFunc>(initBrand));
2467 } else {
2468 errorReporter.addErrorOn(
2469 paramList.getType(),
2470 kj::str("'", expressionString(paramList.getType()), "' is not a struct type."));
2471 }
2472 } else {
2473 // A variable?
2474 target->addError(errorReporter,
2475 "Cannot use generic parameter as whole input or output of a method. Instead, "
2476 "use a parameter/result list containing a field with this type.");
2477 return 0;
2478 }
2479 }
2480 return 0;
2481 }
2482 KJ_UNREACHABLE;
2483}
2484
2485// -------------------------------------------------------------------
2486
2487static const char HEXDIGITS[] = "0123456789abcdef";
2488
2489static kj::StringTree stringLiteral(kj::StringPtr chars) {
2490 return kj::strTree('"', kj::encodeCEscape(chars), '"');
2491}
2492
2493static kj::StringTree binaryLiteral(Data::Reader data) {
2494 kj::Vector<char> escaped(data.size() * 3);
2495
2496 for (byte b: data) {
2497 escaped.add(HEXDIGITS[b % 16]);
2498 escaped.add(HEXDIGITS[b / 16]);
2499 escaped.add(' ');
2500 }
2501
2502 escaped.removeLast();
2503 return kj::strTree("0x\"", escaped, '"');
2504}
2505
2506static kj::StringTree expressionStringTree(Expression::Reader exp);
2507
2508static kj::StringTree tupleLiteral(List<Expression::Param>::Reader params) {
2509 auto parts = kj::heapArrayBuilder<kj::StringTree>(params.size());
2510 for (auto param: params) {
2511 auto part = expressionStringTree(param.getValue());
2512 if (param.isNamed()) {
2513 part = kj::strTree(param.getNamed().getValue(), " = ", kj::mv(part));
2514 }
2515 parts.add(kj::mv(part));
2516 }
2517 return kj::strTree("( ", kj::StringTree(parts.finish(), ", "), " )");
2518}
2519
2520static kj::StringTree expressionStringTree(Expression::Reader exp) {
2521 switch (exp.which()) {
2522 case Expression::UNKNOWN:
2523 return kj::strTree("<parse error>");
2524 case Expression::POSITIVE_INT:
2525 return kj::strTree(exp.getPositiveInt());
2526 case Expression::NEGATIVE_INT:
2527 return kj::strTree('-', exp.getNegativeInt());
2528 case Expression::FLOAT:
2529 return kj::strTree(exp.getFloat());
2530 case Expression::STRING:
2531 return stringLiteral(exp.getString());
2532 case Expression::BINARY:
2533 return binaryLiteral(exp.getBinary());
2534 case Expression::RELATIVE_NAME:
2535 return kj::strTree(exp.getRelativeName().getValue());
2536 case Expression::ABSOLUTE_NAME:
2537 return kj::strTree('.', exp.getAbsoluteName().getValue());
2538 case Expression::IMPORT:
2539 return kj::strTree("import ", stringLiteral(exp.getImport().getValue()));
2540 case Expression::EMBED:
2541 return kj::strTree("embed ", stringLiteral(exp.getEmbed().getValue()));
2542
2543 case Expression::LIST: {
2544 auto list = exp.getList();
2545 auto parts = kj::heapArrayBuilder<kj::StringTree>(list.size());
2546 for (auto element: list) {
2547 parts.add(expressionStringTree(element));
2548 }
2549 return kj::strTree("[ ", kj::StringTree(parts.finish(), ", "), " ]");
2550 }
2551
2552 case Expression::TUPLE:
2553 return tupleLiteral(exp.getTuple());
2554
2555 case Expression::APPLICATION: {
2556 auto app = exp.getApplication();
2557 return kj::strTree(expressionStringTree(app.getFunction()),
2558 '(', tupleLiteral(app.getParams()), ')');
2559 }
2560
2561 case Expression::MEMBER: {
2562 auto member = exp.getMember();
2563 return kj::strTree(expressionStringTree(member.getParent()), '.',
2564 member.getName().getValue());
2565 }
2566 }
2567
2568 KJ_UNREACHABLE;
2569}
2570
2571static kj::String expressionString(Expression::Reader name) {
2572 return expressionStringTree(name).flatten();
2573}
2574
2575// -------------------------------------------------------------------
2576
2577kj::Maybe<NodeTranslator::BrandedDecl>
2578NodeTranslator::compileDeclExpression(
2579 Expression::Reader source, ImplicitParams implicitMethodParams) {
2580 return localBrand->compileDeclExpression(source, resolver, implicitMethodParams);
2581}
2582
2583/* static */ kj::Maybe<NodeTranslator::Resolver::ResolveResult> NodeTranslator::compileDecl(
2584 uint64_t scopeId, uint scopeParameterCount, Resolver& resolver, ErrorReporter& errorReporter,
2585 Expression::Reader expression, schema::Brand::Builder brandBuilder) {
2586 auto scope = kj::refcounted<BrandScope>(errorReporter, scopeId, scopeParameterCount, resolver);
2587 KJ_IF_MAYBE(decl, scope->compileDeclExpression(expression, resolver, noImplicitParams())) {
2588 return decl->asResolveResult(scope->getScopeId(), brandBuilder);
2589 } else {
2590 return nullptr;
2591 }
2592}
2593
2594bool NodeTranslator::compileType(Expression::Reader source, schema::Type::Builder target,
2595 ImplicitParams implicitMethodParams) {
2596 KJ_IF_MAYBE(decl, compileDeclExpression(source, implicitMethodParams)) {
2597 return decl->compileAsType(errorReporter, target);
2598 } else {
2599 return false;
2600 }
2601}
2602
2603// -------------------------------------------------------------------
2604
2605void NodeTranslator::compileDefaultDefaultValue(
2606 schema::Type::Reader type, schema::Value::Builder target) {
2607 switch (type.which()) {
2608 case schema::Type::VOID: target.setVoid(); break;
2609 case schema::Type::BOOL: target.setBool(false); break;
2610 case schema::Type::INT8: target.setInt8(0); break;
2611 case schema::Type::INT16: target.setInt16(0); break;
2612 case schema::Type::INT32: target.setInt32(0); break;
2613 case schema::Type::INT64: target.setInt64(0); break;
2614 case schema::Type::UINT8: target.setUint8(0); break;
2615 case schema::Type::UINT16: target.setUint16(0); break;
2616 case schema::Type::UINT32: target.setUint32(0); break;
2617 case schema::Type::UINT64: target.setUint64(0); break;
2618 case schema::Type::FLOAT32: target.setFloat32(0); break;
2619 case schema::Type::FLOAT64: target.setFloat64(0); break;
2620 case schema::Type::ENUM: target.setEnum(0); break;
2621 case schema::Type::INTERFACE: target.setInterface(); break;
2622
2623 // Bit of a hack: For Text/Data, we adopt a null orphan, which sets the field to null.
2624 // TODO(cleanup): Create a cleaner way to do this.
2625 case schema::Type::TEXT: target.adoptText(Orphan<Text>()); break;
2626 case schema::Type::DATA: target.adoptData(Orphan<Data>()); break;
2627 case schema::Type::STRUCT: target.initStruct(); break;
2628 case schema::Type::LIST: target.initList(); break;
2629 case schema::Type::ANY_POINTER: target.initAnyPointer(); break;
2630 }
2631}
2632
2633void NodeTranslator::compileBootstrapValue(
2634 Expression::Reader source, schema::Type::Reader type, schema::Value::Builder target,
2635 Schema typeScope) {
2636 // Start by filling in a default default value so that if for whatever reason we don't end up
2637 // initializing the value, this won't cause schema validation to fail.
2638 compileDefaultDefaultValue(type, target);
2639
2640 switch (type.which()) {
2641 case schema::Type::LIST:
2642 case schema::Type::STRUCT:
2643 case schema::Type::INTERFACE:
2644 case schema::Type::ANY_POINTER:
2645 unfinishedValues.add(UnfinishedValue { source, type, typeScope, target });
2646 break;
2647
2648 default:
2649 // Primitive value.
2650 compileValue(source, type, typeScope, target, true);
2651 break;
2652 }
2653}
2654
2655void NodeTranslator::compileValue(Expression::Reader source, schema::Type::Reader type,
2656 Schema typeScope, schema::Value::Builder target,
2657 bool isBootstrap) {
2658 class ResolverGlue: public ValueTranslator::Resolver {
2659 public:
2660 inline ResolverGlue(NodeTranslator& translator, bool isBootstrap)
2661 : translator(translator), isBootstrap(isBootstrap) {}
2662
2663 kj::Maybe<DynamicValue::Reader> resolveConstant(Expression::Reader name) override {
2664 return translator.readConstant(name, isBootstrap);
2665 }
2666
2667 kj::Maybe<kj::Array<const byte>> readEmbed(LocatedText::Reader filename) override {
2668 return translator.readEmbed(filename);
2669 }
2670
2671 private:
2672 NodeTranslator& translator;
2673 bool isBootstrap;
2674 };
2675
2676 ResolverGlue glue(*this, isBootstrap);
2677 ValueTranslator valueTranslator(glue, errorReporter, orphanage);
2678
2679 KJ_IF_MAYBE(typeSchema, resolver.resolveBootstrapType(type, typeScope)) {
2680 kj::StringPtr fieldName = Schema::from<schema::Type>()
2681 .getUnionFields()[static_cast<uint>(typeSchema->which())].getProto().getName();
2682
2683 KJ_IF_MAYBE(value, valueTranslator.compileValue(source, *typeSchema)) {
2684 if (typeSchema->isEnum()) {
2685 target.setEnum(value->getReader().as<DynamicEnum>().getRaw());
2686 } else {
2687 toDynamic(target).adopt(fieldName, kj::mv(*value));
2688 }
2689 }
2690 }
2691}
2692
2693kj::Maybe<Orphan<DynamicValue>> ValueTranslator::compileValue(Expression::Reader src, Type type) {
2694 Orphan<DynamicValue> result = compileValueInner(src, type);
2695
2696 switch (result.getType()) {
2697 case DynamicValue::UNKNOWN:
2698 // Error already reported.
2699 return nullptr;
2700
2701 case DynamicValue::VOID:
2702 if (type.isVoid()) {
2703 return kj::mv(result);
2704 }
2705 break;
2706
2707 case DynamicValue::BOOL:
2708 if (type.isBool()) {
2709 return kj::mv(result);
2710 }
2711 break;
2712
2713 case DynamicValue::INT: {
2714 int64_t value = result.getReader().as<int64_t>();
2715 if (value < 0) {
2716 int64_t minValue = 1;
2717 switch (type.which()) {
2718 case schema::Type::INT8: minValue = (int8_t)kj::minValue; break;
2719 case schema::Type::INT16: minValue = (int16_t)kj::minValue; break;
2720 case schema::Type::INT32: minValue = (int32_t)kj::minValue; break;
2721 case schema::Type::INT64: minValue = (int64_t)kj::minValue; break;
2722 case schema::Type::UINT8: minValue = (uint8_t)kj::minValue; break;
2723 case schema::Type::UINT16: minValue = (uint16_t)kj::minValue; break;
2724 case schema::Type::UINT32: minValue = (uint32_t)kj::minValue; break;
2725 case schema::Type::UINT64: minValue = (uint64_t)kj::minValue; break;
2726
2727 case schema::Type::FLOAT32:
2728 case schema::Type::FLOAT64:
2729 // Any integer is acceptable.
2730 minValue = (int64_t)kj::minValue;
2731 break;
2732
2733 default: break;
2734 }
2735 if (minValue == 1) break;
2736
2737 if (value < minValue) {
2738 errorReporter.addErrorOn(src, "Integer value out of range.");
2739 result = minValue;
2740 }
2741 return kj::mv(result);
2742 }
2743
2744 } // fallthrough -- value is positive, so we can just go on to the uint case below.
2745
2746 case DynamicValue::UINT: {
2747 uint64_t maxValue = 0;
2748 switch (type.which()) {
2749 case schema::Type::INT8: maxValue = (int8_t)kj::maxValue; break;
2750 case schema::Type::INT16: maxValue = (int16_t)kj::maxValue; break;
2751 case schema::Type::INT32: maxValue = (int32_t)kj::maxValue; break;
2752 case schema::Type::INT64: maxValue = (int64_t)kj::maxValue; break;
2753 case schema::Type::UINT8: maxValue = (uint8_t)kj::maxValue; break;
2754 case schema::Type::UINT16: maxValue = (uint16_t)kj::maxValue; break;
2755 case schema::Type::UINT32: maxValue = (uint32_t)kj::maxValue; break;
2756 case schema::Type::UINT64: maxValue = (uint64_t)kj::maxValue; break;
2757
2758 case schema::Type::FLOAT32:
2759 case schema::Type::FLOAT64:
2760 // Any integer is acceptable.
2761 maxValue = (uint64_t)kj::maxValue;
2762 break;
2763
2764 default: break;
2765 }
2766 if (maxValue == 0) break;
2767
2768 if (result.getReader().as<uint64_t>() > maxValue) {
2769 errorReporter.addErrorOn(src, "Integer value out of range.");
2770 result = maxValue;
2771 }
2772 return kj::mv(result);
2773 }
2774
2775 case DynamicValue::FLOAT:
2776 if (type.isFloat32() || type.isFloat64()) {
2777 return kj::mv(result);
2778 }
2779 break;
2780
2781 case DynamicValue::TEXT:
2782 if (type.isText()) {
2783 return kj::mv(result);
2784 }
2785 break;
2786
2787 case DynamicValue::DATA:
2788 if (type.isData()) {
2789 return kj::mv(result);
2790 }
2791 break;
2792
2793 case DynamicValue::LIST:
2794 if (type.isList()) {
2795 if (result.getReader().as<DynamicList>().getSchema() == type.asList()) {
2796 return kj::mv(result);
2797 }
2798 } else if (type.isAnyPointer()) {
2799 switch (type.whichAnyPointerKind()) {
2800 case schema::Type::AnyPointer::Unconstrained::ANY_KIND:
2801 case schema::Type::AnyPointer::Unconstrained::LIST:
2802 return kj::mv(result);
2803 case schema::Type::AnyPointer::Unconstrained::STRUCT:
2804 case schema::Type::AnyPointer::Unconstrained::CAPABILITY:
2805 break;
2806 }
2807 }
2808 break;
2809
2810 case DynamicValue::ENUM:
2811 if (type.isEnum()) {
2812 if (result.getReader().as<DynamicEnum>().getSchema() == type.asEnum()) {
2813 return kj::mv(result);
2814 }
2815 }
2816 break;
2817
2818 case DynamicValue::STRUCT:
2819 if (type.isStruct()) {
2820 if (result.getReader().as<DynamicStruct>().getSchema() == type.asStruct()) {
2821 return kj::mv(result);
2822 }
2823 } else if (type.isAnyPointer()) {
2824 switch (type.whichAnyPointerKind()) {
2825 case schema::Type::AnyPointer::Unconstrained::ANY_KIND:
2826 case schema::Type::AnyPointer::Unconstrained::STRUCT:
2827 return kj::mv(result);
2828 case schema::Type::AnyPointer::Unconstrained::LIST:
2829 case schema::Type::AnyPointer::Unconstrained::CAPABILITY:
2830 break;
2831 }
2832 }
2833 break;
2834
2835 case DynamicValue::CAPABILITY:
2836 KJ_FAIL_ASSERT("Interfaces can't have literal values.");
2837
2838 case DynamicValue::ANY_POINTER:
2839 KJ_FAIL_ASSERT("AnyPointers can't have literal values.");
2840 }
2841
2842 errorReporter.addErrorOn(src, kj::str("Type mismatch; expected ", makeTypeName(type), "."));
2843 return nullptr;
2844}
2845
2846Orphan<DynamicValue> ValueTranslator::compileValueInner(Expression::Reader src, Type type) {
2847 switch (src.which()) {
2848 case Expression::RELATIVE_NAME: {
2849 auto name = src.getRelativeName();
2850
2851 // The name is just a bare identifier. It may be a literal value or an enumerant.
2852 kj::StringPtr id = name.getValue();
2853
2854 if (type.isEnum()) {
2855 KJ_IF_MAYBE(enumerant, type.asEnum().findEnumerantByName(id)) {
2856 return DynamicEnum(*enumerant);
2857 }
2858 } else {
2859 // Interpret known constant values.
2860 if (id == "void") {
2861 return VOID;
2862 } else if (id == "true") {
2863 return true;
2864 } else if (id == "false") {
2865 return false;
2866 } else if (id == "nan") {
2867 return kj::nan();
2868 } else if (id == "inf") {
2869 return kj::inf();
2870 }
2871 }
2872
2873 // Apparently not a literal. Try resolving it.
2874 KJ_IF_MAYBE(constValue, resolver.resolveConstant(src)) {
2875 return orphanage.newOrphanCopy(*constValue);
2876 } else {
2877 return nullptr;
2878 }
2879 }
2880
2881 case Expression::ABSOLUTE_NAME:
2882 case Expression::IMPORT:
2883 case Expression::APPLICATION:
2884 case Expression::MEMBER:
2885 KJ_IF_MAYBE(constValue, resolver.resolveConstant(src)) {
2886 return orphanage.newOrphanCopy(*constValue);
2887 } else {
2888 return nullptr;
2889 }
2890
2891 case Expression::EMBED:
2892 KJ_IF_MAYBE(data, resolver.readEmbed(src.getEmbed())) {
2893 switch (type.which()) {
2894 case schema::Type::TEXT: {
2895 // Sadly, we need to make a copy to add the NUL terminator.
2896 auto text = orphanage.newOrphan<Text>(data->size());
2897 memcpy(text.get().begin(), data->begin(), data->size());
2898 return kj::mv(text);
2899 }
2900 case schema::Type::DATA:
2901 // TODO(perf): It would arguably be neat to use orphanage.referenceExternalData(),
2902 // since typically the data is mmap()ed and this would avoid forcing a large file
2903 // to become memory-resident. However, we'd have to figure out who should own the
2904 // Array<byte>. Also, we'd have to deal with the possibility of misaligned data --
2905 // though arguably in that case we know it's not mmap()ed so whatever. One more
2906 // thing: it would be neat to be able to reference text blobs this way too, if only
2907 // we could rely on the assumption that as long as the data doesn't end on a page
2908 // boundary, it will be zero-padded, thus giving us our NUL terminator (4095/4096 of
2909 // the time), but this seems to require documenting constraints on the underlying
2910 // file-reading interfaces. Hm.
2911 return orphanage.newOrphanCopy(Data::Reader(*data));
2912 case schema::Type::STRUCT: {
2913 // We will almost certainly
2914 if (data->size() % sizeof(word) != 0) {
2915 errorReporter.addErrorOn(src,
2916 "Embedded file is not a valid Cap'n Proto message.");
2917 return nullptr;
2918 }
2919 kj::Array<word> copy;
2920 kj::ArrayPtr<const word> words;
2921 if (reinterpret_cast<uintptr_t>(data->begin()) % sizeof(void*) == 0) {
2922 // Hooray, data is aligned.
2923 words = kj::ArrayPtr<const word>(
2924 reinterpret_cast<const word*>(data->begin()),
2925 data->size() / sizeof(word));
2926 } else {
2927 // Ugh, data not aligned. Make a copy.
2928 copy = kj::heapArray<word>(data->size() / sizeof(word));
2929 memcpy(copy.begin(), data->begin(), data->size());
2930 words = copy;
2931 }
2932 ReaderOptions options;
2933 options.traversalLimitInWords = kj::maxValue;
2934 options.nestingLimit = kj::maxValue;
2935 FlatArrayMessageReader reader(words, options);
2936 return orphanage.newOrphanCopy(reader.getRoot<DynamicStruct>(type.asStruct()));
2937 }
2938 default:
2939 errorReporter.addErrorOn(src,
2940 "Embeds can only be used when Text, Data, or a struct is expected.");
2941 return nullptr;
2942 }
2943 } else {
2944 return nullptr;
2945 }
2946
2947 case Expression::POSITIVE_INT:
2948 return src.getPositiveInt();
2949
2950 case Expression::NEGATIVE_INT: {
2951 uint64_t nValue = src.getNegativeInt();
2952 if (nValue > ((uint64_t)kj::maxValue >> 1) + 1) {
2953 errorReporter.addErrorOn(src, "Integer is too big to be negative.");
2954 return nullptr;
2955 } else {
2956 return kj::implicitCast<int64_t>(-nValue);
2957 }
2958 }
2959
2960 case Expression::FLOAT:
2961 return src.getFloat();
2962 break;
2963
2964 case Expression::STRING:
2965 if (type.isData()) {
2966 Text::Reader text = src.getString();
2967 return orphanage.newOrphanCopy(Data::Reader(text.asBytes()));
2968 } else {
2969 return orphanage.newOrphanCopy(src.getString());
2970 }
2971 break;
2972
2973 case Expression::BINARY:
2974 if (!type.isData()) {
2975 errorReporter.addErrorOn(src, kj::str("Type mismatch; expected ", makeTypeName(type), "."));
2976 return nullptr;
2977 }
2978 return orphanage.newOrphanCopy(src.getBinary());
2979
2980 case Expression::LIST: {
2981 if (!type.isList()) {
2982 errorReporter.addErrorOn(src, kj::str("Type mismatch; expected ", makeTypeName(type), "."));
2983 return nullptr;
2984 }
2985 auto listSchema = type.asList();
2986 Type elementType = listSchema.getElementType();
2987 auto srcList = src.getList();
2988 Orphan<DynamicList> result = orphanage.newOrphan(listSchema, srcList.size());
2989 auto dstList = result.get();
2990 for (uint i = 0; i < srcList.size(); i++) {
2991 KJ_IF_MAYBE(value, compileValue(srcList[i], elementType)) {
2992 dstList.adopt(i, kj::mv(*value));
2993 }
2994 }
2995 return kj::mv(result);
2996 }
2997
2998 case Expression::TUPLE: {
2999 if (!type.isStruct()) {
3000 errorReporter.addErrorOn(src, kj::str("Type mismatch; expected ", makeTypeName(type), "."));
3001 return nullptr;
3002 }
3003 auto structSchema = type.asStruct();
3004 Orphan<DynamicStruct> result = orphanage.newOrphan(structSchema);
3005 fillStructValue(result.get(), src.getTuple());
3006 return kj::mv(result);
3007 }
3008
3009 case Expression::UNKNOWN:
3010 // Ignore earlier error.
3011 return nullptr;
3012 }
3013
3014 KJ_UNREACHABLE;
3015}
3016
3017void ValueTranslator::fillStructValue(DynamicStruct::Builder builder,
3018 List<Expression::Param>::Reader assignments) {
3019 for (auto assignment: assignments) {
3020 if (assignment.isNamed()) {
3021 auto fieldName = assignment.getNamed();
3022 KJ_IF_MAYBE(field, builder.getSchema().findFieldByName(fieldName.getValue())) {
3023 auto fieldProto = field->getProto();
3024 auto value = assignment.getValue();
3025
3026 switch (fieldProto.which()) {
3027 case schema::Field::SLOT:
3028 KJ_IF_MAYBE(compiledValue, compileValue(value, field->getType())) {
3029 builder.adopt(*field, kj::mv(*compiledValue));
3030 }
3031 break;
3032
3033 case schema::Field::GROUP:
3034 if (value.isTuple()) {
3035 fillStructValue(builder.init(*field).as<DynamicStruct>(), value.getTuple());
3036 } else {
3037 errorReporter.addErrorOn(value, "Type mismatch; expected group.");
3038 }
3039 break;
3040 }
3041 } else {
3042 errorReporter.addErrorOn(fieldName, kj::str(
3043 "Struct has no field named '", fieldName.getValue(), "'."));
3044 }
3045 } else {
3046 errorReporter.addErrorOn(assignment.getValue(), kj::str("Missing field name."));
3047 }
3048 }
3049}
3050
3051kj::String ValueTranslator::makeNodeName(Schema schema) {
3052 schema::Node::Reader proto = schema.getProto();
3053 return kj::str(proto.getDisplayName().slice(proto.getDisplayNamePrefixLength()));
3054}
3055
3056kj::String ValueTranslator::makeTypeName(Type type) {
3057 switch (type.which()) {
3058 case schema::Type::VOID: return kj::str("Void");
3059 case schema::Type::BOOL: return kj::str("Bool");
3060 case schema::Type::INT8: return kj::str("Int8");
3061 case schema::Type::INT16: return kj::str("Int16");
3062 case schema::Type::INT32: return kj::str("Int32");
3063 case schema::Type::INT64: return kj::str("Int64");
3064 case schema::Type::UINT8: return kj::str("UInt8");
3065 case schema::Type::UINT16: return kj::str("UInt16");
3066 case schema::Type::UINT32: return kj::str("UInt32");
3067 case schema::Type::UINT64: return kj::str("UInt64");
3068 case schema::Type::FLOAT32: return kj::str("Float32");
3069 case schema::Type::FLOAT64: return kj::str("Float64");
3070 case schema::Type::TEXT: return kj::str("Text");
3071 case schema::Type::DATA: return kj::str("Data");
3072 case schema::Type::LIST:
3073 return kj::str("List(", makeTypeName(type.asList().getElementType()), ")");
3074 case schema::Type::ENUM: return makeNodeName(type.asEnum());
3075 case schema::Type::STRUCT: return makeNodeName(type.asStruct());
3076 case schema::Type::INTERFACE: return makeNodeName(type.asInterface());
3077 case schema::Type::ANY_POINTER: return kj::str("AnyPointer");
3078 }
3079 KJ_UNREACHABLE;
3080}
3081
3082kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant(
3083 Expression::Reader source, bool isBootstrap) {
3084 // Look up the constant decl.
3085 NodeTranslator::BrandedDecl constDecl = nullptr;
3086 KJ_IF_MAYBE(decl, compileDeclExpression(source, noImplicitParams())) {
3087 constDecl = *decl;
3088 } else {
3089 // Lookup will have reported an error.
3090 return nullptr;
3091 }
3092
3093 // Is it a constant?
3094 if(constDecl.getKind().orDefault(Declaration::FILE) != Declaration::CONST) {
3095 errorReporter.addErrorOn(source,
3096 kj::str("'", expressionString(source), "' does not refer to a constant."));
3097 return nullptr;
3098 }
3099
3100 // Extract the ID and brand.
3101 MallocMessageBuilder builder(256);
3102 auto constBrand = builder.getRoot<schema::Brand>();
3103 uint64_t id = constDecl.getIdAndFillBrand([&]() { return constBrand; });
3104
3105 // Look up the schema -- we'll need this to compile the constant's type.
3106 Schema constSchema;
3107 KJ_IF_MAYBE(s, resolver.resolveBootstrapSchema(id, constBrand)) {
3108 constSchema = *s;
3109 } else {
3110 // The constant's schema is broken for reasons already reported.
3111 return nullptr;
3112 }
3113
3114 // If we're bootstrapping, then we know we're expecting a primitive value, so if the
3115 // constant turns out to be non-primitive, we'll error out anyway. If we're not
3116 // bootstrapping, we may be compiling a non-primitive value and so we need the final
3117 // version of the constant to make sure its value is filled in.
3118 schema::Node::Reader proto = constSchema.getProto();
3119 if (!isBootstrap) {
3120 KJ_IF_MAYBE(finalProto, resolver.resolveFinalSchema(id)) {
3121 proto = *finalProto;
3122 } else {
3123 // The constant's final schema is broken for reasons already reported.
3124 return nullptr;
3125 }
3126 }
3127
3128 auto constReader = proto.getConst();
3129 auto dynamicConst = toDynamic(constReader.getValue());
3130 auto constValue = dynamicConst.get(KJ_ASSERT_NONNULL(dynamicConst.which()));
3131
3132 if (constValue.getType() == DynamicValue::ANY_POINTER) {
3133 // We need to assign an appropriate schema to this pointer.
3134 AnyPointer::Reader objValue = constValue.as<AnyPointer>();
3135
3136 auto constType = constSchema.asConst().getType();
3137 switch (constType.which()) {
3138 case schema::Type::STRUCT:
3139 constValue = objValue.getAs<DynamicStruct>(constType.asStruct());
3140 break;
3141 case schema::Type::LIST:
3142 constValue = objValue.getAs<DynamicList>(constType.asList());
3143 break;
3144 case schema::Type::ANY_POINTER:
3145 // Fine as-is.
3146 break;
3147 default:
3148 KJ_FAIL_ASSERT("Unrecognized AnyPointer-typed member of schema::Value.");
3149 break;
3150 }
3151 }
3152
3153 if (source.isRelativeName()) {
3154 // A fully unqualified identifier looks like it might refer to a constant visible in the
3155 // current scope, but if that's really what the user wanted, we want them to use a
3156 // qualified name to make it more obvious. Report an error.
3157 KJ_IF_MAYBE(scope, resolver.resolveBootstrapSchema(proto.getScopeId(),
3158 schema::Brand::Reader())) {
3159 auto scopeReader = scope->getProto();
3160 kj::StringPtr parent;
3161 if (scopeReader.isFile()) {
3162 parent = "";
3163 } else {
3164 parent = scopeReader.getDisplayName().slice(scopeReader.getDisplayNamePrefixLength());
3165 }
3166 kj::StringPtr id = source.getRelativeName().getValue();
3167
3168 errorReporter.addErrorOn(source, kj::str(
3169 "Constant names must be qualified to avoid confusion. Please replace '",
3170 expressionString(source), "' with '", parent, ".", id,
3171 "', if that's what you intended."));
3172 }
3173 }
3174
3175 return constValue;
3176}
3177
3178kj::Maybe<kj::Array<const byte>> NodeTranslator::readEmbed(LocatedText::Reader filename) {
3179 KJ_IF_MAYBE(data, resolver.readEmbed(filename.getValue())) {
3180 return kj::mv(*data);
3181 } else {
3182 errorReporter.addErrorOn(filename,
3183 kj::str("Couldn't read file for embed: ", filename.getValue()));
3184 return nullptr;
3185 }
3186}
3187
3188Orphan<List<schema::Annotation>> NodeTranslator::compileAnnotationApplications(
3189 List<Declaration::AnnotationApplication>::Reader annotations,
3190 kj::StringPtr targetsFlagName) {
3191 if (annotations.size() == 0 || !compileAnnotations) {
3192 // Return null.
3193 return Orphan<List<schema::Annotation>>();
3194 }
3195
3196 auto result = orphanage.newOrphan<List<schema::Annotation>>(annotations.size());
3197 auto builder = result.get();
3198
3199 for (uint i = 0; i < annotations.size(); i++) {
3200 Declaration::AnnotationApplication::Reader annotation = annotations[i];
3201 schema::Annotation::Builder annotationBuilder = builder[i];
3202
3203 // Set the annotation's value to void in case we fail to produce something better below.
3204 annotationBuilder.initValue().setVoid();
3205
3206 auto name = annotation.getName();
3207 KJ_IF_MAYBE(decl, compileDeclExpression(name, noImplicitParams())) {
3208 KJ_IF_MAYBE(kind, decl->getKind()) {
3209 if (*kind != Declaration::ANNOTATION) {
3210 errorReporter.addErrorOn(name, kj::str(
3211 "'", expressionString(name), "' is not an annotation."));
3212 } else {
3213 annotationBuilder.setId(decl->getIdAndFillBrand(
3214 [&]() { return annotationBuilder.initBrand(); }));
3215 KJ_IF_MAYBE(annotationSchema,
3216 resolver.resolveBootstrapSchema(annotationBuilder.getId(),
3217 annotationBuilder.getBrand())) {
3218 auto node = annotationSchema->getProto().getAnnotation();
3219 if (!toDynamic(node).get(targetsFlagName).as<bool>()) {
3220 errorReporter.addErrorOn(name, kj::str(
3221 "'", expressionString(name), "' cannot be applied to this kind of declaration."));
3222 }
3223
3224 // Interpret the value.
3225 auto value = annotation.getValue();
3226 switch (value.which()) {
3227 case Declaration::AnnotationApplication::Value::NONE:
3228 // No value, i.e. void.
3229 if (node.getType().isVoid()) {
3230 annotationBuilder.getValue().setVoid();
3231 } else {
3232 errorReporter.addErrorOn(name, kj::str(
3233 "'", expressionString(name), "' requires a value."));
3234 compileDefaultDefaultValue(node.getType(), annotationBuilder.getValue());
3235 }
3236 break;
3237
3238 case Declaration::AnnotationApplication::Value::EXPRESSION:
3239 compileBootstrapValue(value.getExpression(), node.getType(),
3240 annotationBuilder.getValue(),
3241 *annotationSchema);
3242 break;
3243 }
3244 }
3245 }
3246 } else if (*kind != Declaration::ANNOTATION) {
3247 errorReporter.addErrorOn(name, kj::str(
3248 "'", expressionString(name), "' is not an annotation."));
3249 }
3250 }
3251 }
3252
3253 return result;
3254}
3255
3256} // namespace compiler
3257} // namespace capnp
3258