# Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
# 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.

using Cxx = import "c++.capnp";

@0xb471df2f45ca32c7;
$Cxx.namespace("capnp::schema");

# WARNING:  This protocol is still subject to backwards-incompatible change.

using Id = UInt64;
# The globally-unique ID of a file, type, or annotation.

struct Node {
  id @0 :Id;

  displayName @1 :Text;
  # Name to present to humans to identify this Node.  You should not attempt to parse this.  Its
  # format could change.  It is not guaranteed to be unique.
  #
  # (On Zooko's triangle, this is the node's nickname.)

  scopeId @2 :Id = 0;
  # ID of the lexical parent node.  Typically, the scope node will have a NestedNode pointing back
  # at this node, but robust code should avoid relying on this.  `scopeId` is zero if the node has
  # no parent, which is normally only the case with files, but should be allowed for any kind of
  # node (in order to make runtime type generation easier).

  nestedNodes @3 :List(NestedNode);
  # List of nodes nested within this node, along with the names under which they were declared.

  struct NestedNode {
    name @0 :Text;
    # Unqualified symbol name.  Unlike Node.name, this *can* be used programmatically.
    #
    # (On Zooko's triangle, this is the node's petname according to its parent scope.)

    id @1 :Id;
    # ID of the nested node.  Typically, the target node's scopeId points back to this node, but
    # robust code should avoid relying on this.
  }

  annotations @4 :List(Annotation);
  # Annotations applied to this node.

  body @5 union {
    # Info specific to each kind of node.

    fileNode @6 :FileNode;
    structNode @7 :StructNode;
    enumNode @8 :EnumNode;
    interfaceNode @9 :InterfaceNode;
    constNode @10 :ConstNode;
    annotationNode @11 :AnnotationNode;
  }
}

struct Type {
  # Represents a type expression.

  body @0 union {
    voidType @1 :Void;
    boolType @2 :Void;
    int8Type @3 :Void;
    int16Type @4 :Void;
    int32Type @5 :Void;
    int64Type @6 :Void;
    uint8Type @7 :Void;
    uint16Type @8 :Void;
    uint32Type @9 :Void;
    uint64Type @10 :Void;
    float32Type @11 :Void;
    float64Type @12 :Void;
    textType @13 :Void;
    dataType @14 :Void;

    listType @15 :Type;  # Value = the element type.

    enumType @16 :Id;
    structType @17 :Id;
    interfaceType @18 :Id;

    objectType @19 :Void;
  }
}

struct Value {
  # Represents a value, e.g. a field default value, constant value, or annotation value.

  body @0 union {
    # Note ordinals 1 and 10 are intentionally swapped to improve union layout.
    voidValue @10 :Void;
    boolValue @2 :Bool;
    int8Value @3 :Int8;
    int16Value @4 :Int16;
    int32Value @5 :Int32;
    int64Value @6 :Int64;
    uint8Value @7 :UInt8;
    uint16Value @8 :UInt16;
    uint32Value @9 :UInt32;
    uint64Value @1 :UInt64;
    float32Value @11 :Float32;
    float64Value @12 :Float64;
    textValue @13 :Text;
    dataValue @14 :Data;

    listValue @15 :Object;

    enumValue @16 :UInt16;
    structValue @17 :Object;

    interfaceValue @18 :Void;
    # The only interface value that can be represented statically is "null", whose methods always
    # throw exceptions.

    objectValue @19 :Object;
  }
}

struct Annotation {
  # Describes an annotation applied to a declaration.  Note AnnotationNode describes the
  # annotation's declaration, while this describes a use of the annotation.

  id @0 :Id;
  # ID of the annotation node.

  value @1 :Value;
}

struct FileNode {
  imports @0 :List(Import);
  struct Import {
    id @0 :Id;
    # ID of the imported file.

    name @1 :Text;
    # Name which *this* file used to refer to the foreign file.  This may be a relative name.
    # This information is provided because it might be useful for code generation, e.g. to generate
    # #include directives in C++.
    #
    # (On Zooko's triangle, this is the import's petname according to the importing file.)
  }
}

enum ElementSize {
  # Possible element sizes for encoded lists.  These correspond exactly to the possible values of
  # the 3-bit element size component of a list pointer.

