Initial commit, mostly working except for enums.

This commit is contained in:
Jason Paryani 2013-06-18 18:36:18 -07:00
parent dba8ec8331
commit e2507b4ef3
10 changed files with 10324 additions and 0 deletions

27
c++.capnp Normal file
View file

@ -0,0 +1,27 @@
# 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.
@0xbdf87d7bb8304e81;
$namespace("capnproto::annotations");
annotation namespace(file): Text;

96
capnp.tmpl.pxd Normal file
View file

@ -0,0 +1,96 @@
# schema.capnp.cpp.pyx
# distutils: language = c++
# distutils: extra_compile_args = --std=c++11
# distutils: libraries = capnp
from libc.stdint cimport *
ctypedef unsigned int uint
ctypedef uint8_t UInt8
ctypedef uint16_t UInt16
ctypedef uint32_t UInt32
ctypedef uint64_t UInt64
ctypedef int8_t Int8
ctypedef int16_t Int16
ctypedef int32_t Int32
ctypedef int64_t Int64
ctypedef char * Data
ctypedef char * Object
ctypedef char * Text
ctypedef bint Bool
ctypedef float Float32
ctypedef double Float64
cdef extern from "capnp/message.h" namespace "::capnp":
cdef cppclass List[T]:
cppclass Reader:
T operator[](uint)
uint size()
cppclass Builder:
T operator[](uint)
uint size()
cdef extern from "schema.capnp.h" namespace "::capnp::schema":
{%- for node_name, node_dict in nodes.items() %}
cdef cppclass {{node_name|capitalize}}
{%- endfor %}
{%- for node_name, node_dict in nodes.items() recursive %}
{{ 'cdef ' if loop.depth == 1 }}cppclass {{node_name|capitalize}}:
{%- for node_name, node_dict in node_dict['nestedNodes'].items() %}
cppclass {{node_name|capitalize}}
{%- endfor %}
{{ loop(node_dict['nestedNodes'].items()) | indent }}
cppclass Reader:
{%- for member_name, member_dict in node_dict['members'].items() %}
{{member_dict['type']}}{{'.Reader' if member_dict.get('type', '').startswith('List') }} get{{member_name|capitalize}}()
{%- endfor %}
cppclass Builder:
{%- for member_name, member_dict in node_dict['members'].items() %}
{{member_dict['type']}}{{'.Builder' if member_dict.get('type', '').startswith('List') }} get{{member_name|capitalize}}()
{%- if member_dict.get('type', '').startswith('List') %}
{{member_dict['type']}}.Builder init{{member_name|capitalize}}(int)
{%- else %}
{{' ' if not member_dict['type']}}void set{{member_name|capitalize}}({{member_dict['type']}})
{%- endif %}
{%- endfor %}
{%- endfor %}
cdef extern from "capnp/message.h" namespace "::capnp":
cdef cppclass ReaderOptions:
uint64_t traversalLimitInWords
uint nestingLimit
cdef cppclass MessageBuilder:
{%- for name, values in nodes.items() %}
{{name}}.Builder getRoot{{name}}'getRoot<{{namespace}}::{{name}}>'()
{{name}}.Builder initRoot{{name}}'initRoot<{{namespace}}::{{name}}>'()
{%- endfor %}
cdef cppclass MessageReader:
{%- for name, values in nodes.items() %}
{{name}}.Reader getRoot{{name}}'getRoot<{{namespace}}::{{name}}>'()
{%- endfor %}
cdef cppclass MallocMessageBuilder(MessageBuilder):
MallocMessageBuilder()
MallocMessageBuilder(int)
enum Void:
VOID
cdef extern from "capnp/serialize.h" namespace "::capnp":
cdef cppclass StreamFdMessageReader(MessageReader):
StreamFdMessageReader(int)
StreamFdMessageReader(int, ReaderOptions)
void writeMessageToFd(int, MessageBuilder&)
cdef extern from "capnp/serialize-packed.h" namespace "::capnp":
cdef cppclass PackedFdMessageReader(MessageReader):
PackedFdMessageReader(int)
StreamFdMessageReader(int, ReaderOptions)
void writePackedMessageToFd(int, MessageBuilder&)

