node-translator.h 13.8 KB
Newer Older
Kenton Varda's avatar
Kenton Varda committed
1 2
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
Kenton Varda's avatar
Kenton Varda committed
3
//
Kenton Varda's avatar
Kenton Varda committed
4 5 6 7 8 9
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
Kenton Varda's avatar
Kenton Varda committed
10
//
Kenton Varda's avatar
Kenton Varda committed
11 12
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
Kenton Varda's avatar
Kenton Varda committed
13
//
Kenton Varda's avatar
Kenton Varda committed
14 15 16 17 18 19 20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
Kenton Varda's avatar
Kenton Varda committed
21

22
#pragma once
Kenton Varda's avatar
Kenton Varda committed
23

24
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
25 26 27
#pragma GCC system_header
#endif

Kenton Varda's avatar
Kenton Varda committed
28 29
#include <capnp/orphan.h>
#include <capnp/compiler/grammar.capnp.h>
Kenton Varda's avatar
Kenton Varda committed
30
#include <capnp/schema.capnp.h>
Kenton Varda's avatar
Kenton Varda committed
31 32
#include <capnp/dynamic.h>
#include <kj/vector.h>
Kenton Varda's avatar
Kenton Varda committed
33
#include <kj/one-of.h>
Kenton Varda's avatar
Kenton Varda committed
34
#include "error-reporter.h"
35
#include <map>
Kenton Varda's avatar
Kenton Varda committed
36 37 38 39 40 41 42 43 44 45 46 47

namespace capnp {
namespace compiler {

class NodeTranslator {
  // Translates one node in the schema from AST form to final schema form.  A "node" is anything
  // that has a unique ID, such as structs, enums, constants, and annotations, but not fields,
  // unions, enumerants, or methods (the latter set have 16-bit ordinals but not 64-bit global IDs).

public:
  class Resolver {
    // Callback class used to find other nodes relative to this one.
48 49 50 51
    //
    // TODO(cleanup): This has evolved into being a full interface for traversing the node tree.
    //   Maybe we should rename it as such, and move it out of NodeTranslator. See also
    //   TODO(cleanup) on NodeTranslator::BrandedDecl.
Kenton Varda's avatar
Kenton Varda committed
52 53

  public:
Kenton Varda's avatar
Kenton Varda committed
54
    struct ResolvedDecl {
Kenton Varda's avatar
Kenton Varda committed
55
      uint64_t id;
Kenton Varda's avatar
Kenton Varda committed
56 57
      uint genericParamCount;
      uint64_t scopeId;
58
      Declaration::Which kind;
Kenton Varda's avatar
Kenton Varda committed
59
      Resolver* resolver;
60 61 62 63 64 65