  empty @0;    # aka "void", but that's a keyword.
  bit @1;
  byte @2;
  twoBytes @3;
  fourBytes @4;
  eightBytes @5;
  pointer @6;
  inlineComposite @7;
}

struct StructNode {
  dataSectionWordSize @0 :UInt16;
  pointerSectionSize @1 :UInt16;

  preferredListEncoding @2 :ElementSize;
  # The preferred element size to use when encoding a list of this struct.  If this is anything
  # other than `inlineComposite` then the struct is one word or less in size and is a candidate for
  # list packing optimization.

  members @3 :List(Member);
  # Top-level fields and unions of the struct, ordered by ordinal number, except that members of
  # unions are not included in this list (because they are nested inside the union declaration).
  # Note that this ordering is stable as the protocol evolves -- new members can only be added to
  # the end.  So, when encoding a struct as tag/value pairs with numeric tags, it actually may make
  # sense to use the field's position in this list rather than the original ordinal number to
  # identify fields.

  struct Member {
    name @0 :Text;

    ordinal @1 :UInt16;

    codeOrder @2 :UInt16;
    # Indicates where this member appeared in the code, relative to other members.
    # Code ordering may have semantic relevance -- programmers tend to place related fields
    # together.  So, using code ordering makes sense in human-readable formats where ordering is
    # otherwise irrelevant, like JSON.  The values of codeOrder are tightly-packed, so the maximum
    # value is count(members) - 1.  Fields that are members of a union are only ordered relative to
    # the other members of that union, so the maximum value there is count(union.members).

    annotations @3 :List(Annotation);

    body @4 union {
      # More member types could be added over time.  Consumers should skip those that they
      # don't understand.

      fieldMember @5 :Field;
      unionMember @6 :Union;
    }
  }

  struct Field {
    offset @0 :UInt32;
    # Offset, in units of the field's size, from the beginning of the section in which the field
    # resides.  E.g. for a UInt32 field, multiply this by 4 to get the byte offset from the
    # beginning of the data section.

    type @1 :Type;
    defaultValue @2 :Value;
  }

  struct Union {
    discriminantOffset @0 :UInt32;
    # Offset of the union's 16-bit discriminant within the struct's data section, in 16-bit units.

    members @1 :List(Member);
    # Fields of this union, ordered by ordinal.  Currently all members are fields, but
    # consumers should skip member types that they don't understand.  The first member in this list
    # gets discriminant value zero, the next gets one, and so on.
  }
}

struct EnumNode {
  enumerants @0 :List(Enumerant);
  # Enumerants, in order by ordinal.

  struct Enumerant {
    name @0 :Text;

    codeOrder @1 :UInt16;
    # Specifies order in which the enumerants were declared in the code.
    # Like Struct.Field.codeOrder.

    annotations @2 :List(Annotation);
  }
}

struct InterfaceNode {
  methods @0 :List(Method);
  # Methods, in order by ordinal.

  struct Method {
    name @0 :Text;

    codeOrder @1 :UInt16;
    # Specifies order in which the methods were declared in the code.
    # Like Struct.Field.codeOrder.

    params @2 :List(Param);
    struct Param {
      name @0 :Text;
      type @1 :Type;
      defaultValue @2 :Value;
      annotations @3 :List(Annotation);
    }

    requiredParamCount @3 :UInt16;
    # One plus the index of the last parameter that has no default value.  In languages where
    # method calls look like function calls, this is the minimum number of parameters that must
    # always be specified, while subsequent parameters are optional.

    returnType @4 :Type;

    annotations @5 :List(Annotation);
  }
}

struct ConstNode {
  type @0 :Type;
  value @1 :Value;
}

struct AnnotationNode {
  type @0 :Type;

  targetsFile @1 :Bool;
  targetsConst @2 :Bool;
  targetsEnum @3 :Bool;
  targetsEnumerant @4 :Bool;
  targetsStruct @5 :Bool;
  targetsField @6 :Bool;
  targetsUnion @7 :Bool;
  targetsInterface @8 :Bool;
  targetsMethod @9 :Bool;
  targetsParam @10 :Bool;
  targetsAnnotation @11 :Bool;
}

struct CodeGeneratorRequest {
  nodes @0 :List(Node);
  # All nodes parsed by the compiler, including for the files on the command line and their
  # imports.

  requestedFiles @1 :List(Id);
  # IDs of files which were listed on the command line.
}