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#pragma once
23
24#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
25#pragma GCC system_header
26#endif
27
28#include <capnp/orphan.h>
29#include <capnp/compiler/grammar.capnp.h>
30#include <capnp/schema.capnp.h>
31#include <capnp/dynamic.h>
32#include <kj/vector.h>
33#include <kj/one-of.h>
34#include "error-reporter.h"
35#include <map>
36
37namespace capnp {
38namespace compiler {
39
40class NodeTranslator {
41 // Translates one node in the schema from AST form to final schema form. A "node" is anything
42 // that has a unique ID, such as structs, enums, constants, and annotations, but not fields,
43 // unions, enumerants, or methods (the latter set have 16-bit ordinals but not 64-bit global IDs).
44
45public:
46 class Resolver {
47 // Callback class used to find other nodes relative to this one.
48 //
49 // TODO(cleanup): This has evolved into being a full interface for traversing the node tree.
50 // Maybe we should rename it as such, and move it out of NodeTranslator. See also
51 // TODO(cleanup) on NodeTranslator::BrandedDecl.
52
53 public:
54 struct ResolvedDecl {
55 uint64_t id;
56 uint genericParamCount;
57 uint64_t scopeId;
58 Declaration::Which kind;
59 Resolver* resolver;
60
61 kj::Maybe<schema::Brand::Reader> brand;
62 // If present, then it is necessary to replace the brand scope with the given brand before
63 // using the target type. This happens when the decl resolved to an alias; all other fields
64 // of `ResolvedDecl` refer to the target of the alias, except for `scopeId` which is the
65 // scope that contained the alias.
66 };
67
68 struct ResolvedParameter {
69 uint64_t id; // ID of the node declaring the parameter.
70 uint index; // Index of the parameter.
71 };
72
73 typedef kj::OneOf<ResolvedDecl, ResolvedParameter> ResolveResult;
74
75 virtual kj::Maybe<ResolveResult> resolve(kj::StringPtr name) = 0;
76 // Look up the given name, relative to this node, and return basic information about the
77 // target.
78
79 virtual kj::Maybe<ResolveResult> resolveMember(kj::StringPtr name) = 0;
80 // Look up a member of this node.
81
82 virtual ResolvedDecl resolveBuiltin(Declaration::Which which) = 0;
83 virtual ResolvedDecl resolveId(uint64_t id) = 0;
84
85 virtual kj::Maybe<ResolvedDecl> getParent() = 0;
86 // Returns the parent of this scope, or null if this is the top scope.
87
88 virtual ResolvedDecl getTopScope() = 0;
89 // Get the top-level scope containing this node.
90
91 virtual kj::Maybe<Schema> resolveBootstrapSchema(uint64_t id, schema::Brand::Reader brand) = 0;
92 // Get the schema for the given ID. If a schema is returned, it must be safe to traverse its
93 // dependencies via the Schema API. A schema that is only at the bootstrap stage is
94 // acceptable.
95 //
96 // Throws an exception if the id is not one that was found by calling resolve() or by
97 // traversing other schemas. Returns null if the ID is recognized, but the corresponding
98 // schema node failed to be built for reasons that were already reported.
99
100 virtual kj::Maybe<schema::Node::Reader> resolveFinalSchema(uint64_t id) = 0;
101 // Get the final schema for the given ID. A bootstrap schema is not acceptable. A raw
102 // node reader is returned rather than a Schema object because using a Schema object built
103 // by the final schema loader could trigger lazy initialization of dependencies which could
104 // lead to a cycle and deadlock.
105 //
106 // Throws an exception if the id is not one that was found by calling resolve() or by
107 // traversing other schemas. Returns null if the ID is recognized, but the corresponding
108 // schema node failed to be built for reasons that were already reported.
109
110 virtual kj::Maybe<ResolvedDecl> resolveImport(kj::StringPtr name) = 0;
111 // Get the ID of an imported file given the import path.
112
113 virtual kj::Maybe<kj::Array<const byte>> readEmbed(kj::StringPtr name) = 0;
114 // Read and return the contents of a file for an `embed` expression.
115
116 virtual kj::Maybe<Type> resolveBootstrapType(schema::Type::Reader type, Schema scope) = 0;
117 // Compile a schema::Type into a Type whose dependencies may safely be traversed via the schema
118 // API. These dependencies may have only bootstrap schemas. Returns null if the type could not
119 // be constructed due to already-reported errors.
120 };
121
122 NodeTranslator(Resolver& resolver, ErrorReporter& errorReporter,
123 const Declaration::Reader& decl, Orphan<schema::Node> wipNode,
124 bool compileAnnotations);
125 // Construct a NodeTranslator to translate the given declaration. The wipNode starts out with
126 // `displayName`, `id`, `scopeId`, and `nestedNodes` already initialized. The `NodeTranslator`
127 // fills in the rest.
128
129 ~NodeTranslator() noexcept(false);
130
131 struct NodeSet {
132 schema::Node::Reader node;
133 // The main node.
134
135 kj::Array<schema::Node::Reader> auxNodes;
136 // Auxiliary nodes that were produced when translating this node and should be loaded along
137 // with it. In particular, structs that contain groups (or named unions) spawn extra nodes
138 // representing those, and interfaces spawn struct nodes representing method params/results.
139
140 kj::Array<schema::Node::SourceInfo::Reader> sourceInfo;
141 // The SourceInfo for the node and all aux nodes.
142 };
143
144 NodeSet getBootstrapNode();
145 // Get an incomplete version of the node in which pointer-typed value expressions have not yet
146 // been translated. Instead, for all `schema.Value` objects representing pointer-type values,
147 // the value is set to an appropriate "empty" value. This version of the schema can be used to
148 // bootstrap the dynamic API which can then in turn be used to encode the missing complex values.
149 //
150 // If the final node has already been built, this will actually return the final node (in fact,
151 // it's the same node object).
152
153 NodeSet finish();
154 // Finish translating the node (including filling in all the pieces that are missing from the
155 // bootstrap node) and return it.
156
157 static kj::Maybe<Resolver::ResolveResult> compileDecl(
158 uint64_t scopeId, uint scopeParameterCount, Resolver& resolver, ErrorReporter& errorReporter,
159 Expression::Reader expression, schema::Brand::Builder brandBuilder);
160 // Compile a one-off declaration expression without building a NodeTranslator. Used for
161 // evaluating aliases.
162 //
163 // `brandBuilder` may be used to construct a message which will fill in ResolvedDecl::brand in
164 // the result.
165
166private:
167 class DuplicateNameDetector;
168 class DuplicateOrdinalDetector;
169 class StructLayout;
170 class StructTranslator;
171 class BrandedDecl;
172 class BrandScope;
173
174 Resolver& resolver;
175 ErrorReporter& errorReporter;
176 Orphanage orphanage;
177 bool compileAnnotations;
178 kj::Own<BrandScope> localBrand;
179
180 Orphan<schema::Node> wipNode;
181 // The work-in-progress schema node.
182
183 Orphan<schema::Node::SourceInfo> sourceInfo;
184 // Doc comments and other source info for this node.
185
186 struct AuxNode {
187 Orphan<schema::Node> node;
188 Orphan<schema::Node::SourceInfo> sourceInfo;
189 };
190
191 kj::Vector<AuxNode> groups;
192 // If this is a struct node and it contains groups, these are the nodes for those groups, which
193 // must be loaded together with the top-level node.
194
195 kj::Vector<AuxNode> paramStructs;
196 // If this is an interface, these are the auto-generated structs representing params and results.
197
198 struct UnfinishedValue {
199 Expression::Reader source;
200 schema::Type::Reader type;
201 Schema typeScope;
202 schema::Value::Builder target;
203 };
204 kj::Vector<UnfinishedValue> unfinishedValues;
205 // List of values in `wipNode` which have not yet been interpreted, because they are structs
206 // or lists and as such interpreting them require using the types' schemas (to take advantage
207 // of the dynamic API). Once bootstrap schemas have been built, they can be used to interpret
208 // these values.
209
210 void compileNode(Declaration::Reader decl, schema::Node::Builder builder);
211
212 void compileConst(Declaration::Const::Reader decl, schema::Node::Const::Builder builder);
213 void compileAnnotation(Declaration::Annotation::Reader decl,
214 schema::Node::Annotation::Builder builder);
215
216 void compileEnum(Void decl, List<Declaration>::Reader members,
217 schema::Node::Builder builder);
218 void compileStruct(Void decl, List<Declaration>::Reader members,
219 schema::Node::Builder builder);
220 void compileInterface(Declaration::Interface::Reader decl,
221 List<Declaration>::Reader members,
222 schema::Node::Builder builder);
223 // The `members` arrays contain only members with ordinal numbers, in code order. Other members
224 // are handled elsewhere.
225
226 struct ImplicitParams {
227 // Represents a set of implicit parameters visible in the current context.
228
229 uint64_t scopeId;
230 // If zero, then any reference to an implciit param in this context should be compiled to a
231 // `implicitMethodParam` AnyPointer. If non-zero, it should be compiled to a `parameter`
232 // AnyPointer.
233
234 List<Declaration::BrandParameter>::Reader params;
235 };
236
237 static inline ImplicitParams noImplicitParams() {
238 return { 0, List<Declaration::BrandParameter>::Reader() };
239 }
240
241 template <typename InitBrandFunc>
242 uint64_t compileParamList(kj::StringPtr methodName, uint16_t ordinal, bool isResults,
243 Declaration::ParamList::Reader paramList,
244 typename List<Declaration::BrandParameter>::Reader implicitParams,
245 InitBrandFunc&& initBrand);
246 // Compile a param (or result) list and return the type ID of the struct type.
247
248 kj::Maybe<BrandedDecl> compileDeclExpression(
249 Expression::Reader source, ImplicitParams implicitMethodParams);
250 // Compile an expression which is expected to resolve to a declaration or type expression.
251
252 bool compileType(Expression::Reader source, schema::Type::Builder target,
253 ImplicitParams implicitMethodParams);
254 // Returns false if there was a problem, in which case value expressions of this type should
255 // not be parsed.
256
257 void compileDefaultDefaultValue(schema::Type::Reader type, schema::Value::Builder target);
258 // Initializes `target` to contain the "default default" value for `type`.
259
260 void compileBootstrapValue(
261 Expression::Reader source, schema::Type::Reader type, schema::Value::Builder target,
262 Schema typeScope = Schema());
263 // Calls compileValue() if this value should be interpreted at bootstrap time. Otheriwse,
264 // adds the value to `unfinishedValues` for later evaluation.
265 //
266 // If `type` comes from some other node, `typeScope` is the schema for that node. This is only
267 // really needed for looking up generic parameter bindings, therefore if the type comes from
268 // the node being built, an empty "Schema" (the default) works here because the node being built
269 // is of course being built for all possible bindings and thus none of its generic parameters are
270 // bound.
271
272 void compileValue(Expression::Reader source, schema::Type::Reader type,
273 Schema typeScope, schema::Value::Builder target, bool isBootstrap);
274 // Interprets the value expression and initializes `target` with the result.
275
276 kj::Maybe<DynamicValue::Reader> readConstant(Expression::Reader name, bool isBootstrap);
277 // Get the value of the given constant. May return null if some error occurs, which will already
278 // have been reported.
279
280 kj::Maybe<kj::Array<const byte>> readEmbed(LocatedText::Reader filename);
281 // Read a raw file for embedding.
282
283 Orphan<List<schema::Annotation>> compileAnnotationApplications(
284 List<Declaration::AnnotationApplication>::Reader annotations,
285 kj::StringPtr targetsFlagName);
286};
287
288class ValueTranslator {
289public:
290 class Resolver {
291 public:
292 virtual kj::Maybe<DynamicValue::Reader> resolveConstant(Expression::Reader name) = 0;
293 virtual kj::Maybe<kj::Array<const byte>> readEmbed(LocatedText::Reader filename) = 0;
294 };
295
296 ValueTranslator(Resolver& resolver, ErrorReporter& errorReporter, Orphanage orphanage)
297 : resolver(resolver), errorReporter(errorReporter), orphanage(orphanage) {}
298
299 kj::Maybe<Orphan<DynamicValue>> compileValue(Expression::Reader src, Type type);
300
301 void fillStructValue(DynamicStruct::Builder builder,
302 List<Expression::Param>::Reader assignments);
303 // Interprets the given assignments and uses them to fill in the given struct builder.
304
305private:
306 Resolver& resolver;
307 ErrorReporter& errorReporter;
308 Orphanage orphanage;
309
310 Orphan<DynamicValue> compileValueInner(Expression::Reader src, Type type);
311 // Helper for compileValue().
312
313 kj::String makeNodeName(Schema node);
314 kj::String makeTypeName(Type type);
315
316 kj::Maybe<ListSchema> makeListSchemaOf(schema::Type::Reader elementType);
317};
318
319} // namespace compiler
320} // namespace capnp
321