175
capnp.tmpl.pyx Normal file
View file

@ -0,0 +1,175 @@
# schema.capnp.cpp.pyx
# distutils: language = c++
# distutils: extra_compile_args = --std=c++11
# distutils: libraries = capnp
cimport capnp_schema as capnp
from capnp_schema cimport {% for node_name, node_dict in nodes.items() %}{{node_name|capitalize}} as C_{{node_name|capitalize}}{{',' if not loop.last}}{% endfor %}
# from capnp_schema cimport *
# Not doing this since we want to namespace away the class names
from cython.operator cimport dereference as deref
from libc.stdint cimport *
ctypedef unsigned int uint
ctypedef uint8_t UInt8
ctypedef uint16_t UInt16
ctypedef uint32_t UInt32
ctypedef uint64_t UInt64
ctypedef int8_t Int8
ctypedef int16_t Int16
ctypedef int32_t Int32
ctypedef int64_t Int64
ctypedef char * Data
ctypedef char * Object
ctypedef char * Text
ctypedef bint Bool
ctypedef float Float32
ctypedef double Float64
cdef extern from "capnp/message.h" namespace "::capnp":
cdef cppclass List[T]:
cppclass Reader:
T operator[](uint)
uint size()
cppclass Builder:
T operator[](uint)
uint size()
def make_enum(enum_name, *sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
reverse = dict((value, key) for key, value in enums.iteritems())
enums['reverse_mapping'] = reverse
return type(enum_name, (), enums)
{%- for list_name, list_dict in list_types.items() %}
cdef class _{{ list_name |replace('[', '_')|replace(']','_')|replace('.','_')}}Reader:
cdef List[{{ list_dict['elem_type_cython'] }}].Reader thisptr
cdef init(self, List[{{ list_dict['elem_type_cython'] }}].Reader other):
self.thisptr = other
return self
def __getitem__(self, index):
size = self.thisptr.size()
if index > size:
raise IndexError('Out of bounds')
index = index % size
{%- if list_dict['elem_type'] in built_in_types %}
return self.thisptr[index]
{%- else %}
return _{{ list_dict['elem_type']|replace('.','_') }}Reader().init(<{{ list_dict['elem_type_cython'] }}.Reader>self.thisptr[index])
{%- endif %}
def __len__(self):
return self.thisptr.size()
cdef class _{{ list_name |replace('[', '_')|replace(']','_')|replace('.','_')}}Builder:
cdef List[{{ list_dict['elem_type_cython'] }}].Builder thisptr
cdef init(self, List[{{ list_dict['elem_type_cython'] }}].Builder other):
self.thisptr = other
return self
def __getitem__(self, index):
size = self.thisptr.size()
if index > size:
raise IndexError('Out of bounds')
index = index % size
{%- if list_dict['elem_type'] in built_in_types %}
return self.thisptr[index]
{%- else %}
return _{{ list_dict['elem_type']|replace('.','_') }}Builder().init(<{{ list_dict['elem_type_cython'] }}.Builder>self.thisptr[index])
{%- endif %}
def __len__(self):
return self.thisptr.size()
{%- endfor %}
{%- for node_name, node_dict in nodes.items() recursive %}
{{ loop(node_dict['nestedNodes'].items()) }}
{%- if node_dict['body'] != 'enum' %}
cdef class {{ node_dict['full_name_cython'] }}Reader:
cdef C_{{ node_dict['full_name'] }}.Reader thisptr
cdef init(self, C_{{ node_dict['full_name'] }}.Reader other):
self.thisptr = other
return self
{%- for member_name, member_dict in node_dict['members'].items() %}
property {{member_name}}:
def __get__(self):
{%- if member_dict['type'] in primitive_types %}
return self.thisptr.get{{member_name|capitalize}}()
{%- elif member_dict['type'].startswith('List[') %}
return _{{ member_dict['type'] |replace('[', '_')|replace(']','_')|replace('.','_')}}Reader().init(self.thisptr.get{{member_name|capitalize}}())
{%- elif member_dict['type'] in built_in_types %}
return None
{%- else %}
return _{{ member_dict['full_type']|replace('.','_') }}Reader().init(<C_{{ member_dict['full_type'] }}.Reader>self.thisptr.get{{member_name|capitalize}}())
{%- endif %}
{%- endfor %}
cdef class {{ node_dict['full_name_cython'] }}Builder:
cdef C_{{ node_dict['full_name'] }}.Builder thisptr
cdef init(self, C_{{ node_dict['full_name'] }}.Builder other):
self.thisptr = other
return self
{%- for member_name, member_dict in node_dict['members'].items() %}
property {{member_name}}:
def __get__(self):
{%- if member_dict['type'] in primitive_types %}
return self.thisptr.get{{member_name|capitalize}}()
{%- elif member_dict['type'].startswith('List[') %}
return _{{ member_dict['type'] |replace('[', '_')|replace(']','_')|replace('.','_')}}Builder().init(self.thisptr.get{{member_name|capitalize}}())
{%- elif member_dict['type'] in built_in_types %}
return None
{%- else %}
return _{{ member_dict['full_type']|replace('.','_') }}Builder().init(<C_{{ member_dict['full_type'] }}.Builder>self.thisptr.get{{member_name|capitalize}}())
{%- endif %}
{%- if member_dict['type'] in primitive_types %}
def __set__(self, val):
self.thisptr.set{{member_name|capitalize}}(val)
{%- elif member_dict['type'].startswith('List[') %}
cpdef init{{member_name|capitalize}}(self, uint num):
return _{{ member_dict['type'] |replace('[', '_')|replace(']','_')|replace('.','_')}}Builder().init(self.thisptr.init{{member_name|capitalize}}(num))
{%- else %}
def __set__(self, val):
pass
{%- endif %}
{%- endfor %}
{%- endif %}
{%- endfor %}
cdef class MessageBuilder:
cdef capnp.MessageBuilder * thisptr
def __dealloc__(self):
del self.thisptr
{%- for name, node_dict in nodes.items() %}
{%- if node_dict['body'] != 'enum' %}
cpdef getRoot{{name}}(self):
return {{ node_dict['full_name_cython'] }}Builder().init(self.thisptr.getRoot{{name}}())
cpdef initRoot{{name}}(self):
return {{ node_dict['full_name_cython'] }}Builder().init(self.thisptr.initRoot{{name}}())
{%- endif %}
{%- endfor %}
cdef class MallocMessageBuilder(MessageBuilder):
def __cinit__(self):
self.thisptr = new capnp.MallocMessageBuilder()
cdef class MessageReader:
cdef capnp.MessageReader * thisptr
def __dealloc__(self):
del self.thisptr
{%- for name, node_dict in nodes.items() %}
{%- if node_dict['body'] != 'enum' %}
cpdef getRoot{{name}}(self):
return {{ node_dict['full_name_cython'] }}Reader().init(self.thisptr.getRoot{{name}}())
{%- endif %}
{%- endfor %}
cdef class StreamFdMessageReader(MessageReader):
def __cinit__(self, int fd):
self.thisptr = new capnp.StreamFdMessageReader(int)
cdef class PackedFdMessageReader(MessageReader):
def __cinit__(self, int fd):
self.thisptr = new capnp.PackedFdMessageReader(int)
def writeMessageToFd(int fd, MessageBuilder m):
capnp.writeMessageToFd(fd, deref(m.thisptr))
def writePackedMessageToFd(int fd, MessageBuilder m):
capnp.writePackedMessageToFd(fd, deref(m.thisptr))

314
schema.capnp Normal file
View file

@ -0,0 +1,314 @@
# 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.
}