      kj::Maybe<schema::Brand::Reader> brand;
      // If present, then it is necessary to replace the brand scope with the given brand before
      // using the target type. This happens when the decl resolved to an alias; all other fields
      // of `ResolvedDecl` refer to the target of the alias, except for `scopeId` which is the
      // scope that contained the alias.
Kenton Varda's avatar
Kenton Varda committed
66 67
    };

Kenton Varda's avatar
Kenton Varda committed
68 69 70 71 72
    struct ResolvedParameter {
      uint64_t id;  // ID of the node declaring the parameter.
      uint index;   // Index of the parameter.
    };

73
    typedef kj::OneOf<ResolvedDecl, ResolvedParameter> ResolveResult;
Kenton Varda's avatar
Kenton Varda committed
74

75
    virtual kj::Maybe<ResolveResult> resolve(kj::StringPtr name) = 0;
Kenton Varda's avatar
Kenton Varda committed
76 77 78
    // Look up the given name, relative to this node, and return basic information about the
    // target.

79
    virtual kj::Maybe<ResolveResult> resolveMember(kj::StringPtr name) = 0;
Kenton Varda's avatar
Kenton Varda committed
80 81
    // Look up a member of this node.

82 83 84
    virtual ResolvedDecl resolveBuiltin(Declaration::Which which) = 0;
    virtual ResolvedDecl resolveId(uint64_t id) = 0;

85 86 87
    virtual kj::Maybe<ResolvedDecl> getParent() = 0;
    // Returns the parent of this scope, or null if this is the top scope.

Kenton Varda's avatar
Kenton Varda committed
88 89 90
    virtual ResolvedDecl getTopScope() = 0;
    // Get the top-level scope containing this node.

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 94
    // dependencies via the Schema API.  A schema that is only at the bootstrap stage is
    // acceptable.
95 96 97
    //
    // Throws an exception if the id is not one that was found by calling resolve() or by
    // 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.
Kenton Varda's avatar
Kenton Varda committed
99

100
    virtual kj::Maybe<schema::Node::Reader> resolveFinalSchema(uint64_t id) = 0;
101 102 103 104
    // Get the final schema for the given ID.  A bootstrap schema is not acceptable.  A raw
    // node reader is returned rather than a Schema object because using a Schema object built
    // by the final schema loader could trigger lazy initialization of dependencies which could
    // lead to a cycle and deadlock.
105 106 107 108
    //
    // Throws an exception if the id is not one that was found by calling resolve() or by
    // traversing other schemas.  Returns null if the ID is recognized, but the corresponding
    // schema node failed to be built for reasons that were already reported.
109

Kenton Varda's avatar
Kenton Varda committed
110
    virtual kj::Maybe<ResolvedDecl> resolveImport(kj::StringPtr name) = 0;
111
    // Get the ID of an imported file given the import path.
112

113 114 115
    virtual kj::Maybe<kj::Array<const byte>> readEmbed(kj::StringPtr name) = 0;
    // Read and return the contents of a file for an `embed` expression.

116 117 118 119
    virtual kj::Maybe<Type> resolveBootstrapType(schema::Type::Reader type, Schema scope) = 0;
    // Compile a schema::Type into a Type whose dependencies may safely be traversed via the schema
    // API. These dependencies may have only bootstrap schemas. Returns null if the type could not
    // be constructed due to already-reported errors.
Kenton Varda's avatar
Kenton Varda committed
120 121
  };

122
  NodeTranslator(Resolver& resolver, ErrorReporter& errorReporter,
Kenton Varda's avatar
Kenton Varda committed
123
                 const Declaration::Reader& decl, Orphan<schema::Node> wipNode,
124
                 bool compileAnnotations);
Kenton Varda's avatar
Kenton Varda committed
125 126 127 128
  // Construct a NodeTranslator to translate the given declaration.  The wipNode starts out with
  // `displayName`, `id`, `scopeId`, and `nestedNodes` already initialized.  The `NodeTranslator`
  // fills in the rest.

Kenton Varda's avatar
Kenton Varda committed
129
  ~NodeTranslator() noexcept(false);
130

Kenton Varda's avatar
Kenton Varda committed
131
  struct NodeSet {
Kenton Varda's avatar
Kenton Varda committed
132
    schema::Node::Reader node;
Kenton Varda's avatar
Kenton Varda committed
133 134
    // The main node.

Kenton Varda's avatar
Kenton Varda committed
135
    kj::Array<schema::Node::Reader> auxNodes;
Kenton Varda's avatar
Kenton Varda committed
136 137
    // Auxiliary nodes that were produced when translating this node and should be loaded along
    // 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 141

    kj::Array<schema::Node::SourceInfo::Reader> sourceInfo;
    // The SourceInfo for the node and all aux nodes.
Kenton Varda's avatar
Kenton Varda committed
142 143 144
  };

