blob: eb1a23354341dba645510476f83ba807b0e0f04d [file] [log] [blame]
// Copyright (c) 2013, Kenton Varda <[email protected]>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CAPNP_COMPILER_NODE_TRANSLATOR_H_
#define CAPNP_COMPILER_NODE_TRANSLATOR_H_
#include <capnp/orphan.h>
#include <capnp/compiler/grammar.capnp.h>
#include <capnp/schema.capnp.h>
#include <capnp/schema-loader.h>
#include <capnp/dynamic.h>
#include <kj/vector.h>
#include "error-reporter.h"
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.
public:
struct ResolvedName {
uint64_t id;
Declaration::Body::Which kind;
};
virtual kj::Maybe<ResolvedName> resolve(const DeclName::Reader& name) const = 0;
// Look up the given name, relative to this node, and return basic information about the
// target.
virtual kj::Maybe<Schema> resolveBootstrapSchema(uint64_t id) const = 0;
// Get the schema for the given ID. If a schema is returned, it must be safe to traverse its
// dependencies using Schema::getDependency(). A schema that is only at the bootstrap stage
// is acceptable.
//
// 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.
virtual kj::Maybe<Schema> resolveFinalSchema(uint64_t id) const = 0;
// Get the final schema for the given ID. A bootstrap schema is not acceptable. It is NOT
// safe to traverse the schema's dependencies with Schema::getDependency() as doing so may
// trigger lazy loading callbacks that deadlock on the compiler mutex. Instead, the caller
// should carefully look up dependencies through this Resolver.
//
// 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.
};
NodeTranslator(const Resolver& resolver, const ErrorReporter& errorReporter,
const Declaration::Reader& decl, Orphan<schema::Node> wipNode);
// 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.
schema::Node::Reader getBootstrapNode() { return wipNode.getReader(); }
// 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).
schema::Node::Reader finish();
// Finish translating the node (including filling in all the pieces that are missing from the
// bootstrap node) and return it.
private:
const Resolver& resolver;
const ErrorReporter& errorReporter;
Orphan<schema::Node> wipNode;
// The work-in-progress schema node.
struct UnfinishedValue {
ValueExpression::Reader source;
schema::Type::Reader type;
schema::Value::Builder target;
};
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.
void compileNode(Declaration::Reader decl, schema::Node::Builder builder);
void checkMembers(List<Declaration>::Reader nestedDecls, Declaration::Body::Which parentKind);
// Check the given member list for errors, including detecting duplicate names and detecting
// out-of-place declarations.
void disallowNested(List<Declaration>::Reader nestedDecls);
// Complain if the nested decl list is non-empty.
void compileFile(Declaration::Reader decl, schema::FileNode::Builder builder);
void compileConst(Declaration::Const::Reader decl, schema::ConstNode::Builder builder);
void compileAnnotation(Declaration::Annotation::Reader decl,
schema::AnnotationNode::Builder builder);
class DuplicateOrdinalDetector;
class StructLayout;
class StructTranslator;
void compileEnum(Declaration::Enum::Reader decl, List<Declaration>::Reader members,
schema::EnumNode::Builder builder);
void compileStruct(Declaration::Struct::Reader decl, List<Declaration>::Reader members,
schema::StructNode::Builder builder);
void compileInterface(Declaration::Interface::Reader decl, List<Declaration>::Reader members,
schema::InterfaceNode::Builder builder);
// The `members` arrays contain only members with ordinal numbers, in code order. Other members
// are handled elsewhere.
bool compileType(TypeExpression::Reader source, schema::Type::Builder target);
// Returns false if there was a problem, in which case value expressions of this type should
// not be parsed.
void compileDefaultDefaultValue(schema::Type::Reader type, schema::Value::Builder target);
// Initializes `target` to contain the "default default" value for `type`.
void compileBootstrapValue(ValueExpression::Reader source, schema::Type::Reader type,
schema::Value::Builder target);
// Calls compileValue() if this value should be interpreted at bootstrap time. Otheriwse,
// adds the value to `unfinishedValues` for later evaluation.
void compileValue(ValueExpression::Reader source, schema::Type::Reader type,
schema::Value::Builder target, bool isBootstrap);
// Interprets the value expression and initializes `target` with the result.
class DynamicSlot;
void compileValue(ValueExpression::Reader src, DynamicSlot& dst, bool isBootstrap);
// Fill in `dst` (which effectively points to a struct field or list element) with the given
// value.
void compileValueInner(ValueExpression::Reader src, DynamicSlot& dst, bool isBootstrap);
// Helper for compileValue().
void copyValue(schema::Value::Reader src, schema::Type::Reader srcType,
schema::Value::Builder dst, schema::Type::Reader dstType,
ValueExpression::Reader errorLocation);
// Copy a value from one schema to another, possibly coercing the type if compatible, or
// reporting an error otherwise.
kj::Maybe<DynamicValue::Reader> readConstant(DeclName::Reader name, bool isBootstrap,
ValueExpression::Reader errorLocation);
// Get the value of the given constant. May return null if some error occurs, which will already
// have been reported.
kj::Maybe<ListSchema> makeListSchemaOf(schema::Type::Reader elementType);
// Construct a list schema representing a list of elements of the given type. May return null if
// some error occurs, which will already have been reported.
Orphan<List<schema::Annotation>> compileAnnotationApplications(
List<Declaration::AnnotationApplication>::Reader annotations,
kj::StringPtr targetsFlagName);
};
} // namespace compiler
} // namespace capnp
#endif // CAPNP_COMPILER_NODE_TRANSLATOR_H_