2510
schema.capnp.c++ Normal file

File diff suppressed because it is too large Load diff

1631
schema.capnp.cpp.pyx Normal file

File diff suppressed because it is too large Load diff

5301
schema.capnp.h Normal file

File diff suppressed because it is too large Load diff

BIN
serialized_schema.test.bin Normal file

Binary file not shown.

241
setup.py Normal file
View file

@ -0,0 +1,241 @@
#!/usr/bin/env python
from distutils.core import setup
from Cython.Build import cythonize
from jinja2 import Environment, FileSystemLoader
import os
curr_dir = os.path.abspath(os.path.dirname(__file__))
env = Environment(loader=FileSystemLoader(curr_dir))
nodes = {
'Node' : {'body' : 'struct',
'members' : {
'id' : {'type' : 'UInt64'},
'displayName' : {'type' : 'Text'},
'scopeId' : {'type' : 'UInt64'},
'nestedNodes' : {'type' : 'List[Node.NestedNode]'},
'NestedNode' : {'body' : 'struct', 'is_not_field' : True,
'members' : {
'name' : {'type' : 'Text'},
'id' : {'type' : 'UInt64'},
}},
'annotations' : {'type' : 'List[Annotation]'},
'body' : {'body' : 'union',
'members' : {
'fileNode' : {'type' : 'FileNode'},
'structNode' : {'type' : 'StructNode'},
'enumNode' : {'type' : 'EnumNode'},
'interfaceNode' : {'type' : 'InterfaceNode'},
'constNode' : {'type' : 'ConstNode'},
'annotationNode' : {'type' : 'AnnotationNode'},
}},
}},
'Type' : {'body' : 'struct',
'members' : {
'body' : {'body' : 'union',
'members' : {
'voidType' : {'type' : 'Void'},
'boolType' : {'type' : 'Void'},
'int8Type' : {'type' : 'Void'},
'int16Type' : {'type' : 'Void'},
'int32Type' : {'type' : 'Void'},
'int64Type' : {'type' : 'Void'},
'uint8Type' : {'type' : 'Void'},
'uint16Type' : {'type' : 'Void'},
'uint32Type' : {'type' : 'Void'},
'uint64Type' : {'type' : 'Void'},
'float32Type' : {'type' : 'Void'},
'float64Type' : {'type' : 'Void'},
'textType' : {'type' : 'Void'},
'dataType' : {'type' : 'Void'},
'listType' : {'type' : 'Type'},
'enumType' : {'type' : 'UInt64'},
'structType' : {'type' : 'UInt64'},
'interfaceType' : {'type' : 'UInt64'},
'objectType' : {'type' : 'Void'},
}},
}},
'Value' : {'body' : 'struct',
'members' : {
'body' : {'body' : 'union',
'members' : {
'voidValue' : {'type' : 'Void'},
'boolValue' : {'type' : 'Bool'},
'int8Value' : {'type' : 'Int8'},
'int16Value' : {'type' : 'Int16'},
'int32Value' : {'type' : 'Int32'},
'int64Value' : {'type' : 'Int64'},
'uint8Value' : {'type' : 'UInt8'},
'uint16Value' : {'type' : 'UInt16'},
'uint32Value' : {'type' : 'UInt32'},
'uint64Value' : {'type' : 'UInt64'},
'float32Value' : {'type' : 'Float32'},
'float64Value' : {'type' : 'Float64'},
'textValue' : {'type' : 'Text'},
'dataValue' : {'type' : 'Data'},
'listValue' : {'type' : 'Object'},
'enumValue' : {'type' : 'UInt16'},
'structValue' : {'type' : 'Object'},
'interfaceValue' : {'type' : 'Void'},
'objectValue' : {'type' : 'Object'},
}},
}},
'Annotation' : {'body' : 'struct',
'members' : {
'id' : {'type' : 'UInt64'},
'value' : {'type' : 'Value'},
}},
'FileNode' : {'body' : 'struct',
'members' : {
'imports' : {'type' : 'List[FileNode.Import]'},
'Import' : {'body' : 'struct', 'is_not_field' : True,
'members' : {
'id' : {'type' : 'UInt64'},
'name' : {'type' : 'Text'},
}},
}},
'ElementSize' : {'body' : 'enum',
'members' : {
'empty' : {},
'bit' : {},
'byte' : {},
'twoBytes' : {},
'fourBytes' : {},
'eightBytes' : {},
'pointer' : {},
'inlineComposite' : {},
}},
'StructNode' : {'body' : 'struct',
'members' : {
'dataSectionWordSize' : {'type' : 'UInt16'},
'pointerSectionSize' : {'type' : 'UInt16'},
# 'preferredListEncoding' : {'type' : 'ElementSize'},
'members' : {'type' : 'List[StructNode.Member]'},
'Member' : {'body' : 'struct', 'is_not_field' : True,
'members' : {
'name' : {'type' : 'Text'},
'ordinal' : {'type' : 'UInt16'},
'codeOrder' : {'type' : 'UInt16'},
'annotations' : {'type' : 'List[Annotation]'},
'body' : {'body' : 'union',
'members' : {
'fieldMember' : {'type' : 'StructNode.Field'},
'unionMember' : {'type' : 'StructNode.Union'},
}},
}},
'Field' : {'body' : 'struct', 'is_not_field' : True,
'members' : {
'offset' : {'type' : 'UInt32'},
'type' : {'type' : 'Type'},
'defaultValue' : {'type' : 'Value'},
}},
'Union' : {'body' : 'struct', 'is_not_field' : True,
'members' : {
'discriminantOffset' : {'type' : 'UInt32'},
'members' : {'type' : 'List[StructNode.Member]'},
}},
}},
'EnumNode' : {'body' : 'struct',
'members' : {
'enumerants' : {'type' : 'List[EnumNode.Enumerant]'},
'Enumerant' : {'body' : 'struct', 'is_not_field' : True,
'members' : {
'name' : {'type' : 'Text'},
'codeOrder' : {'type' : 'UInt16'},
'annotations' : {'type' : 'List[Annotation]'},
}},
}},
'InterfaceNode' : {'body' : 'struct',
'members' : {
'methods' : {'type' : 'List[InterfaceNode.Method]'},
'Method' : {'body' : 'struct', 'is_not_field' : True,
'members' : {
'name' : {'type' : 'Text'},
'codeOrder' : {'type' : 'UInt16'},
'params' : {'type' : 'List[InterfaceNode.Method.Param]'},
'Param' : {'body' : 'struct', 'is_not_field' : True,
'members' : {
'name' : {'type' : 'Text'},
'type' : {'type' : 'Type'},
'defaultValue' : {'type' : 'Value'},
'annotations' : {'type' : 'List[Annotation]'},
}},
'requiredParamCount' : {'type' : 'UInt16'},
'returnType' : {'type' : 'Type'},
'annotations' : {'type' : 'List[Annotation]'},
}},
}},
'ConstNode' : {'body' : 'struct',
'members' : {
'type' : {'type' : 'Type'},
'value' : {'type' : 'Value'},
}},
'AnnotationNode' : {'body' : 'struct',
'members' : {
'type' : {'type' : 'Type'},
'targetsFile' : {'type' : 'Bool'},
'targetsConst' : {'type' : 'Bool'},
'targetsEnum' : {'type' : 'Bool'},
'targetsEnumerant' : {'type' : 'Bool'},
'targetsStruct' : {'type' : 'Bool'},
'targetsField' : {'type' : 'Bool'},
'targetsUnion' : {'type' : 'Bool'},
'targetsInterface' : {'type' : 'Bool'},
'targetsMethod' : {'type' : 'Bool'},
'targetsParam' : {'type' : 'Bool'},
'targetsAnnotation' : {'type' : 'Bool'},
}},
'CodeGeneratorRequest' : {'body' : 'struct',
'members' : {
'nodes' : {'type' : 'List[Node]'},
'requestedFiles' : {'type' : 'List[UInt64]'},
}},
}
primitive_types = set(('Bool','Int8','Int16','Int32','Int64','UInt8','UInt16','UInt32','UInt64','Float32','Float64'))
built_in_types = set(('Bool','Int8','Int16','Int32','Int64','UInt8','UInt16','UInt32','UInt64','Float32','Float64', 'Text', 'Data', 'Void', 'Object'))
list_types = {}
def capitalize(s):
if len(s) < 2:
return s
return s[0].upper() + s[1:]
def fixNodes(n):
def fixNode(node_dict, full_name):
nested = {}
node_dict['full_name'] = full_name
node_dict['full_name_cython'] = '_' + full_name.replace('.', '_')
for member, member_dict in node_dict['members'].items():
member_dict['full_type'] = member_dict.get('type')
if 'body' in member_dict:
nested[member] = fixNode(member_dict, full_name+'.'+capitalize(member))
if 'is_not_field' in member_dict:
del node_dict['members'][member]
else:
node_dict['members'][member] = {'type' : full_name+'.'+capitalize(member)}
node_dict['members'][member]['full_type'] = node_dict['members'][member].get('type')
elif member_dict.get('type', '').startswith('List'):
elem_type = member_dict['type'][member_dict['type'].find('[')+1:member_dict['type'].find(']')]
elem_type_name = elem_type if elem_type in built_in_types else capitalize((full_name+'.'+elem_type))
elem_type_cython = elem_type if elem_type in built_in_types else 'C_' + capitalize((full_name+'.'+elem_type))
list_types['List[%s]' % elem_type_name] = {'elem_type' : elem_type, 'elem_type_cython' : elem_type_cython}
member_dict['type'] = 'List[%s]' % elem_type_name
elif '.' in member_dict.get('type', ''):
member_dict['type'] = '.'.join(member_dict['type'].split('.')[1:])
node_dict['nestedNodes'] = nested
return node_dict
for node, node_dict in n.items():
fixNode(node_dict, capitalize(node))
return n
env.filters['capitalize'] = capitalize
nodes = fixNodes(nodes)
tmpl = env.get_template('capnp.tmpl.pxd')
open(os.path.join(curr_dir, 'capnp_schema.pxd'), 'w').write(tmpl.render(nodes=nodes, namespace='::capnp::schema', built_in_types=built_in_types))
tmpl = env.get_template('capnp.tmpl.pyx')
open(os.path.join(curr_dir, 'schema.capnp.cpp.pyx'), 'w').write(tmpl.render(nodes=nodes, namespace='::capnp::schema', primitive_types=primitive_types, built_in_types=built_in_types, list_types=list_types))
setup(
name = "capnp",
ext_modules = cythonize('schema.capnp.cpp.pyx'),
)

29
translate.py Normal file
View file

@ -0,0 +1,29 @@
#!/usr/bin/env python
from jinja2 import Template
nodes = {
'Node' : {'body' : 'struct',
'members' : {
'id' : {'type' : 'UInt64'}
}
}}
f=open('schema.verbose')
for line in f.readlines()[10:]:
sline = line.strip()
if sline == '':
continue
elif sline.startswith('struct ') or sline.startswith('union ') or sline.startswith('enum '):
print "'%s' : {'body' : '%s',\n'members' : {" % (line.split()[1], line.split()[0])
elif sline.startswith('}'):
print '}},'
else:
if len(sline.split()) > 1:
name, type = sline.split()[:2]
if type.startswith('List('):
type = type.replace('List(', 'List[').replace(')', ']').replace('[.', '[')
if type.startswith('.'):
type = type[1:]
print ' ', "'%s' : {'type' : '%s'}," % (name, type)
else:
print ' ', "'%s' : {}," % sline.split()[0]