  NodeSet getBootstrapNode();
Kenton Varda's avatar
Kenton Varda committed
145 146 147 148 149 150 151 152
  // Get an incomplete version of the node in which pointer-typed value expressions have not yet
  // been translated.  Instead, for all `schema.Value` objects representing pointer-type values,
  // the value is set to an appropriate "empty" value.  This version of the schema can be used to
  // bootstrap the dynamic API which can then in turn be used to encode the missing complex values.
  //
  // If the final node has already been built, this will actually return the final node (in fact,
  // it's the same node object).

Kenton Varda's avatar
Kenton Varda committed
153
  NodeSet finish();
Kenton Varda's avatar
Kenton Varda committed
154 155 156
  // Finish translating the node (including filling in all the pieces that are missing from the
  // bootstrap node) and return it.

157 158 159 160 161 162 163 164 165
  static kj::Maybe<Resolver::ResolveResult> compileDecl(
      uint64_t scopeId, uint scopeParameterCount, Resolver& resolver, ErrorReporter& errorReporter,
      Expression::Reader expression, schema::Brand::Builder brandBuilder);
  // Compile a one-off declaration expression without building a NodeTranslator. Used for
  // evaluating aliases.
  //
  // `brandBuilder` may be used to construct a message which will fill in ResolvedDecl::brand in
  // the result.

Kenton Varda's avatar
Kenton Varda committed
166
private:
167 168 169 170
  class DuplicateNameDetector;
  class DuplicateOrdinalDetector;
  class StructLayout;
  class StructTranslator;
171 172
  class BrandedDecl;
  class BrandScope;
173

174 175
  Resolver& resolver;
  ErrorReporter& errorReporter;
176
  Orphanage orphanage;
177
  bool compileAnnotations;
178
  kj::Own<BrandScope> localBrand;
Kenton Varda's avatar
Kenton Varda committed
179

Kenton Varda's avatar
Kenton Varda committed
180
  Orphan<schema::Node> wipNode;
181
  // The work-in-progress schema node.
Kenton Varda's avatar
Kenton Varda committed
182

183 184 185 186 187 188 189
  Orphan<schema::Node::SourceInfo> sourceInfo;
  // Doc comments and other source info for this node.

  struct AuxNode {
    Orphan<schema::Node> node;
    Orphan<schema::Node::SourceInfo> sourceInfo;
  };
Kenton Varda's avatar
Kenton Varda committed
190

191
  kj::Vector<AuxNode> groups;
Kenton Varda's avatar
Kenton Varda committed
192 193 194
  // If this is a struct node and it contains groups, these are the nodes for those groups,  which
  // must be loaded together with the top-level node.

195
  kj::Vector<AuxNode> paramStructs;
196 197
  // If this is an interface, these are the auto-generated structs representing params and results.

Kenton Varda's avatar
Kenton Varda committed
198
  struct UnfinishedValue {
Kenton Varda's avatar
Kenton Varda committed
199
    Expression::Reader source;
Kenton Varda's avatar
Kenton Varda committed
200
    schema::Type::Reader type;
201
    Schema typeScope;
Kenton Varda's avatar
Kenton Varda committed
202
    schema::Value::Builder target;
Kenton Varda's avatar
Kenton Varda committed
203 204 205 206 207 208 209
  };
  kj::Vector<UnfinishedValue> unfinishedValues;
  // List of values in `wipNode` which have not yet been interpreted, because they are structs
  // or lists and as such interpreting them require using the types' schemas (to take advantage
  // of the dynamic API).  Once bootstrap schemas have been built, they can be used to interpret
  // these values.

Kenton Varda's avatar
Kenton Varda committed
210
  void compileNode(Declaration::Reader decl, schema::Node::Builder builder);
Kenton Varda's avatar
Kenton Varda committed
211

Kenton Varda's avatar
Kenton Varda committed
212
  void compileConst(Declaration::Const::Reader decl, schema::Node::Const::Builder builder);
Kenton Varda's avatar
Kenton Varda committed
213
  void compileAnnotation(Declaration::Annotation::Reader decl,
Kenton Varda's avatar
Kenton Varda committed
214
                         schema::Node::Annotation::Builder builder);
Kenton Varda's avatar
Kenton Varda committed
215

216
  void compileEnum(Void decl, List<Declaration>::Reader members,
Kenton Varda's avatar
Kenton Varda committed
217
                   schema::Node::Builder builder);
218
  void compileStruct(Void decl, List<Declaration>::Reader members,
Kenton Varda's avatar
Kenton Varda committed
219
                     schema::Node::Builder builder);
220 221
  void compileInterface(Declaration::Interface::Reader decl,
                        List<Declaration>::Reader members,
Kenton Varda's avatar
Kenton Varda committed
222
                        schema::Node::Builder builder);
Kenton Varda's avatar
Kenton Varda committed
223 224 225
  // The `members` arrays contain only members with ordinal numbers, in code order.  Other members
  // are handled elsewhere.

226 227 228 229 230
  struct ImplicitParams {
    // Represents a set of implicit parameters visible in the current context.

    uint64_t scopeId;
    // 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 233 234 235 236 237 238 239 240
    // AnyPointer.

    List<Declaration::BrandParameter>::Reader params;
  };

  static inline ImplicitParams noImplicitParams() {
    return { 0, List<Declaration::BrandParameter>::Reader() };
  }

241
  template <typename InitBrandFunc>
242
  uint64_t compileParamList(kj::StringPtr methodName, uint16_t ordinal, bool isResults,
Kenton Varda's avatar
Kenton Varda committed
243
                            Declaration::ParamList::Reader paramList,
244
                            typename List<Declaration::BrandParameter>::Reader implicitParams,
245
                            InitBrandFunc&& initBrand);
246 247
  // Compile a param (or result) list and return the type ID of the struct type.

248 249
  kj::Maybe<BrandedDecl> compileDeclExpression(
      Expression::Reader source, ImplicitParams implicitMethodParams);
Kenton Varda's avatar
Kenton Varda committed
250 251
  // Compile an expression which is expected to resolve to a declaration or type expression.

252 253
  bool compileType(Expression::Reader source, schema::Type::Builder target,
                   ImplicitParams implicitMethodParams);
Kenton Varda's avatar
Kenton Varda committed
254 255 256
  // Returns false if there was a problem, in which case value expressions of this type should
  // not be parsed.

Kenton Varda's avatar
Kenton Varda committed
257
  void compileDefaultDefaultValue(schema::Type::Reader type, schema::Value::Builder target);
Kenton Varda's avatar
Kenton Varda committed
258 259
  // Initializes `target` to contain the "default default" value for `type`.

260 261 262
  void compileBootstrapValue(
      Expression::Reader source, schema::Type::Reader type, schema::Value::Builder target,
      Schema typeScope = Schema());
263 264
  // Calls compileValue() if this value should be interpreted at bootstrap time.  Otheriwse,
  // adds the value to `unfinishedValues` for later evaluation.
265 266 267 268 269 270
  //
  // If `type` comes from some other node, `typeScope` is the schema for that node. This is only
  // really needed for looking up generic parameter bindings, therefore if the type comes from
  // the node being built, an empty "Schema" (the default) works here because the node being built
  // is of course being built for all possible bindings and thus none of its generic parameters are
  // bound.
Kenton Varda's avatar
Kenton Varda committed
271

Kenton Varda's avatar
Kenton Varda committed
272
  void compileValue(Expression::Reader source, schema::Type::Reader type,
273
                    Schema typeScope, schema::Value::Builder target, bool isBootstrap);
274 275
  // Interprets the value expression and initializes `target` with the result.

Kenton Varda's avatar
Kenton Varda committed
276
  kj::Maybe<DynamicValue::Reader> readConstant(Expression::Reader name, bool isBootstrap);
277 278 279
  // Get the value of the given constant.  May return null if some error occurs, which will already
  // have been reported.

280 281 282
  kj::Maybe<kj::Array<const byte>> readEmbed(LocatedText::Reader filename);
  // Read a raw file for embedding.

283 284 285 286 287 288 289 290 291
  Orphan<List<schema::Annotation>> compileAnnotationApplications(
      List<Declaration::AnnotationApplication>::Reader annotations,
      kj::StringPtr targetsFlagName);
};

class ValueTranslator {
public:
  class Resolver {
  public:
Kenton Varda's avatar
Kenton Varda committed
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 298
      : resolver(resolver), errorReporter(errorReporter), orphanage(orphanage) {}

299
  kj::Maybe<Orphan<DynamicValue>> compileValue(Expression::Reader src, Type type);
300

301 302 303 304
  void fillStructValue(DynamicStruct::Builder builder,
                       List<Expression::Param>::Reader assignments);
  // Interprets the given assignments and uses them to fill in the given struct builder.

305 306
private:
  Resolver& resolver;
307
  ErrorReporter& errorReporter;
308
  Orphanage orphanage;
309

310
  Orphan<DynamicValue> compileValueInner(Expression::Reader src, Type type);
311
  // Helper for compileValue().
Kenton Varda's avatar
Kenton Varda committed
312

313 314
  kj::String makeNodeName(Schema node);
  kj::String makeTypeName(Type type);
315

Kenton Varda's avatar
Kenton Varda committed
316
  kj::Maybe<ListSchema> makeListSchemaOf(schema::Type::Reader elementType);
Kenton Varda's avatar
Kenton Varda committed
317 318 319 320
};

}  // namespace compiler
}  // namespace capnp