├── .flowconfig ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── gulpfile.babel.js ├── integration ├── .gitignore ├── schema │ ├── generic.capnp │ ├── group.capnp │ └── plain.capnp └── test │ ├── plain-b.js │ └── plain-r.js ├── package-lock.json ├── package.json ├── src ├── Index.js ├── Printer.js ├── Visitor.js ├── bin │ └── flow.js ├── codeGeneratorRespond.js ├── schema.capnp-r.js ├── serialization │ ├── accumulateBuilderLibs.js │ ├── accumulateLocals.js │ ├── accumulateParameters.js │ ├── accumulateReaderLibs.js │ ├── accumulateUsers.js │ ├── accumulateValues.js │ ├── generate.js │ ├── libs.js │ ├── printBuilderBodies.js │ ├── printBuilderInstantiations.js │ ├── printReaderBodies.js │ └── printReaderInstantiations.js └── util │ ├── NonRepeats.js │ ├── capitalize.js │ ├── flatMap.js │ └── paramName.js └── test ├── .gitignore └── schema ├── const-bool.capnp ├── const-data.capnp ├── const-enum.capnp ├── const-float32.capnp ├── const-float64.capnp ├── const-genericStructBoolList.capnp ├── const-genericStructInt16List.capnp ├── const-genericStructStruct.capnp ├── const-genericStructText.capnp ├── const-int16.capnp ├── const-int32.capnp ├── const-int64.capnp ├── const-int8.capnp ├── const-listBool.capnp ├── const-listData.capnp ├── const-listFloat32.capnp ├── const-listFloat64.capnp ├── const-listInt16.capnp ├── const-listInt32.capnp ├── const-listInt64.capnp ├── const-listInt8.capnp ├── const-listText.capnp ├── const-listUint16.capnp ├── const-listUint32.capnp ├── const-listUint64.capnp ├── const-listUint8.capnp ├── const-listVoid.capnp ├── const-struct.capnp ├── const-text.capnp ├── const-uint16.capnp ├── const-uint32.capnp ├── const-uint64.capnp ├── const-uint8.capnp ├── const-void.capnp ├── defField-bool.capnp ├── defField-data.capnp ├── defField-enum.capnp ├── defField-float32.capnp ├── defField-float64.capnp ├── defField-genericStructBoolList.capnp ├── defField-genericStructInt16List.capnp ├── defField-genericStructStruct.capnp ├── defField-genericStructText.capnp ├── defField-int16.capnp ├── defField-int32.capnp ├── defField-int64.capnp ├── defField-int8.capnp ├── defField-listBool.capnp ├── defField-listData.capnp ├── defField-listFloat32.capnp ├── defField-listFloat64.capnp ├── defField-listInt16.capnp ├── defField-listInt32.capnp ├── defField-listInt64.capnp ├── defField-listInt8.capnp ├── defField-listText.capnp ├── defField-listUint16.capnp ├── defField-listUint32.capnp ├── defField-listUint64.capnp ├── defField-listUint8.capnp ├── defField-listVoid.capnp ├── defField-struct.capnp ├── defField-text.capnp ├── defField-uint16.capnp ├── defField-uint32.capnp ├── defField-uint64.capnp ├── defField-uint8.capnp ├── defField-void.capnp ├── field-bool.capnp ├── field-data.capnp ├── field-enum.capnp ├── field-float32.capnp ├── field-float64.capnp ├── field-genericStructBoolList.capnp ├── field-genericStructInt16List.capnp ├── field-genericStructStruct.capnp ├── field-genericStructText.capnp ├── field-int16.capnp ├── field-int32.capnp ├── field-int64.capnp ├── field-int8.capnp ├── field-listBool.capnp ├── field-listData.capnp ├── field-listFloat32.capnp ├── field-listFloat64.capnp ├── field-listInt16.capnp ├── field-listInt32.capnp ├── field-listInt64.capnp ├── field-listInt8.capnp ├── field-listText.capnp ├── field-listUint16.capnp ├── field-listUint32.capnp ├── field-listUint64.capnp ├── field-listUint8.capnp ├── field-listVoid.capnp ├── field-struct.capnp ├── field-text.capnp ├── field-uint16.capnp ├── field-uint32.capnp ├── field-uint64.capnp ├── field-uint8.capnp ├── field-void.capnp ├── union1.capnp └── union2.capnp /.flowconfig: -------------------------------------------------------------------------------- 1 | [options] 2 | esproposal.optional_chaining=enable 3 | 4 | [ignore] 5 | /src/old/.* 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /lib/ 2 | /node_modules/ 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | browser/ 2 | src/ 3 | test/ 4 | 5 | .babelrc 6 | .flowconfig 7 | .gitignore 8 | .npmignore 9 | gulpfile.babel.js 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 capnp-js 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | [Install](https://capnproto.org/install.html) the Cap'n Proto compiler. 3 | Install the plugin locally: 4 | 5 | ```npm install --save-dev @capnp-js/plugin``` 6 | 7 | # Use 8 | Under a local installation the plugin will not be part of your path, but npm scripts will add the locally installed plugin to your path during execution. 9 | Invoke the Cap'n Proto compiler within your `package.json` file's scripts. 10 | Typically this looks like `"compile": "capnp compile -o flow-js ..."`. 11 | -------------------------------------------------------------------------------- /gulpfile.babel.js: -------------------------------------------------------------------------------- 1 | import { exec } from "child_process"; 2 | import del from "del"; 3 | import gulp from "gulp"; 4 | import babel from "gulp-babel"; 5 | import eslint from "gulp-eslint"; 6 | import ext from "gulp-ext-replace"; 7 | import jscc from "gulp-jscc"; 8 | 9 | const eslintConfig = { 10 | "parser": "babel-eslint", 11 | "plugins": ["flowtype"], 12 | "rules": { 13 | "comma-dangle": [2, "always-multiline"], 14 | "semi": 2, 15 | "no-unexpected-multiline": 1, 16 | "no-underscore-dangle": 0, 17 | "space-infix-ops": 0, 18 | "no-multi-spaces": 0, 19 | "no-unused-vars": 1, 20 | "comma-spacing": 1, 21 | "no-use-before-define": 0, 22 | "eol-last": 0, 23 | "no-extra-semi": 0, 24 | "curly": 0, 25 | "dot-notation": 0, 26 | "no-shadow": 0, 27 | "no-proto": 0, 28 | "flowtype/boolean-style": [2, "boolean"], 29 | "flowtype/define-flow-type": 1, 30 | "flowtype/delimiter-dangle": [2, "always-multiline"], 31 | "flowtype/generic-spacing": [2, "never"], 32 | "flowtype/no-dupe-keys": 2, 33 | "flowtype/no-primitive-constructor-types": 2, 34 | "flowtype/no-types-missing-file-annotation": 0, 35 | "flowtype/no-unused-expressions": 2, 36 | "flowtype/no-weak-types": 2, 37 | "flowtype/object-type-delimiter": "comma", 38 | "flowtype/require-parameter-type": 0, 39 | "flowtype/require-return-type": 0, 40 | "flowtype/require-valid-file-annotation": [ 41 | 2, 42 | "always", 43 | {"annotationStyle": "block"}, 44 | ], 45 | "flowtype/semi": 2, 46 | "flowtype/space-after-type-colon": [2, "always"], 47 | "flowtype/space-before-generic-bracket": [2, "never"], 48 | "flowtype/space-before-type-colon": [2, "never"], 49 | "flowtype/union-intersection-spacing": [2, "always"], 50 | "flowtype/use-flow-type": 1, //TODO: What the hell does this do? 51 | }, 52 | "settings": { 53 | "flowtype": {"onlyFilesWithFlowAnnotation": false}, 54 | }, 55 | }; 56 | 57 | // `clean` task 58 | 59 | export function clean() { 60 | return del([ 61 | "lib/", 62 | "integration/*.js", 63 | "test/*.js", 64 | ], {force: true}); 65 | } 66 | 67 | 68 | // `lib`... 69 | 70 | export function lib() { 71 | const presets = [["@babel/preset-env", {targets: {node: "8.9"}, modules: "commonjs"}]]; 72 | 73 | return gulp.src("src/**/*.js") 74 | .pipe(eslint(eslintConfig)) 75 | .pipe(eslint.format()) 76 | .pipe(eslint.failAfterError()) 77 | .pipe(jscc({ values: { _DEBUG: process.env.DEBUG } })) 78 | .pipe(babel({plugins: ["@babel/transform-flow-strip-types"], presets})) 79 | .pipe(gulp.dest("lib/")); 80 | } 81 | 82 | export function lint() { 83 | return gulp.src(["test/*.js", "integration/*.js"]) 84 | .pipe(eslint(eslintConfig)) 85 | .pipe(eslint.format()) 86 | .pipe(eslint.failAfterError()); 87 | } 88 | 89 | export function compile() { 90 | function test(filename) { 91 | const plugin = process.env.PWD + "/lib/bin/flow.js"; 92 | return new Promise((resolve, reject) => { 93 | exec( 94 | `capnp compile --src-prefix test/schema -o ${plugin}:test ${process.env.PWD}/test/schema/${filename}`, 95 | (error, stdout, stderr) => { 96 | if (error !== null && error.code !== 0) { 97 | console.log("stdout: " + stdout); 98 | console.log("stderr: " + stderr); 99 | reject(error.code); 100 | } else { 101 | resolve(0); 102 | } 103 | }, 104 | ); 105 | }); 106 | } 107 | 108 | function integration(filename) { 109 | const plugin = process.env.PWD + "/lib/bin/flow.js"; 110 | return new Promise((resolve, reject) => { 111 | exec( 112 | `capnp compile --src-prefix integration/schema -o ${plugin}:integration ${process.env.PWD}/integration/schema/${filename}`, 113 | (error, stdout, stderr) => { 114 | if (error !== null && error.code !== 0) { 115 | console.log("stdout: " + stdout); 116 | console.log("stderr: " + stderr); 117 | reject(error.code); 118 | } else { 119 | resolve(0); 120 | } 121 | }, 122 | ); 123 | }); 124 | } 125 | 126 | const integrations = Promise.all([ 127 | integration("generic.capnp"), 128 | integration("group.capnp"), 129 | integration("plain.capnp"), 130 | ]); 131 | 132 | const tests = Promise.all([ 133 | test("const-void.capnp"), 134 | test("const-bool.capnp"), 135 | test("const-int8.capnp"), 136 | test("const-int16.capnp"), 137 | test("const-int32.capnp"), 138 | test("const-int64.capnp"), 139 | test("const-uint8.capnp"), 140 | test("const-uint16.capnp"), 141 | test("const-uint32.capnp"), 142 | test("const-uint64.capnp"), 143 | test("const-float32.capnp"), 144 | test("const-float64.capnp"), 145 | test("const-text.capnp"), 146 | test("const-data.capnp"), 147 | test("const-listVoid.capnp"), 148 | test("const-listBool.capnp"), 149 | test("const-listInt8.capnp"), 150 | test("const-listInt16.capnp"), 151 | test("const-listInt32.capnp"), 152 | test("const-listInt64.capnp"), 153 | test("const-listUint8.capnp"), 154 | test("const-listUint16.capnp"), 155 | test("const-listUint32.capnp"), 156 | test("const-listUint64.capnp"), 157 | test("const-listFloat32.capnp"), 158 | test("const-listFloat64.capnp"), 159 | test("const-listText.capnp"), 160 | test("const-listData.capnp"), 161 | test("const-enum.capnp"), 162 | test("const-struct.capnp"), 163 | test("const-genericStructBoolList.capnp"), 164 | test("const-genericStructInt16List.capnp"), 165 | test("const-genericStructStruct.capnp"), 166 | test("const-genericStructText.capnp"), 167 | test("field-void.capnp"), 168 | test("field-bool.capnp"), 169 | test("field-int8.capnp"), 170 | test("field-int16.capnp"), 171 | test("field-int32.capnp"), 172 | test("field-int64.capnp"), 173 | test("field-uint8.capnp"), 174 | test("field-uint16.capnp"), 175 | test("field-uint32.capnp"), 176 | test("field-uint64.capnp"), 177 | test("field-float32.capnp"), 178 | test("field-float64.capnp"), 179 | test("field-text.capnp"), 180 | test("field-data.capnp"), 181 | test("field-listVoid.capnp"), 182 | test("field-listBool.capnp"), 183 | test("field-listInt8.capnp"), 184 | test("field-listInt16.capnp"), 185 | test("field-listInt32.capnp"), 186 | test("field-listInt64.capnp"), 187 | test("field-listUint8.capnp"), 188 | test("field-listUint16.capnp"), 189 | test("field-listUint32.capnp"), 190 | test("field-listUint64.capnp"), 191 | test("field-listFloat32.capnp"), 192 | test("field-listFloat64.capnp"), 193 | test("field-listText.capnp"), 194 | test("field-listData.capnp"), 195 | test("field-enum.capnp"), 196 | test("field-struct.capnp"), 197 | test("field-genericStructBoolList.capnp"), 198 | test("field-genericStructInt16List.capnp"), 199 | test("field-genericStructStruct.capnp"), 200 | test("field-genericStructText.capnp"), 201 | test("defField-void.capnp"), 202 | test("defField-bool.capnp"), 203 | test("defField-int8.capnp"), 204 | test("defField-int16.capnp"), 205 | test("defField-int32.capnp"), 206 | test("defField-int64.capnp"), 207 | test("defField-uint8.capnp"), 208 | test("defField-uint16.capnp"), 209 | test("defField-uint32.capnp"), 210 | test("defField-uint64.capnp"), 211 | test("defField-float32.capnp"), 212 | test("defField-float64.capnp"), 213 | test("defField-text.capnp"), 214 | test("defField-data.capnp"), 215 | test("defField-listVoid.capnp"), 216 | test("defField-listBool.capnp"), 217 | test("defField-listInt8.capnp"), 218 | test("defField-listInt16.capnp"), 219 | test("defField-listInt32.capnp"), 220 | test("defField-listInt64.capnp"), 221 | test("defField-listUint8.capnp"), 222 | test("defField-listUint16.capnp"), 223 | test("defField-listUint32.capnp"), 224 | test("defField-listUint64.capnp"), 225 | test("defField-listFloat32.capnp"), 226 | test("defField-listFloat64.capnp"), 227 | test("defField-listText.capnp"), 228 | test("defField-listData.capnp"), 229 | test("defField-enum.capnp"), 230 | test("defField-struct.capnp"), 231 | test("defField-genericStructBoolList.capnp"), 232 | test("defField-genericStructInt16List.capnp"), 233 | test("defField-genericStructStruct.capnp"), 234 | test("defField-genericStructText.capnp"), 235 | test("union1.capnp"), 236 | test("union2.capnp"), 237 | ]); 238 | 239 | return Promise.all([ 240 | integrations, 241 | tests, 242 | ]); 243 | } 244 | -------------------------------------------------------------------------------- /integration/.gitignore: -------------------------------------------------------------------------------- 1 | /*.js 2 | -------------------------------------------------------------------------------- /integration/schema/generic.capnp: -------------------------------------------------------------------------------- 1 | @0xe3a048f5756763dd; 2 | 3 | struct Trivial {} 4 | 5 | const a :Text = "a"; 6 | const b :Trivial = (); 7 | const c :List(Text) = ["c"]; 8 | 9 | struct FirstNongeneric { 10 | struct FirstGeneric(A, B) { 11 | struct SecondNongeneric { 12 | struct SecondGeneric(X) { 13 | sg0 @0 :B; 14 | sg1 @1 :X; 15 | } 16 | interface J(Y) { 17 | struct Inner {} 18 | a @0 (j1 :Int16, j2 :Y, j3 :A) -> (r1 :Data, r2 :AnyPointer); 19 | } 20 | fg0 @0 :A; 21 | } 22 | defAnyS @0 :AnyStruct = .b; 23 | defAnyL @1 :AnyList = .c; 24 | } 25 | someAnyP @0 :AnyPointer; 26 | someAnyS @1 :AnyStruct; 27 | union { 28 | someAnyL @2 :AnyList; 29 | someNumber @3 :UInt32 = 12; 30 | } 31 | 32 | interface I { 33 | p @0 () -> (result: Trivial); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /integration/schema/group.capnp: -------------------------------------------------------------------------------- 1 | @0x8837f94efa34b445; 2 | 3 | struct S(A,B) { 4 | a :group { 5 | uint8 @0 :UInt8; 6 | paramA @1 :A; 7 | } 8 | b :group { 9 | int32 @2 :Int32; 10 | data @3 :Data; 11 | } 12 | c :union { 13 | f1 @4 :Int8; 14 | f2 @5 :Int8; 15 | d :union { 16 | f3 @6 :Int8; 17 | paramB @7 :B; 18 | } 19 | } 20 | union { 21 | g1 @8 :Int8; 22 | e :union { 23 | g2 @9 :Int8; 24 | paramB @10 :B; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /integration/schema/plain.capnp: -------------------------------------------------------------------------------- 1 | @0x9a476aab458f8e81; 2 | 3 | struct Leaves { 4 | void @0 :Void = void; 5 | bool @1 :Bool = true; 6 | uint8 @2 :UInt8 = 253; 7 | uint16 @3 :UInt16 = 65531; 8 | uint32 @4 :UInt32 = 4294967123; 9 | uint64 @5 :UInt64 = 18446744073709551602; 10 | int8 @6 :Int8 = -119; 11 | int16 @7 :Int16 = -32612; 12 | int32 @8 :Int32 = -2147483102; 13 | int64 @9 :Int64 = -9223372036854775712; 14 | float32 @10 :Float32 = -1923484748.1422; 15 | float64 @11 :Float64 = -1909817719838772387192132987.12343; 16 | data @12 :Data = 0x"11 ab 2e"; 17 | text @13 :Text = "some text"; 18 | } 19 | 20 | struct MaybeLeaves { 21 | void @0 :Void; 22 | bool @1 :Bool; 23 | uint8 @2 :UInt8; 24 | uint16 @3 :UInt16; 25 | uint32 @4 :UInt32; 26 | uint64 @5 :UInt64; 27 | int8 @6 :Int8; 28 | int16 @7 :Int16; 29 | int32 @8 :Int32; 30 | int64 @9 :Int64; 31 | float32 @10 :Float32; 32 | float64 @11 :Float64; 33 | data @12 :Data; 34 | text @13 :Text; 35 | } 36 | -------------------------------------------------------------------------------- /integration/test/plain-b.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import * as assert from "assert"; 4 | import { describe, it } from "mocha"; 5 | import { Limited } from "@capnp-js/base-arena"; 6 | import { Builder } from "@capnp-js/builder-arena"; 7 | import { nonnull } from "@capnp-js/nullary"; 8 | import { inject as injectI64 } from "@capnp-js/int64"; 9 | import { inject as injectU64 } from "@capnp-js/uint64"; 10 | import { Leaves, MaybeLeaves } from "../plain.capnp-b"; 11 | 12 | describe("Leaves", function () { 13 | const arena = Builder.fresh(2000, new Limited(1<<26, 64)); 14 | const leaves = arena.initRoot(Leaves); 15 | 16 | describe("void field", function () { 17 | it("gets value without errors", function () { 18 | assert.doesNotThrow(() => leaves.getVoid()); 19 | }); 20 | 21 | it("sets value without errors", function () { 22 | assert.doesNotThrow(() => leaves.setVoid()); 23 | }); 24 | }); 25 | 26 | describe("bool field", function () { 27 | it("gets the default field value if the field is not set", function () { 28 | assert.equal(leaves.getBool(), true); 29 | }); 30 | 31 | it("sets the field value", function () { 32 | it("exposes bool fields", function () { 33 | leaves.setBool(false); 34 | assert.equal(leaves.getBool(), false); 35 | }); 36 | }); 37 | }) 38 | 39 | describe("uint8 field", function () { 40 | it("gets the default field value if the field is not set", function () { 41 | assert.equal(leaves.getUint8(), 253); 42 | }); 43 | 44 | it("sets the field value", function () { 45 | leaves.setUint8(12); 46 | assert.equal(leaves.getUint8(), 12); 47 | }); 48 | }); 49 | 50 | describe("uint16 field", function () { 51 | it("gets the default field value if the field is not set", function () { 52 | assert.equal(leaves.getUint16(), 65531); 53 | }); 54 | 55 | it("sets the field value", function () { 56 | leaves.setUint16(23000); 57 | assert.equal(leaves.getUint16(), 23000); 58 | }); 59 | }); 60 | 61 | describe("uint32 field", function () { 62 | it("gets the default field value if the field is not set", function () { 63 | assert.equal(leaves.getUint32(), 4294967123); 64 | }); 65 | 66 | it("sets the field value", function () { 67 | leaves.setUint32(18374747); 68 | assert.equal(leaves.getUint32(), 18374747); 69 | }); 70 | }); 71 | 72 | describe("uint64 field", function () { 73 | it("gets the default field value if the field is not set", function () { 74 | const def = leaves.getUint64(); 75 | assert.equal(def[0], 0xffffffff); 76 | assert.equal(def[1], 0xfffffff2); 77 | }); 78 | 79 | it("sets the field value", function () { 80 | leaves.setUint64(injectU64(0x00942983, 0x01989383)); 81 | const value = leaves.getUint64(); 82 | assert.equal(value[0], 0x00942983); 83 | assert.equal(value[1], 0x01989383); 84 | }); 85 | }); 86 | 87 | describe("int8 field", function () { 88 | it("gets the default field value if the field is not set", function () { 89 | assert.equal(leaves.getInt8(), -119); 90 | }); 91 | 92 | it("sets the field value", function () { 93 | leaves.setInt8(12); 94 | assert.equal(leaves.getInt8(), 12); 95 | }); 96 | }); 97 | 98 | describe("int16 field", function () { 99 | it("gets the default field value if the field is not set", function () { 100 | assert.equal(leaves.getInt16(), -32612); 101 | }); 102 | 103 | it("sets the field value", function () { 104 | leaves.setInt16(-800); 105 | assert.equal(leaves.getInt16(), -800); 106 | }); 107 | }); 108 | 109 | describe("int32 field", function () { 110 | it("gets the default field value if the field is not set", function () { 111 | assert.equal(leaves.getInt32(), -2147483102); 112 | }); 113 | 114 | it("sets the field value", function () { 115 | leaves.setInt32(-918733); 116 | assert.equal(leaves.getInt32(), -918733); 117 | }); 118 | }); 119 | 120 | describe("int64 field", function () { 121 | it("gets the default field value if the field is not set", function () { 122 | const def = leaves.getInt64(); 123 | assert.equal(def[0], -0x80000000); 124 | assert.equal(def[1], 0x60); 125 | }); 126 | 127 | it("sets the field value", function () { 128 | leaves.setInt64(injectI64(-0x01837400, 0x91737333)); 129 | const value = leaves.getInt64(); 130 | assert.equal(value[0], -0x01837400); 131 | assert.equal(value[1], 0x91737333); 132 | }); 133 | }); 134 | 135 | describe("float32 field", function () { 136 | it("gets the default field value if the field is not set", function () { 137 | const epsilon = Math.pow(2, -24); 138 | const v = -1923484748.1422; 139 | assert.ok(Math.abs(v - leaves.getFloat32()) < Math.abs(v*epsilon)); 140 | }); 141 | 142 | it("sets the field value", function () { 143 | const epsilon = Math.pow(2, -24); 144 | const v = 89.437462763762; 145 | leaves.setFloat32(v); 146 | assert.ok(Math.abs(v - leaves.getFloat32()) < Math.abs(v*epsilon)); 147 | }); 148 | }); 149 | 150 | describe("float64 field", function () { 151 | it("gets the default field value if the field is not set", function () { 152 | const epsilon = Math.pow(2, -53); 153 | const v = -1909817719838772387192132987.12343; 154 | assert.ok(Math.abs(v - leaves.getFloat64()) < Math.abs(v*epsilon)); 155 | }); 156 | 157 | it("sets the field value", function () { 158 | const epsilon = Math.pow(2, -53); 159 | const v = -1947476828222.2742874928239892; 160 | leaves.setFloat64(v); 161 | assert.ok(Math.abs(v - leaves.getFloat64()) < Math.abs(v*epsilon)); 162 | }); 163 | }); 164 | 165 | describe("data field", function () { 166 | it("gets the default field value if the field is not set", function () { 167 | assert.equal(nonnull(arena.getRoot()).getAs(MaybeLeaves).getData(), null); 168 | const def = leaves.getData().asBytes(); 169 | assert.equal(def[0], 0x11); 170 | assert.equal(def[1], 0xab); 171 | assert.equal(def[2], 0x2e); 172 | assert.equal(def.length, 3); 173 | leaves.disownData(); 174 | }); 175 | 176 | it("gets the field value", function () { 177 | leaves.adoptData(arena.initData(2)); 178 | assert.notEqual(nonnull(arena.getRoot()).getAs(MaybeLeaves).getData(), null); 179 | const data = leaves.getData().asBytes(); 180 | data[0] = 0xfc; 181 | data[1] = 0x53; 182 | assert.equal(data[0], 0xfc); 183 | assert.equal(data[1], 0x53); 184 | assert.equal(data.length, 2); 185 | leaves.disownData(); 186 | }); 187 | 188 | it("disowns the default field value if the field is not set", function () { 189 | const maybes = nonnull(arena.getRoot()).getAs(MaybeLeaves); 190 | assert.equal(maybes.getData(), null); 191 | const orphan = leaves.disownData(); 192 | assert.equal(maybes.getData(), null); 193 | leaves.adoptData(orphan); 194 | assert.notEqual(maybes.getData(), null); 195 | const data = leaves.getData().asBytes(); 196 | assert.equal(data[0], 0x11); 197 | assert.equal(data[1], 0xab); 198 | assert.equal(data[2], 0x2e); 199 | assert.equal(data.length, 3); 200 | leaves.disownData(); 201 | }); 202 | 203 | it("disowns the field value", function () { 204 | const maybes = nonnull(arena.getRoot()).getAs(MaybeLeaves); 205 | assert.equal(maybes.getData(), null); 206 | leaves.adoptData(arena.initData(2)); 207 | assert.notEqual(maybes.getData(), null); 208 | const orphan = leaves.disownData(); 209 | assert.equal(maybes.getData(), null); 210 | leaves.adoptData(orphan); 211 | assert.notEqual(maybes.getData(), null); 212 | assert.equal(leaves.getData().asBytes().length, 2); 213 | }); 214 | 215 | it("sets the field value", function () { 216 | leaves.adoptData(arena.initData(1)); 217 | const value = leaves.getData(); 218 | leaves.disownData(); 219 | const maybes = nonnull(arena.getRoot()).getAs(MaybeLeaves); 220 | assert.equal(maybes.getData(), null); 221 | leaves.setData(value); 222 | assert.equal(leaves.getData().asBytes().length, 1); 223 | leaves.disownData(); 224 | }); 225 | 226 | it("adopts the field value", function () { 227 | leaves.adoptData(arena.initData(5)); 228 | assert.equal(leaves.getData().asBytes().length, 5); 229 | leaves.disownData(); 230 | }); 231 | 232 | it("rejects attached orphans from adoption", function () { 233 | const orphan = arena.initData(4); 234 | assert.ok(orphan.isDetached()); 235 | leaves.adoptData(orphan); 236 | assert.ok(!orphan.isDetached()); 237 | assert.throws(() => leaves.adoptData(orphan)); 238 | leaves.disownData(); 239 | }); 240 | }); 241 | 242 | describe("text field", function () { 243 | it("gets the default field value if the field is not set", function () { 244 | assert.equal(nonnull(arena.getRoot()).getAs(MaybeLeaves).getText(), null); 245 | assert.equal(leaves.getText().toString(), "some text"); 246 | leaves.disownText(); 247 | }); 248 | 249 | it("gets the field value", function () { 250 | leaves.adoptText(arena.initText("new text")); 251 | assert.notEqual(nonnull(arena.getRoot()).getAs(MaybeLeaves).getText(), null); 252 | const text = leaves.getText().toString(); 253 | assert.equal(text, "new text"); 254 | leaves.disownText(); 255 | }); 256 | 257 | it("disowns the default field value if the field is not set", function () { 258 | const maybes = nonnull(arena.getRoot()).getAs(MaybeLeaves); 259 | assert.equal(maybes.getText(), null); 260 | const orphan = leaves.disownText(); 261 | assert.equal(maybes.getText(), null); 262 | leaves.adoptText(orphan); 263 | assert.notEqual(maybes.getText(), null); 264 | const text = leaves.getText().toString(); 265 | assert.equal(text, "some text"); 266 | leaves.disownText(); 267 | }); 268 | 269 | it("disowns the field value", function () { 270 | const maybes = nonnull(arena.getRoot()).getAs(MaybeLeaves); 271 | assert.equal(maybes.getText(), null); 272 | leaves.adoptText(arena.initText("different text")); 273 | assert.notEqual(maybes.getText(), null); 274 | const orphan = leaves.disownText(); 275 | assert.equal(maybes.getText(), null); 276 | leaves.adoptText(orphan); 277 | assert.notEqual(maybes.getText(), null); 278 | assert.equal(leaves.getText().toString(), "different text"); 279 | }); 280 | 281 | it("sets the field value", function () { 282 | leaves.adoptText(arena.initText("more text")); 283 | const value = leaves.getText(); 284 | leaves.disownText(); 285 | const maybes = nonnull(arena.getRoot()).getAs(MaybeLeaves); 286 | assert.equal(maybes.getText(), null); 287 | leaves.setText(value); 288 | assert.equal(leaves.getText().toString(), "more text"); 289 | leaves.disownText(); 290 | }); 291 | 292 | it("adopts the field value", function () { 293 | leaves.adoptText(arena.initText("some string")); 294 | assert.equal(leaves.getText().toString(), "some string"); 295 | leaves.disownText(); 296 | }); 297 | 298 | it("rejects attached orphans from adoption", function () { 299 | const orphan = arena.initText("yet another string"); 300 | assert.ok(orphan.isDetached()); 301 | leaves.adoptText(orphan); 302 | assert.ok(!orphan.isDetached()); 303 | assert.throws(() => leaves.adoptText(orphan)); 304 | leaves.disownText(); 305 | }); 306 | }); 307 | }); 308 | -------------------------------------------------------------------------------- /integration/test/plain-r.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { Leaves } from "../plain.capnp-r"; 4 | 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@capnp-js/plugin", 3 | "version": "0.4.0", 4 | "description": "Cap'n Proto code generator", 5 | "main": "lib/index", 6 | "bin": { 7 | "capnpc-flow-js": "lib/bin/flow.js" 8 | }, 9 | "scripts": { 10 | "build": "gulp lib", 11 | "refresh": "rm -f package-lock.json && npm run clean && npm unpublish --force && rm -rf node_modules/@capnp-js && npm run build && npm publish", 12 | "clean": "gulp clean", 13 | "compile-schema": "gulp compile && gulp lint", 14 | "test-flow": "flow check --merge-timeout 0 --strip-root --show-all-errors --color=always src", 15 | "test-integration": "mocha --require @babel/register integration/test", 16 | "test": "npm run test-flow && npm run test-integration", 17 | "start-flow": "flow start --merge-timeout 20000", 18 | "flow": "flow", 19 | "stop-flow": "flow stop" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/capnp-js/capnp-js-plugin.git" 24 | }, 25 | "keywords": [ 26 | "capnproto", 27 | "capnp", 28 | "capnpc" 29 | ], 30 | "author": "Tim Popham", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/capnp-js/capnp-js-plugin/issues" 34 | }, 35 | "homepage": "https://github.com/capnp-js/capnp-js-plugin", 36 | "devDependencies": { 37 | "@babel/core": "^7.1.6", 38 | "@babel/preset-env": "^7.1.6", 39 | "@babel/preset-flow": "^7.0.0", 40 | "@babel/register": "^7.0.0", 41 | "babel-eslint": "^10.0.1", 42 | "del": "^3.0.0", 43 | "eslint-plugin-flowtype": "^3.2.0", 44 | "flow-bin": "^0.93.0", 45 | "gulp": "^4.0.0", 46 | "gulp-babel": "^8.0.0", 47 | "gulp-eslint": "^5.0.0", 48 | "gulp-ext-replace": "^0.3.0", 49 | "gulp-jscc": "^1.2.0", 50 | "mocha": "^5.2.0" 51 | }, 52 | "dependencies": { 53 | "@capnp-js/base-arena": "^0.4.0", 54 | "@capnp-js/builder-arena": "^0.4.0", 55 | "@capnp-js/bytes": "^0.4.0", 56 | "@capnp-js/int64": "^0.4.0", 57 | "@capnp-js/layout": "^0.4.0", 58 | "@capnp-js/memory": "^0.4.0", 59 | "@capnp-js/nullary": "^0.4.0", 60 | "@capnp-js/read-data": "^0.4.0", 61 | "@capnp-js/reader-arena": "^0.4.0", 62 | "@capnp-js/trans-align-bytes": "^0.4.0", 63 | "@capnp-js/trans-base64": "^0.4.0", 64 | "@capnp-js/trans-concat": "^0.4.0", 65 | "@capnp-js/trans-inject": "^0.4.0", 66 | "@capnp-js/trans-packing": "^0.4.0", 67 | "@capnp-js/trans-readable": "^0.4.0", 68 | "@capnp-js/trans-stream": "^0.4.0", 69 | "@capnp-js/uint64": "^0.4.0" 70 | }, 71 | "babel": { 72 | "presets": [ 73 | [ 74 | "@babel/preset-env", 75 | { 76 | "targets": { 77 | "node": "8.9" 78 | }, 79 | "modules": "commonjs" 80 | } 81 | ] 82 | ], 83 | "plugins": [ 84 | "@babel/transform-flow-strip-types" 85 | ] 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type { StructListR } from "@capnp-js/reader-core"; 4 | import type { UInt64 } from "@capnp-js/uint64"; 5 | 6 | import type { Node__InstanceR } from "./schema.capnp-r"; 7 | 8 | import { nonnull } from "@capnp-js/nullary"; 9 | import { toHex } from "@capnp-js/uint64"; 10 | 11 | import { Field, Node } from "./schema.capnp-r"; 12 | 13 | export type Scope = { 14 | +name: string, 15 | +node: Node__InstanceR, 16 | }; 17 | 18 | type ScopesIndex = { [uuid: string]: $ReadOnlyArray }; 19 | 20 | class BootstrapVisitor { 21 | +nodesIndex: { [uuid: string]: Node__InstanceR }; 22 | 23 | constructor(nodes: StructListR) { 24 | this.nodesIndex = {}; 25 | nodes.forEach(node => { 26 | this.nodesIndex[toHex(node.getId())] = node; 27 | }); 28 | } 29 | 30 | visit(scopes: $ReadOnlyArray, id: UInt64, scopesIndex: ScopesIndex): void { 31 | const node = this.nodesIndex[toHex(id)]; 32 | if (!node) { 33 | return; 34 | } 35 | 36 | switch (node.tag()) { 37 | case Node.tags.file: 38 | this.file(scopes, node, scopesIndex); 39 | break; 40 | case Node.tags.struct: 41 | this.struct(scopes, node, scopesIndex); 42 | break; 43 | case Node.tags.enum: 44 | this.enum(scopes, node, scopesIndex); 45 | break; 46 | case Node.tags.interface: 47 | this.interface(scopes, node, scopesIndex); 48 | break; 49 | case Node.tags.const: 50 | this.const(scopes, node, scopesIndex); 51 | break; 52 | case Node.tags.annotation: 53 | this.annotation(scopes, node, scopesIndex); 54 | break; 55 | default: throw new Error("Unrecognized node tag."); 56 | } 57 | 58 | const nestedNodes = node.getNestedNodes(); 59 | if (nestedNodes !== null) { 60 | nestedNodes.forEach(nestedNode => { 61 | const name = nonnull(nestedNode.getName()).toString(); 62 | const id = nestedNode.getId(); 63 | const nestedScope = scopes.slice(0); 64 | nestedScope.push({ 65 | name, 66 | node: this.nodesIndex[toHex(id)], 67 | }); 68 | 69 | this.visit(nestedScope, id, scopesIndex); 70 | }); 71 | } 72 | } 73 | 74 | file(scopes: $ReadOnlyArray, node: Node__InstanceR, scopesIndex: ScopesIndex): void { 75 | const uuid = toHex(node.getId()); 76 | scopesIndex[uuid] = scopes; 77 | } 78 | 79 | struct(scopes: $ReadOnlyArray, node: Node__InstanceR, scopesIndex: ScopesIndex): void { 80 | const uuid = toHex(node.getId()); 81 | scopesIndex[uuid] = scopes; 82 | 83 | const fields = node.getStruct().getFields(); 84 | if (fields !== null) { 85 | fields.forEach(field => { 86 | if (field.tag() === Field.tags.group) { 87 | const name = nonnull(field.getName()).toString(); 88 | const id = field.getGroup().getTypeId(); 89 | const groupScope = scopes.slice(0); 90 | groupScope.push({ 91 | name, 92 | node: this.nodesIndex[toHex(id)], 93 | }); 94 | 95 | this.visit(groupScope, id, scopesIndex); 96 | } 97 | }); 98 | } 99 | } 100 | 101 | enum(scopes: $ReadOnlyArray, node: Node__InstanceR, scopesIndex: ScopesIndex): void { 102 | const uuid = toHex(node.getId()); 103 | scopesIndex[uuid] = scopes; 104 | } 105 | 106 | interface(scopes: $ReadOnlyArray, node: Node__InstanceR, scopesIndex: ScopesIndex): void { 107 | const uuid = toHex(node.getId()); 108 | scopesIndex[uuid] = scopes; 109 | 110 | const methods = node.getInterface().getMethods(); 111 | if (methods !== null) { 112 | methods.forEach(method => { 113 | const paramId = method.getParamStructType(); 114 | const param = this.nodesIndex[toHex(paramId)]; 115 | const paramScopeId = param.getScopeId(); 116 | if (paramScopeId[0] === 0 && paramScopeId[1] === 0) { 117 | const name = nonnull(method.getName()).toString(); 118 | const methodScope = scopes.slice(0); 119 | methodScope.push({ 120 | name, 121 | node: this.nodesIndex[toHex(paramId)], 122 | }); 123 | 124 | this.visit(methodScope, paramId, scopesIndex); 125 | } 126 | 127 | const resultId = method.getResultStructType(); 128 | const result = this.nodesIndex[toHex(resultId)]; 129 | const resultScopeId = result.getScopeId(); 130 | if (resultScopeId[0] === 0 && resultScopeId[1] === 0) { 131 | const name = nonnull(method.getName()).toString(); 132 | const methodScope = scopes.slice(0); 133 | methodScope.push({ 134 | name, 135 | node: this.nodesIndex[toHex(resultId)], 136 | }); 137 | 138 | this.visit(methodScope, resultId, scopesIndex); 139 | } 140 | }); 141 | } 142 | } 143 | 144 | const(scopes: $ReadOnlyArray, node: Node__InstanceR, scopesIndex: ScopesIndex): void { 145 | const uuid = toHex(node.getId()); 146 | scopesIndex[uuid] = scopes; 147 | } 148 | 149 | annotation(scopes: $ReadOnlyArray, node: Node__InstanceR, scopesIndex: ScopesIndex): void { 150 | const uuid = toHex(node.getId()); 151 | scopesIndex[uuid] = scopes; 152 | } 153 | } 154 | 155 | //TODO: + variance on indexer. 156 | export type ReadOnlyScopesIndex = { [uuid: string]: $ReadOnlyArray }; 157 | 158 | export default class Index { 159 | +scopesIndex: ReadOnlyScopesIndex; 160 | 161 | constructor(nodes: null | StructListR) { 162 | this.scopesIndex = {}; 163 | if (nodes !== null) { 164 | const visitor = new BootstrapVisitor(nodes); 165 | nodes.forEach(node => { 166 | if (node.tag() === Node.tags.file) { 167 | visitor.visit([{ name: "", node }], node.getId(), this.scopesIndex); 168 | } 169 | }); 170 | } 171 | } 172 | 173 | getScopes(id: UInt64 | string): $ReadOnlyArray { 174 | if (typeof id !== "string") { 175 | id = toHex(id); 176 | } 177 | return this.scopesIndex[id]; 178 | } 179 | 180 | getNode(id: UInt64 | string): Node__InstanceR { 181 | if (typeof id !== "string") { 182 | id = toHex(id); 183 | } 184 | const scopes = this.scopesIndex[id]; 185 | return scopes[scopes.length - 1].node; 186 | } 187 | 188 | forEachNode(fn: (node: Node__InstanceR) => mixed) { 189 | for (let uuid in this.scopesIndex) { 190 | const scopes = this.scopesIndex[uuid]; 191 | fn(scopes[scopes.length - 1].node); 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /src/Printer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | /* TODO: Migrate to test and clobber from this compilation unit: 4 | p = new Printer(2); 5 | 6 | p.line("import type { K } from \"./asdf\";"); 7 | p.blank(); 8 | p.block("class SomeClass", p => { 9 | p.line("member: string;"); 10 | p.line("another: K;"); 11 | p.blank(); 12 | p.block("constructor(member: string)", p => { 13 | p.line("this.member = member"); 14 | }); 15 | p.blank(); 16 | p.block("fn(concat: string)", p => { 17 | p.ifElse( 18 | "concat === \"\"", 19 | p => p.line("this.member += \"some default\";"), 20 | p => p.line("this.member += concat") 21 | ); 22 | }); 23 | }); 24 | */ 25 | 26 | //TODO: Generic specialization with Text? The setter variant for `"someString"` 27 | //cannot work, right? So shouldn't I afford a quick `internText` function for 28 | //creating Text outside of any arena for setting? 29 | 30 | type uint = number; 31 | 32 | class Words { 33 | +s: string; 34 | p: uint; 35 | 36 | constructor(s: string) { 37 | this.s = s; 38 | this.p = 0; 39 | while (this.p < this.s.length && this.s.charAt(this.p) === " ") ++this.p; 40 | } 41 | 42 | next(): IteratorResult { 43 | if (this.p === this.s.length) { 44 | return { done: true }; 45 | } else { 46 | let value = ""; 47 | do { 48 | value += this.s.charAt(this.p); 49 | ++this.p; 50 | } while (this.p < this.s.length && this.s.charAt(this.p) !== " "); 51 | 52 | return { done: false, value }; 53 | } 54 | } 55 | } 56 | 57 | export default class Printer { 58 | +indentWidth: uint; 59 | level: uint; 60 | text: string; 61 | interrupted: boolean; 62 | 63 | constructor(indentWidth: uint) { 64 | this.indentWidth = indentWidth; 65 | this.level = 0; 66 | this.text = ""; 67 | this.interrupted = true; 68 | } 69 | 70 | indent(cb: (p: this) => void): void { 71 | ++this.level; 72 | cb(this); 73 | --this.level; 74 | } 75 | 76 | interrupt(): void { 77 | if (!this.interrupted) { 78 | this.text += "\n"; 79 | this.interrupted = true; 80 | } 81 | } 82 | 83 | comment(s: string): void { 84 | let line = " ".repeat(this.level * this.indentWidth) + "/*"; 85 | const words = new Words(s); 86 | for (let w=words.next(); !w.done; w=words.next()) { 87 | if (line.length + 1 + w.value.length < 80) { 88 | line += " "; 89 | line += w.value; 90 | } else { 91 | this.text += line; 92 | this.text += "\n"; 93 | line = " ".repeat(this.level * this.indentWidth) + " * " + w.value; 94 | } 95 | } 96 | 97 | if (line.length + 3 < 80) { 98 | line += " */"; 99 | this.text += line; 100 | this.text += "\n"; 101 | } else { 102 | this.text += line; 103 | this.text += "\n"; 104 | line = " ".repeat(this.level * this.indentWidth) + " */"; 105 | this.text += line; 106 | this.text += "\n"; 107 | } 108 | 109 | this.interrupted = false; 110 | } 111 | 112 | line(s: string): void { 113 | this.text += " ".repeat(this.level * this.indentWidth); 114 | this.text += s; 115 | this.text += "\n"; 116 | 117 | this.interrupted = false; 118 | } 119 | 120 | block(prefix: string, cb: (p: this) => void): void { 121 | this.text += " ".repeat(this.level * this.indentWidth); 122 | this.text += prefix; 123 | if (prefix !== "") { 124 | /* Only add a space when there exists a prefix. */ 125 | this.text += " "; 126 | } 127 | this.text += "{\n"; 128 | 129 | ++this.level; 130 | this.interrupted = true; 131 | cb(this); 132 | --this.level; 133 | 134 | this.text += " ".repeat(this.level * this.indentWidth); 135 | this.text += "}\n"; 136 | 137 | this.interrupted = false; 138 | } 139 | 140 | if(predicate: string, ifCb: (p: this) => void): void { 141 | this.text += " ".repeat(this.level * this.indentWidth); 142 | this.text += "if ("; 143 | this.text += predicate; 144 | this.text += ") {\n"; 145 | 146 | ++this.level; 147 | this.interrupted = true; 148 | ifCb(this); 149 | --this.level; 150 | 151 | this.text += " ".repeat(this.level * this.indentWidth); 152 | this.text += "}\n"; 153 | 154 | this.interrupted = false; 155 | } 156 | 157 | ifElse(predicate: string, ifCb: (p: this) => void, elseCb: (p: this) => void): void { 158 | this.text += " ".repeat(this.level * this.indentWidth); 159 | this.text += "if ("; 160 | this.text += predicate; 161 | this.text += ") {\n"; 162 | 163 | ++this.level; 164 | this.interrupted = true; 165 | ifCb(this); 166 | --this.level; 167 | 168 | this.text += " ".repeat(this.level * this.indentWidth); 169 | this.text += "} else {\n"; 170 | 171 | ++this.level; 172 | this.interrupted = true; 173 | elseCb(this); 174 | --this.level; 175 | 176 | this.text += " ".repeat(this.level * this.indentWidth); 177 | this.text += "}\n"; 178 | 179 | this.interrupted = false; 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/Visitor.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type { UInt64 } from "@capnp-js/uint64"; 4 | import type { Node__InstanceR } from "./schema.capnp-r"; 5 | 6 | import Index from "./Index"; 7 | import { Node } from "./schema.capnp-r"; 8 | 9 | export default class Visitor { 10 | +index: Index; 11 | 12 | constructor(index: Index) { 13 | this.index = index; 14 | } 15 | 16 | visit(id: UInt64, acc: T): T { 17 | const node = this.index.getNode(id); 18 | if (!node) { 19 | return acc; 20 | } 21 | 22 | switch (node.tag()) { 23 | case Node.tags.file: 24 | acc = this.file(node, acc); 25 | break; 26 | case Node.tags.struct: 27 | acc = this.struct(node, acc); 28 | break; 29 | case Node.tags.enum: 30 | acc = this.enum(node, acc); 31 | break; 32 | case Node.tags.interface: 33 | acc = this.interface(node, acc); 34 | break; 35 | case Node.tags.const: 36 | acc = this.const(node, acc); 37 | break; 38 | case Node.tags.annotation: 39 | acc = this.annotation(node, acc); 40 | break; 41 | default: throw new Error("Unrecognized node tag."); 42 | } 43 | 44 | return acc; 45 | } 46 | 47 | file(node: Node__InstanceR, acc: T): T { 48 | const nestedNodes = node.getNestedNodes(); 49 | if (nestedNodes !== null) { 50 | nestedNodes.forEach(nestedNode => { 51 | acc = this.visit(nestedNode.getId(), acc); 52 | }); 53 | } 54 | 55 | return acc; 56 | } 57 | 58 | struct(node: Node__InstanceR, acc: T): T { 59 | const nestedNodes = node.getNestedNodes(); 60 | if (nestedNodes !== null) { 61 | nestedNodes.forEach(nestedNode => { 62 | acc = this.visit(nestedNode.getId(), acc); 63 | }); 64 | } 65 | 66 | /* I don't iterate through the struct's groups in case some subclass chooses 67 | to ignore them. */ 68 | 69 | return acc; 70 | } 71 | 72 | enum(node: Node__InstanceR, acc: T): T { 73 | const nestedNodes = node.getNestedNodes(); 74 | if (nestedNodes !== null) { 75 | nestedNodes.forEach(nestedNode => { 76 | acc = this.visit(nestedNode.getId(), acc); 77 | }); 78 | } 79 | 80 | return acc; 81 | } 82 | 83 | interface(node: Node__InstanceR, acc: T): T { 84 | const nestedNodes = node.getNestedNodes(); 85 | if (nestedNodes !== null) { 86 | nestedNodes.forEach(nestedNode => { 87 | acc = this.visit(nestedNode.getId(), acc); 88 | }); 89 | } 90 | 91 | /* I don't iterate through the interfaces param nor result structs in case 92 | some subclass chooses to ignore them. */ 93 | 94 | return acc; 95 | } 96 | 97 | const(node: Node__InstanceR, acc: T): T { 98 | const nestedNodes = node.getNestedNodes(); 99 | if (nestedNodes !== null) { 100 | nestedNodes.forEach(nestedNode => { 101 | acc = this.visit(nestedNode.getId(), acc); 102 | }); 103 | } 104 | 105 | return acc; 106 | } 107 | 108 | annotation(node: Node__InstanceR, acc: T): T { 109 | const nestedNodes = node.getNestedNodes(); 110 | if (nestedNodes !== null) { 111 | nestedNodes.forEach(nestedNode => { 112 | acc = this.visit(nestedNode.getId(), acc); 113 | }); 114 | } 115 | 116 | return acc; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/bin/flow.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* @flow */ 3 | 4 | import type { Readable } from "@capnp-js/trans-readable"; 5 | 6 | import readable from "@capnp-js/trans-readable"; 7 | import { segmentize } from "@capnp-js/memory"; 8 | import { nonnull } from "@capnp-js/nullary"; 9 | import { Reader } from "@capnp-js/reader-arena"; 10 | import { finishDecode } from "@capnp-js/trans-stream"; 11 | 12 | import { CodeGeneratorRequest } from "../schema.capnp-r"; 13 | 14 | import codeGeneratorRespond from "../codeGeneratorRespond"; 15 | 16 | //TODO: Verify that readable streams work under Node 8 and Node 10 17 | const stdin = ((process.stdin: any): Readable); // eslint-disable-line flowtype/no-weak-types 18 | 19 | const decode = finishDecode((err, raws) => { 20 | if (err) { 21 | process.stderr.write("Failed: " + err.message + "\n"); 22 | } else { 23 | const arena = Reader.limited(segmentize(raws), 1 << 26, 64); 24 | 25 | //TODO: Write an empty file on null? Can null happen? 26 | const root = nonnull(arena.getRoot()); 27 | const request = root.getAs(CodeGeneratorRequest); 28 | 29 | codeGeneratorRespond(request); 30 | } 31 | }); 32 | 33 | decode(readable(stdin)); 34 | -------------------------------------------------------------------------------- /src/codeGeneratorRespond.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type { CodeGeneratorRequest__InstanceR } from "./schema.capnp-r"; 4 | 5 | import Index from "./Index"; 6 | import { values, classes } from "./serialization/generate"; 7 | 8 | const readerStrategy = { 9 | tag: "reader", 10 | filename(base: string): string { 11 | return base + "-r"; 12 | }, 13 | suffix(base: string): string { 14 | return base + "R"; 15 | }, 16 | }; 17 | 18 | const builderStrategy = { 19 | tag: "builder", 20 | filename(base: string): string { 21 | return base + "-b"; 22 | }, 23 | suffix(base: string): string { 24 | return base + "B"; 25 | }, 26 | }; 27 | 28 | export default function codeGeneratorRespond(request: CodeGeneratorRequest__InstanceR): void { 29 | const index = new Index(request.getNodes()); 30 | 31 | const requestedFiles = request.getRequestedFiles(); 32 | if (requestedFiles !== null) { 33 | requestedFiles.forEach(requestedFile => { 34 | const vs = values(index, requestedFile); 35 | 36 | [ readerStrategy, builderStrategy ].forEach(strategy => { 37 | classes(index, vs, strategy, requestedFile); 38 | }); 39 | }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/serialization/accumulateBuilderLibs.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type { UInt64 } from "@capnp-js/uint64"; 4 | 5 | import type Index from "../Index"; 6 | import type { 7 | Node__InstanceR, 8 | Brand__InstanceR, 9 | Type__InstanceR, 10 | } from "../schema.capnp-r"; 11 | import type { Libs } from "./libs"; 12 | 13 | import { Brand, Field, Type } from "../schema.capnp-r"; 14 | import Visitor from "../Visitor"; 15 | 16 | type Acc = { 17 | +aliases: { [naive: string]: string }, 18 | +type: { 19 | int64: { [naive: string]: string }, 20 | uint64: { [naive: string]: string }, 21 | layout: { [naive: string]: string }, 22 | memory: { [naive: string]: string }, 23 | "reader-core": { [naive: string]: string }, 24 | "builder-core": { [naive: string]: string }, 25 | }, 26 | +value: { 27 | +int64: { [naive: string]: string }, 28 | +uint64: { [naive: string]: string }, 29 | +"copy-pointers": { [naive: string]: string }, 30 | +layout: { [naive: string]: string }, 31 | +memory: { [naive: string]: string }, 32 | +"reader-core": { [naive: string]: string }, 33 | +"builder-core": { [naive: string]: string }, 34 | +"reader-arena": { [naive: string]: string }, 35 | }, 36 | +"all-value": { 37 | "read-data": null | "decode", 38 | "write-data": null | "encode", 39 | }, 40 | }; 41 | 42 | class LibsVisitor extends Visitor { 43 | +names: Set; 44 | 45 | constructor(index: Index, names: Set) { 46 | super(index); 47 | this.names = names; 48 | } 49 | 50 | mangle(naive: string): string { 51 | return this.names.has(naive) ? "capnp_" + naive : naive; 52 | } 53 | 54 | struct(node: Node__InstanceR, acc: Acc): Acc { 55 | /* GenericR */ 56 | const parameters = node.getParameters(); 57 | if (parameters !== null && parameters.length() > 0) { 58 | acc.type["reader-core"]["AnyGutsR"] = this.mangle("AnyGutsR"); 59 | acc.type["reader-core"]["CtorR"] = this.mangle("CtorR"); 60 | acc.type["builder-core"]["ReaderCtor"] = this.mangle("ReaderCtor"); 61 | acc.type["builder-core"]["CtorB"] = this.mangle("CtorB"); 62 | } 63 | 64 | /* CtorR */ 65 | acc.aliases["uint"] = "number"; 66 | acc.type["reader-core"]["StructGutsR"] = this.mangle("StructGutsR"); 67 | acc.type["builder-core"]["StructCtorB"] = this.mangle("StructCtorB"); 68 | acc.type["builder-core"]["ArenaB"] = this.mangle("ArenaB"); 69 | acc.type["builder-core"]["AnyGutsB"] = this.mangle("AnyGutsB"); 70 | acc.type["builder-core"]["StructGutsB"] = this.mangle("StructGutsB"); 71 | acc.type.layout["Bytes"] = this.mangle("Bytes"); 72 | acc.type.memory["Pointer"] = this.mangle("Pointer"); 73 | acc.type.memory["SegmentB"] = this.mangle("SegmentB"); 74 | acc.type.memory["Word"] = this.mangle("Word"); 75 | acc.value.memory["isNull"] = "isNull"; 76 | acc.value["builder-core"]["RefedStruct"] = this.mangle("RefedStruct"); 77 | acc.value["builder-core"]["Orphan"] = this.mangle("Orphan"); //TODO: this should prevent type Orphan from getting brought in. Consider a method that does this check instead of my assignments. 78 | 79 | /* InstanceR */ 80 | if (node.getStruct().getDiscriminantCount() > 0) { 81 | acc.aliases["u16"] = "number"; 82 | } 83 | 84 | acc.type["reader-core"]["CtorR"] = this.mangle("CtorR"); 85 | acc.type["reader-core"]["StructGutsR"] = this.mangle("StructGutsR"); 86 | const fields = node.getStruct().getFields(); 87 | if (fields !== null) { 88 | fields.forEach(field => { 89 | switch (field.tag()) { 90 | case Field.tags.slot: 91 | this.addAlias(field.getSlot().getType(), acc); 92 | this.addType(field.getSlot().getType(), acc); 93 | break; 94 | case Field.tags.group: 95 | /* Dig into the struct's groups for their field types too. */ 96 | this.visit(field.getGroup().getTypeId(), acc); 97 | break; 98 | default: throw new Error("Unrecognized field tag."); 99 | } 100 | }); 101 | } 102 | 103 | return super.struct(node, acc); 104 | } 105 | 106 | interface(node: Node__InstanceR, acc: Acc): Acc { 107 | /* GenericR */ 108 | const parameters = node.getParameters(); 109 | if (parameters !== null && parameters.length() > 0) { 110 | acc.type["reader-core"]["AnyGutsR"] = this.mangle("AnyGutsR"); 111 | acc.type["builder-core"]["CtorB"] = this.mangle("CtorB"); 112 | } 113 | 114 | const methods = node.getInterface().getMethods(); 115 | if (methods !== null) { 116 | methods.forEach(method => { 117 | const paramId = method.getParamStructType(); 118 | const param = this.index.getNode(paramId); 119 | const paramScopeId = param.getScopeId(); 120 | if (paramScopeId[0] === 0 && paramScopeId[1] === 0) { 121 | acc = this.visit(paramId, acc); 122 | } 123 | 124 | const resultId = method.getResultStructType(); 125 | const result = this.index.getNode(resultId); 126 | const resultScopeId = result.getScopeId(); 127 | if (resultScopeId[0] === 0 && resultScopeId[1] === 0) { 128 | acc = this.visit(resultId, acc); 129 | } 130 | }); 131 | } 132 | 133 | return super.interface(node, acc); 134 | } 135 | 136 | addAlias(type: null | Type__InstanceR, acc: Acc): void { 137 | if (type === null) { 138 | type = Type.empty(); 139 | } 140 | 141 | switch (type.tag()) { 142 | case Type.tags.void: 143 | case Type.tags.bool: 144 | break; 145 | case Type.tags.int8: 146 | acc.aliases["i8"] = "number"; 147 | break; 148 | case Type.tags.int16: 149 | acc.aliases["i16"] = "number"; 150 | break; 151 | case Type.tags.int32: 152 | acc.aliases["i32"] = "number"; 153 | break; 154 | case Type.tags.uint8: 155 | acc.aliases["u8"] = "number"; 156 | break; 157 | case Type.tags.uint16: 158 | acc.aliases["u16"] = "number"; 159 | break; 160 | case Type.tags.uint32: 161 | acc.aliases["u32"] = "number"; 162 | break; 163 | case Type.tags.float32: 164 | acc.aliases["f32"] = "number"; 165 | break; 166 | case Type.tags.float64: 167 | acc.aliases["f64"] = "number"; 168 | break; 169 | case Type.tags.enum: 170 | acc.aliases["u16"] = "number"; 171 | } 172 | } 173 | 174 | addType(type: null | Type__InstanceR, acc: Acc): void { 175 | if (type === null) { 176 | type = Type.empty(); 177 | } 178 | 179 | switch (type.tag()) { 180 | case Type.tags.void: 181 | break; 182 | case Type.tags.bool: 183 | case Type.tags.int8: 184 | case Type.tags.int16: 185 | case Type.tags.int32: 186 | case Type.tags.uint8: 187 | case Type.tags.uint16: 188 | case Type.tags.uint32: 189 | case Type.tags.float32: 190 | acc["all-value"]["read-data"] = "decode"; 191 | acc["all-value"]["write-data"] = "encode"; 192 | break; 193 | case Type.tags.float64: 194 | acc["all-value"]["read-data"] = "decode"; 195 | acc["all-value"]["write-data"] = "encode"; 196 | acc.value.int64["inject"] = "injectI64"; 197 | break; 198 | case Type.tags.int64: 199 | acc.type.int64["Int64"] = this.mangle("Int64"); 200 | acc["all-value"]["read-data"] = "decode"; 201 | acc["all-value"]["write-data"] = "encode"; 202 | acc.value.int64["inject"] = "injectI64"; 203 | break; 204 | case Type.tags.uint64: 205 | acc.type.uint64["UInt64"] = this.mangle("UInt64"); 206 | acc["all-value"]["read-data"] = "decode"; 207 | acc["all-value"]["write-data"] = "encode"; 208 | acc.value.uint64["inject"] = "injectU64"; 209 | break; 210 | case Type.tags.text: 211 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 212 | acc.type["reader-core"]["Text"] = this.mangle("TextR"); 213 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 214 | acc.value["builder-core"]["Text"] = this.mangle("Text"); 215 | break; 216 | case Type.tags.data: 217 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 218 | acc.type["reader-core"]["Data"] = this.mangle("DataR"); 219 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 220 | acc.value["builder-core"]["Data"] = this.mangle("Data"); 221 | break; 222 | case Type.tags.list: 223 | this.addList(type.getList().getElementType(), acc); 224 | break; 225 | case Type.tags.enum: 226 | acc["all-value"]["read-data"] = "decode"; 227 | acc["all-value"]["write-data"] = "encode"; 228 | break; 229 | case Type.tags.struct: 230 | this.addStruct(type.getStruct().getBrand(), acc); 231 | //TODO: Eslint rule for `//fall through` switch statements. 232 | break; 233 | case Type.tags.interface: 234 | acc.type["reader-core"]["CapValue"] = this.mangle("CapValueR"); 235 | acc.type["reader-core"]["CapGutsR"] = this.mangle("CapGutsR"); 236 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 237 | acc.value["builder-core"]["CapValue"] = this.mangle("CapValue"); 238 | break; 239 | case Type.tags.anyPointer: 240 | { 241 | const anyPointerGroup = Type.groups.anyPointer; 242 | const anyPointer = type.getAnyPointer(); 243 | switch (anyPointer.tag()) { 244 | case anyPointerGroup.tags.unconstrained: 245 | { 246 | const unconstrainedGroup = anyPointerGroup.groups.unconstrained; 247 | const unconstrained = anyPointer.getUnconstrained(); 248 | switch (unconstrained.tag()) { 249 | case unconstrainedGroup.tags.anyKind: 250 | acc.type["reader-core"]["AnyValue"] = this.mangle("AnyValueR"); 251 | acc.type["reader-core"]["AnyGutsR"] = this.mangle("AnyGutsR"); 252 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 253 | acc.value["builder-core"]["AnyValue"] = this.mangle("AnyValue"); 254 | break; 255 | case unconstrainedGroup.tags.struct: 256 | acc.type["reader-core"]["StructValue"] = this.mangle("StructValueR"); 257 | acc.type["reader-core"]["StructGutsR"] = this.mangle("StructGutsR"); 258 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 259 | acc.value["builder-core"]["StructValue"] = this.mangle("StructValue"); 260 | break; 261 | case unconstrainedGroup.tags.list: 262 | acc.type["reader-core"]["ListValue"] = this.mangle("ListValueR"); 263 | acc.type["reader-core"]["BoolListGutsR"] = this.mangle("BoolListGutsR"); 264 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 265 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 266 | acc.value["builder-core"]["ListValue"] = this.mangle("ListValue"); 267 | break; 268 | case unconstrainedGroup.tags.capability: 269 | acc.type["reader-core"]["CapValue"] = this.mangle("CapValueR"); 270 | acc.type["reader-core"]["CapGutsR"] = this.mangle("CapGutsR"); 271 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 272 | acc.value["builder-core"]["CapValue"] = this.mangle("CapValue"); 273 | break; 274 | default: 275 | throw new Error("Unrecognized unconstrained-AnyPointer tag."); 276 | } 277 | } 278 | case anyPointerGroup.tags.parameter: 279 | break; //TODO: Can a parameter name collide with anything? My hunch is no given the underscores. If collisions can occur, then consider `__r` instead of `_r`. 280 | case anyPointerGroup.tags.implicitMethodParameter: 281 | throw new Error("TODO"); 282 | default: 283 | throw new Error("Unrecognized any pointer tag."); 284 | } 285 | } 286 | break; 287 | default: 288 | throw new Error("Unrecognized type tag."); 289 | } 290 | } 291 | 292 | //TODO: Flag on Flow to stop treating uncalled functions as any. If you forget the parens, then you get errors silenced. 293 | addList(elementType: null | Type__InstanceR, acc: Acc): void { 294 | if (elementType === null) { 295 | elementType = Type.empty(); 296 | } 297 | 298 | switch (elementType.tag()) { 299 | case Type.tags.void: 300 | acc.type["reader-core"]["VoidList"] = this.mangle("VoidListR"); 301 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 302 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 303 | acc.value["builder-core"]["VoidList"] = this.mangle("VoidList"); 304 | break; 305 | case Type.tags.bool: 306 | acc.type["reader-core"]["BoolList"] = this.mangle("BoolListR"); 307 | acc.type["reader-core"]["BoolListGutsR"] = this.mangle("BoolListGutsR"); 308 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 309 | acc.value["builder-core"]["BoolList"] = this.mangle("BoolList"); 310 | break; 311 | case Type.tags.int8: 312 | acc.type["reader-core"]["Int8List"] = this.mangle("Int8ListR"); 313 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 314 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 315 | acc.value["builder-core"]["Int8List"] = this.mangle("Int8List"); 316 | break; 317 | case Type.tags.int16: 318 | acc.type["reader-core"]["Int16List"] = this.mangle("Int16ListR"); 319 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 320 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 321 | acc.value["builder-core"]["Int16List"] = this.mangle("Int16List"); 322 | break; 323 | case Type.tags.int32: 324 | acc.type["reader-core"]["Int32List"] = this.mangle("Int32ListR"); 325 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 326 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 327 | acc.value["builder-core"]["Int32List"] = this.mangle("Int32List"); 328 | break; 329 | case Type.tags.int64: 330 | acc.type["reader-core"]["Int64List"] = this.mangle("Int64ListR"); 331 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 332 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 333 | acc.value["builder-core"]["Int64List"] = this.mangle("Int64List"); 334 | break; 335 | case Type.tags.uint8: 336 | acc.type["reader-core"]["UInt8List"] = this.mangle("UInt8ListR"); 337 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 338 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 339 | acc.value["builder-core"]["UInt8List"] = this.mangle("UInt8List"); 340 | break; 341 | case Type.tags.uint16: 342 | acc.type["reader-core"]["UInt16List"] = this.mangle("UInt16ListR"); 343 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 344 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 345 | acc.value["builder-core"]["UInt16List"] = this.mangle("UInt16List"); 346 | break; 347 | case Type.tags.uint32: 348 | acc.type["reader-core"]["UInt32List"] = this.mangle("UInt32ListR"); 349 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 350 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 351 | acc.value["builder-core"]["UInt32List"] = this.mangle("UInt32List"); 352 | break; 353 | case Type.tags.uint64: 354 | acc.type["reader-core"]["UInt64List"] = this.mangle("UInt64ListR"); 355 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 356 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 357 | acc.value["builder-core"]["UInt64List"] = this.mangle("UInt64List"); 358 | break; 359 | case Type.tags.float32: 360 | acc.type["reader-core"]["Float32List"] = this.mangle("Float32ListR"); 361 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 362 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 363 | acc.value["builder-core"]["Float32List"] = this.mangle("Float32List"); 364 | break; 365 | case Type.tags.float64: 366 | acc.type["reader-core"]["Float64List"] = this.mangle("Float64ListR"); 367 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 368 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 369 | acc.value["builder-core"]["Float64List"] = this.mangle("Float64List"); 370 | break; 371 | case Type.tags.text: 372 | acc.type["reader-core"]["PointerListR"] = this.mangle("PointerListR"); 373 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 374 | acc.type["reader-core"]["Text"] = this.mangle("TextR"); 375 | acc.type["builder-core"]["PointerListB"] = this.mangle("PointerListB"); 376 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 377 | acc.value["builder-core"]["Text"] = this.mangle("Text"); 378 | acc.value["builder-core"]["pointers"] = "pointers"; 379 | break; 380 | case Type.tags.data: 381 | acc.type["reader-core"]["PointerListR"] = this.mangle("PointerListR"); 382 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 383 | acc.type["reader-core"]["Data"] = this.mangle("DataR"); 384 | acc.type["builder-core"]["PointerListB"] = this.mangle("PointerListB"); 385 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 386 | acc.value["builder-core"]["Data"] = this.mangle("Data"); 387 | acc.value["builder-core"]["pointers"] = "pointers"; 388 | break; 389 | case Type.tags.list: 390 | acc.type["reader-core"]["PointerListR"] = this.mangle("PointerListR"); 391 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 392 | acc.type["builder-core"]["PointerListB"] = this.mangle("PointerListB"); 393 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 394 | acc.value["builder-core"]["pointers"] = "pointers"; 395 | this.addList(elementType.getList().getElementType(), acc); 396 | break; 397 | case Type.tags.enum: 398 | acc.type["reader-core"]["UInt16List"] = this.mangle("UInt16ListR"); 399 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 400 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 401 | acc.value["builder-core"]["UInt16List"] = this.mangle("UInt16List"); 402 | break; 403 | case Type.tags.struct: 404 | acc.type["reader-core"]["StructListR"] = this.mangle("StructListR"); 405 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 406 | acc.type["builder-core"]["StructListB"] = this.mangle("StructListB"); 407 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 408 | acc.value["builder-core"]["structs"] = "structs"; 409 | break; 410 | case Type.tags.interface: 411 | acc.type["reader-core"]["CapGutsR"] = this.mangle("CapGutsR"); 412 | acc.type["reader-core"]["CapValue"] = this.mangle("CapValueR"); 413 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 414 | acc.value["builder-core"]["CapValue"] = this.mangle("CapValue"); 415 | break; 416 | case Type.tags.anyPointer: 417 | { 418 | const anyPointerGroup = Type.groups.anyPointer; 419 | const anyPointer = elementType.getAnyPointer(); 420 | switch (anyPointer.tag()) { 421 | case anyPointerGroup.tags.unconstrained: 422 | { 423 | const unconstrainedGroup = anyPointerGroup.groups.unconstrained; 424 | const unconstrained = anyPointer.getUnconstrained(); 425 | switch (unconstrained.tag()) { 426 | case unconstrainedGroup.tags.anyKind: 427 | throw new Error("Forbidden type: List(AnyPointer)."); 428 | case unconstrainedGroup.tags.struct: 429 | throw new Error("Forbidden type: List(AnyStruct)."); 430 | case unconstrainedGroup.tags.list: 431 | //TODO: None of my current schemata use a `List(AnyList)`. Be sure that this gets tested. 432 | acc.type["reader-core"]["BoolListGutsR"] = this.mangle("BoolListGutsR"); 433 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 434 | acc.type["reader-core"]["ListValue"] = this.mangle("ListValueR"); 435 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 436 | acc.value["builder-core"]["ListValue"] = this.mangle("ListValue"); 437 | break; 438 | case unconstrainedGroup.tags.capability: 439 | acc.type["reader-core"]["CapGutsR"] = this.mangle("CapGutsR"); 440 | acc.type["reader-core"]["CapValue"] = this.mangle("CapValueR"); 441 | acc.type["builder-core"]["Orphan"] = this.mangle("Orphan"); 442 | acc.value["builder-core"]["CapValue"] = this.mangle("CapValue"); 443 | break; 444 | default: 445 | throw new Error("Unrecognized unconstrained-AnyPointer tag."); 446 | } 447 | } 448 | break; 449 | case anyPointerGroup.tags.parameter: 450 | throw new Error("Forbidden type: List(T) for some parameter T"); 451 | case anyPointerGroup.tags.implicitMethodParameter: 452 | throw new Error("TODO"); 453 | default: 454 | throw new Error("Unrecognized any pointer tag."); 455 | } 456 | } 457 | break; 458 | default: 459 | throw new Error("Unrecognized type tag."); 460 | } 461 | } 462 | 463 | addStruct(brand: null | Brand__InstanceR, acc: Acc): void { 464 | //TODO: I never touch the struct's id. Don't I need to? I expect imported structs to bust. 465 | if (brand !== null) { 466 | const scopes = brand.getScopes(); 467 | if (scopes !== null) { 468 | scopes.forEach(scope => { 469 | if (scope.tag() === Brand.Scope.tags.bind) { 470 | const bind = scope.getBind(); 471 | if (bind !== null) { 472 | bind.forEach(binding => { 473 | if (binding.tag() === Brand.Binding.tags.type) { 474 | this.addType(binding.getType(), acc); 475 | } 476 | }); 477 | } 478 | } 479 | }); 480 | } 481 | } 482 | } 483 | } 484 | 485 | export default function accumulateBuilderLibs(index: Index, fileId: UInt64, names: Set): Libs { 486 | function minus(lhs: { [naive: string]: string }, rhs: { [naive: string]: string }): { [naive: string]: string } { 487 | const result = {}; 488 | Object.keys(lhs).forEach(naive => { 489 | if (!rhs.hasOwnProperty(naive)) { 490 | result[naive] = lhs[naive]; 491 | } 492 | }); 493 | 494 | return result; 495 | } 496 | 497 | function addNames(table: { [naive: string]: string }, acc: Set): void { 498 | Object.keys(table).forEach(naive => { 499 | acc.add(table[naive]); 500 | }); 501 | } 502 | 503 | const internalAcc = new LibsVisitor(index, names).visit(fileId, { 504 | aliases: {}, 505 | type: { 506 | int64: {}, 507 | uint64: {}, 508 | layout: {}, 509 | memory: {}, 510 | "reader-core": {}, 511 | "builder-core": {}, 512 | }, 513 | value: { 514 | int64: {}, 515 | uint64: {}, 516 | "copy-pointers": {}, 517 | layout: {}, 518 | memory: {}, 519 | "reader-core": {}, 520 | "builder-core": {}, 521 | "reader-arena": {}, 522 | }, 523 | "all-value": { 524 | "read-data": null, 525 | "write-data": null, 526 | }, 527 | }); 528 | 529 | const libNames = new Set(); 530 | 531 | internalAcc.type.int64 = minus(internalAcc.type.int64, internalAcc.value.int64); 532 | addNames(internalAcc.type.int64, libNames); 533 | internalAcc.type.uint64 = minus(internalAcc.type.uint64, internalAcc.value.uint64); 534 | addNames(internalAcc.type.uint64, libNames); 535 | internalAcc.type.layout = minus(internalAcc.type.layout, internalAcc.value.layout); 536 | addNames(internalAcc.type.layout, libNames); 537 | internalAcc.type.memory = minus(internalAcc.type.memory, internalAcc.value.memory); 538 | addNames(internalAcc.type.memory, libNames); 539 | internalAcc.type["reader-core"] = minus(internalAcc.type["reader-core"], internalAcc.value["reader-core"]); 540 | addNames(internalAcc.type["reader-core"], libNames); 541 | internalAcc.type["builder-core"] = minus(internalAcc.type["builder-core"], internalAcc.value["builder-core"]); 542 | addNames(internalAcc.type["builder-core"], libNames); 543 | 544 | addNames(internalAcc.value.int64, libNames); 545 | addNames(internalAcc.value.uint64, libNames); 546 | addNames(internalAcc.value.layout, libNames); 547 | addNames(internalAcc.value.memory, libNames); 548 | addNames(internalAcc.value["reader-core"], libNames); 549 | addNames(internalAcc.value["builder-core"], libNames); 550 | 551 | return { ...internalAcc, names: libNames }; 552 | } 553 | -------------------------------------------------------------------------------- /src/serialization/accumulateLocals.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type { UInt64 } from "@capnp-js/uint64"; 4 | 5 | import type Index from "../Index"; 6 | import type { Node__InstanceR } from "../schema.capnp-r"; 7 | 8 | import { toHex } from "@capnp-js/uint64"; 9 | 10 | import Visitor from "../Visitor"; 11 | 12 | export type Locals = { 13 | +names: Set, 14 | +structs: Set, 15 | +paramStructs: Set, 16 | +resultStructs: Set, 17 | +interfaces: Set, 18 | +identifiers: { [uuid: string]: string }, 19 | }; 20 | 21 | class LocalsVisitor extends Visitor { 22 | struct(node: Node__InstanceR, acc: Locals): Locals { 23 | const baseName = this.index.getScopes(node.getId()).slice(1).map(s => s.name).join("_"); 24 | acc.names.add(baseName); 25 | acc.structs.add(baseName); 26 | acc.identifiers[toHex(node.getId())] = baseName; 27 | 28 | return super.struct(node, acc); 29 | } 30 | 31 | enum(node: Node__InstanceR, acc: Locals): Locals { 32 | const baseName = this.index.getScopes(node.getId()).slice(1).map(s => s.name).join("_"); 33 | acc.names.add(baseName); 34 | acc.identifiers[toHex(node.getId())] = baseName; 35 | 36 | return super.enum(node, acc); 37 | } 38 | 39 | interface(node: Node__InstanceR, acc: Locals): Locals { 40 | const baseName = this.index.getScopes(node.getId()).slice(1).map(s => s.name).join("_"); 41 | acc.names.add(baseName); 42 | acc.interfaces.add(baseName); 43 | acc.identifiers[toHex(node.getId())] = baseName; 44 | 45 | const methods = node.getInterface().getMethods(); 46 | if (methods !== null) { 47 | methods.forEach(method => { 48 | const paramId = method.getParamStructType(); 49 | const param = this.index.getNode(paramId); 50 | const paramScopeId = param.getScopeId(); 51 | if (paramScopeId[0] === 0 && paramScopeId[1] === 0) { 52 | const baseName = this.index.getScopes(paramId).slice(1).map(s => s.name).join("_"); 53 | acc.names.add(baseName); 54 | acc.paramStructs.add(baseName); 55 | acc.identifiers[toHex(paramId)] = baseName; 56 | } 57 | 58 | const resultId = method.getResultStructType(); 59 | const result = this.index.getNode(resultId); 60 | const resultScopeId = result.getScopeId(); 61 | if (resultScopeId[0] === 0 && resultScopeId[1] === 0) { 62 | const baseName = this.index.getScopes(resultId).slice(1).map(s => s.name).join("_"); 63 | acc.names.add(baseName); 64 | acc.resultStructs.add(baseName); 65 | acc.identifiers[toHex(resultId)] = baseName; 66 | } 67 | }); 68 | } 69 | 70 | return super.interface(node, acc); 71 | } 72 | } 73 | 74 | export default function accumulateLocals(index: Index, fileId: UInt64): Locals { 75 | return new LocalsVisitor(index).visit(fileId, { 76 | names: new Set(), 77 | structs: new Set(), 78 | paramStructs: new Set(), 79 | resultStructs: new Set(), 80 | interfaces: new Set(), 81 | identifiers: {}, 82 | }); 83 | } 84 | -------------------------------------------------------------------------------- /src/serialization/accumulateParameters.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type Index from "../Index"; 4 | import type { Scope } from "../Index"; 5 | 6 | import { toHex } from "@capnp-js/uint64"; 7 | import { nonnull } from "@capnp-js/nullary"; 8 | 9 | import { Node } from "../schema.capnp-r"; 10 | 11 | export type Parameters = { 12 | main: $ReadOnlyArray, 13 | generic: $ReadOnlyArray, 14 | specialize: $ReadOnlyArray, 15 | }; 16 | 17 | export type ParametersIndex = { [hostId: string]: Parameters }; 18 | 19 | function parameters(scopes: $ReadOnlyArray): Parameters { 20 | const main = scopes.slice(1).map((scope, depth) => { 21 | const locals = scope.node.getParameters(); 22 | if (locals === null) { 23 | return []; 24 | } else { 25 | return locals.map(parameter => { 26 | const name = nonnull(parameter.getName()).toString(); 27 | return `${name}_${depth}`; 28 | }); 29 | } 30 | }); 31 | 32 | const generic = main.slice(0, main.length - 1); 33 | const specialize = main.slice(main.length - 1); 34 | 35 | return { 36 | main: main.reduce((acc, params) => acc.concat(params), []), 37 | generic: generic.reduce((acc, params) => acc.concat(params), []), 38 | specialize: specialize.reduce((acc, params) => acc.concat(params), []), 39 | }; 40 | } 41 | 42 | export default function accumulateParameters(index: Index): ParametersIndex { 43 | const parametersIndex = {}; 44 | index.forEachNode(node => { 45 | parametersIndex[toHex(node.getId())] = parameters(index.getScopes(node.getId())); 46 | 47 | if (node.tag() === Node.tags.interface) { 48 | const iface = node.getInterface(); 49 | const methods = iface.getMethods(); 50 | if (methods !== null) { 51 | methods.forEach(method => { 52 | const paramId = method.getParamStructType(); 53 | const param = index.getNode(paramId); 54 | const paramScopeId = param.getScopeId(); 55 | if (!(paramScopeId[0] === 0 && paramScopeId[1] === 0)) { 56 | parametersIndex[toHex(paramId)] = parameters(index.getScopes(paramId)); 57 | } 58 | 59 | const resultId = method.getResultStructType(); 60 | const result = index.getNode(resultId); 61 | const resultScopeId = result.getScopeId(); 62 | if (!(resultScopeId[0] === 0 && resultScopeId[1] === 0)) { 63 | parametersIndex[toHex(resultId)] = parameters(index.getScopes(resultId)); 64 | } 65 | }); 66 | } 67 | } 68 | }); 69 | 70 | return parametersIndex; 71 | } 72 | -------------------------------------------------------------------------------- /src/serialization/accumulateReaderLibs.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type { UInt64 } from "@capnp-js/uint64"; 4 | 5 | import type Index from "../Index"; 6 | import type { 7 | Node__InstanceR, 8 | Brand__InstanceR, 9 | Type__InstanceR, 10 | } from "../schema.capnp-r"; 11 | import type { Libs } from "./libs"; 12 | 13 | import { Brand, Field, Type } from "../schema.capnp-r"; 14 | import Visitor from "../Visitor"; 15 | 16 | type Acc = { 17 | +aliases: { [naive: string]: string }, 18 | +type: { 19 | +int64: { [naive: string]: string }, 20 | +uint64: { [naive: string]: string }, 21 | +layout: { [naive: string]: string }, 22 | +memory: { [naive: string]: string }, 23 | +"reader-core": { [naive: string]: string }, 24 | +"builder-core": { [naive: string]: string }, 25 | }, 26 | +value: { 27 | +int64: { [naive: string]: string }, 28 | +uint64: { [naive: string]: string }, 29 | +layout: { [naive: string]: string }, 30 | +memory: { [naive: string]: string }, 31 | +"reader-core": { [naive: string]: string }, 32 | +"builder-core": { [naive: string]: string }, 33 | +"reader-arena": { [naive: string]: string }, 34 | }, 35 | +"all-value": { 36 | "read-data": null | "decode", 37 | "write-data": null | "encode", 38 | }, 39 | }; 40 | 41 | function addNames(table: { [naive: string]: string }, acc: Set): void { 42 | Object.keys(table).forEach(naive => { 43 | acc.add(table[naive]); 44 | }); 45 | } 46 | 47 | class LibsVisitor extends Visitor { 48 | +names: Set; 49 | 50 | constructor(index: Index, names: Set) { 51 | super(index); 52 | this.names = names; 53 | } 54 | 55 | mangle(naive: string): string { 56 | return this.names.has(naive) ? "capnp_" + naive : naive; 57 | } 58 | 59 | struct(node: Node__InstanceR, acc: Acc): Acc { 60 | /* GenericR */ 61 | const parameters = node.getParameters(); 62 | if (parameters !== null && parameters.length() > 0) { 63 | acc.type["reader-core"]["AnyGutsR"] = this.mangle("AnyGutsR"); 64 | acc.type["reader-core"]["CtorR"] = this.mangle("CtorR"); 65 | } 66 | 67 | /* CtorR */ 68 | acc.aliases["uint"] = "number"; 69 | acc.type["reader-core"]["StructCtorR"] = this.mangle("StructCtorR"); 70 | acc.type["reader-core"]["StructGutsR"] = this.mangle("StructGutsR"); 71 | acc.type["reader-core"]["ArenaR"] = this.mangle("ArenaR"); 72 | acc.type["reader-core"]["AnyGutsR"] = this.mangle("AnyGutsR"); 73 | acc.type.layout["Bytes"] = this.mangle("Bytes"); 74 | acc.type.memory["SegmentR"] = this.mangle("SegmentR"); 75 | acc.type.memory["Word"] = this.mangle("Word"); 76 | acc.value.memory["isNull"] = "isNull"; 77 | acc.value["reader-core"]["RefedStruct"] = this.mangle("RefedStruct"); 78 | acc.value["reader-arena"]["empty"] = "empty"; 79 | 80 | /* InstanceR */ 81 | if (node.getStruct().getDiscriminantCount() > 0) { 82 | acc.aliases["u16"] = "number"; 83 | } 84 | 85 | const fields = node.getStruct().getFields(); 86 | if (fields !== null) { 87 | fields.forEach(field => { 88 | switch (field.tag()) { 89 | case Field.tags.slot: 90 | this.addAlias(field.getSlot().getType(), acc); 91 | this.addType(field.getSlot().getType(), acc); 92 | break; 93 | case Field.tags.group: 94 | /* Dig into the struct's groups for their field types too. */ 95 | acc = this.visit(field.getGroup().getTypeId(), acc); 96 | break; 97 | default: throw new Error("Unrecognized field tag."); 98 | } 99 | }); 100 | } 101 | 102 | return super.struct(node, acc); 103 | } 104 | 105 | interface(node: Node__InstanceR, acc: Acc): Acc { 106 | /* GenericR */ 107 | const parameters = node.getParameters(); 108 | if (parameters !== null && parameters.length() > 0) { 109 | acc.type["reader-core"]["AnyGutsR"] = this.mangle("AnyGutsR"); 110 | acc.type["reader-core"]["CtorR"] = this.mangle("CtorR"); 111 | } 112 | 113 | const methods = node.getInterface().getMethods(); 114 | if (methods !== null) { 115 | methods.forEach(method => { 116 | const paramId = method.getParamStructType(); 117 | const param = this.index.getNode(paramId); 118 | const paramScopeId = param.getScopeId(); 119 | if (paramScopeId[0] === 0 && paramScopeId[1] === 0) { 120 | acc = this.visit(paramId, acc); 121 | } 122 | 123 | const resultId = method.getResultStructType(); 124 | const result = this.index.getNode(resultId); 125 | const resultScopeId = result.getScopeId(); 126 | if (resultScopeId[0] === 0 && resultScopeId[1] === 0) { 127 | acc = this.visit(resultId, acc); 128 | } 129 | }); 130 | } 131 | 132 | return super.interface(node, acc); 133 | } 134 | 135 | const(node: Node__InstanceR, acc: Acc): Acc { 136 | let type = node.getConst().getType(); 137 | if (type === null) { 138 | type = Type.empty(); 139 | } 140 | 141 | this.addAlias(type, acc); 142 | switch (type.tag()) { 143 | case Type.tags.void: 144 | case Type.tags.bool: 145 | case Type.tags.int8: 146 | case Type.tags.int16: 147 | case Type.tags.int32: 148 | case Type.tags.uint8: 149 | case Type.tags.uint16: 150 | case Type.tags.uint32: 151 | case Type.tags.float32: 152 | case Type.tags.float64: 153 | case Type.tags.enum: 154 | break; 155 | 156 | case Type.tags.int64: 157 | acc.type.int64["Int64"] = this.mangle("Int64"); 158 | acc.value.int64["inject"] = "injectI64"; 159 | break; 160 | case Type.tags.uint64: 161 | acc.type.uint64["UInt64"] = this.mangle("UInt64"); 162 | acc.value.uint64["inject"] = "injectU64"; 163 | break; 164 | 165 | case Type.tags.text: 166 | case Type.tags.data: 167 | case Type.tags.list: 168 | case Type.tags.struct: 169 | case Type.tags.interface: 170 | case Type.tags.anyPointer: 171 | this.addType(node.getConst().getType(), acc); 172 | break; 173 | 174 | default: 175 | throw new Error("Unrecognized type tag."); 176 | } 177 | 178 | return super.const(node, acc); 179 | } 180 | 181 | addAlias(type: null | Type__InstanceR, acc: Acc): void { 182 | if (type === null) { 183 | type = Type.empty(); 184 | } 185 | 186 | switch (type.tag()) { 187 | case Type.tags.void: 188 | case Type.tags.bool: 189 | break; 190 | case Type.tags.int8: 191 | acc.aliases["i8"] = "number"; 192 | break; 193 | case Type.tags.int16: 194 | acc.aliases["i16"] = "number"; 195 | break; 196 | case Type.tags.int32: 197 | acc.aliases["i32"] = "number"; 198 | break; 199 | case Type.tags.uint8: 200 | acc.aliases["u8"] = "number"; 201 | break; 202 | case Type.tags.uint16: 203 | acc.aliases["u16"] = "number"; 204 | break; 205 | case Type.tags.uint32: 206 | acc.aliases["u32"] = "number"; 207 | break; 208 | case Type.tags.float32: 209 | acc.aliases["f32"] = "number"; 210 | break; 211 | case Type.tags.float64: 212 | acc.aliases["f64"] = "number"; 213 | break; 214 | case Type.tags.enum: 215 | acc.aliases["u16"] = "number"; 216 | } 217 | } 218 | 219 | addParameterType(type: null | Type__InstanceR, acc: Acc): void { 220 | if (type === null) { 221 | type = Type.empty(); 222 | } 223 | 224 | switch (type.tag()) { 225 | case Type.tags.void: 226 | case Type.tags.bool: 227 | case Type.tags.int8: 228 | case Type.tags.int16: 229 | case Type.tags.int32: 230 | case Type.tags.uint8: 231 | case Type.tags.uint16: 232 | case Type.tags.uint32: 233 | case Type.tags.float32: 234 | case Type.tags.float64: 235 | case Type.tags.int64: 236 | case Type.tags.uint64: 237 | case Type.tags.enum: 238 | break; 239 | case Type.tags.text: 240 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 241 | acc.value["reader-core"]["Text"] = this.mangle("Text"); 242 | break; 243 | case Type.tags.data: 244 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 245 | acc.value["reader-core"]["Data"] = this.mangle("Data"); 246 | break; 247 | case Type.tags.list: 248 | this.addParameterList(type.getList().getElementType(), acc); 249 | break; 250 | case Type.tags.struct: 251 | acc.type["reader-core"]["StructGutsR"] = this.mangle("StructGutsR"); 252 | this.addStruct(type.getStruct().getBrand(), acc); 253 | //TODO: Eslint rule for `//fall through` switch statements. 254 | break; 255 | case Type.tags.interface: 256 | acc.type["reader-core"]["CapGutsR"] = this.mangle("CapGutsR"); 257 | acc.value["reader-core"]["CapValue"] = this.mangle("CapValue"); 258 | break; 259 | case Type.tags.anyPointer: 260 | { 261 | const anyPointerGroup = Type.groups.anyPointer; 262 | const anyPointer = type.getAnyPointer(); 263 | switch (anyPointer.tag()) { 264 | case anyPointerGroup.tags.unconstrained: 265 | { 266 | const unconstrainedGroup = anyPointerGroup.groups.unconstrained; 267 | const unconstrained = anyPointer.getUnconstrained(); 268 | switch (unconstrained.tag()) { 269 | case unconstrainedGroup.tags.anyKind: 270 | acc.type["reader-core"]["AnyGutsR"] = this.mangle("AnyGutsR"); 271 | acc.value["reader-core"]["AnyValue"] = this.mangle("AnyValue"); 272 | break; 273 | case unconstrainedGroup.tags.struct: 274 | acc.type["reader-core"]["StructGutsR"] = this.mangle("StructGutsR"); 275 | acc.value["reader-core"]["StructValue"] = this.mangle("StructValue"); 276 | break; 277 | case unconstrainedGroup.tags.list: 278 | acc.type["reader-core"]["BoolListGutsR"] = this.mangle("BoolListGutsR"); 279 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 280 | acc.value["reader-core"]["ListValue"] = this.mangle("ListValue"); 281 | break; 282 | case unconstrainedGroup.tags.capability: 283 | acc.type["reader-core"]["CapGutsR"] = this.mangle("CapGutsR"); 284 | acc.value["reader-core"]["CapValue"] = this.mangle("CapValue"); 285 | break; 286 | default: 287 | throw new Error("Unrecognized unconstrained-AnyPointer tag."); 288 | } 289 | } 290 | case anyPointerGroup.tags.parameter: 291 | break; //TODO: Can a parameter name collide with anything? My hunch is no given the underscores. If collisions can occur, then consider `__r` instead of `_r`. 292 | case anyPointerGroup.tags.implicitMethodParameter: 293 | //TODO: I substitute AnyValue for now. Implement in parallel with RPC 294 | // requirements. 295 | acc.type["reader-core"]["AnyGutsR"] = this.mangle("AnyGutsR"); 296 | acc.value["reader-core"]["AnyValue"] = this.mangle("AnyValue"); 297 | break; 298 | default: 299 | throw new Error("Unrecognized any pointer tag."); 300 | } 301 | } 302 | break; 303 | default: 304 | throw new Error("Unrecognized type tag."); 305 | } 306 | } 307 | 308 | addType(type: null | Type__InstanceR, acc: Acc): void { 309 | if (type === null) { 310 | type = Type.empty(); 311 | } 312 | 313 | switch (type.tag()) { 314 | case Type.tags.void: 315 | break; 316 | case Type.tags.bool: 317 | case Type.tags.int8: 318 | case Type.tags.int16: 319 | case Type.tags.int32: 320 | case Type.tags.uint8: 321 | case Type.tags.uint16: 322 | case Type.tags.uint32: 323 | case Type.tags.float32: 324 | acc["all-value"]["read-data"] = "decode"; 325 | break; 326 | case Type.tags.float64: 327 | acc["all-value"]["read-data"] = "decode"; 328 | acc.value.int64["inject"] = "injectI64"; 329 | break; 330 | case Type.tags.int64: 331 | acc.type.int64["Int64"] = this.mangle("Int64"); 332 | acc["all-value"]["read-data"] = "decode"; 333 | acc.value.int64["inject"] = "injectI64"; 334 | break; 335 | case Type.tags.uint64: 336 | acc.type.uint64["UInt64"] = this.mangle("UInt64"); 337 | acc["all-value"]["read-data"] = "decode"; 338 | acc.value.uint64["inject"] = "injectU64"; 339 | break; 340 | case Type.tags.text: 341 | acc.value["reader-core"]["Text"] = this.mangle("Text"); 342 | break; 343 | case Type.tags.data: 344 | acc.value["reader-core"]["Data"] = this.mangle("Data"); 345 | break; 346 | case Type.tags.list: 347 | this.addList(type.getList().getElementType(), acc); 348 | break; 349 | case Type.tags.enum: 350 | acc["all-value"]["read-data"] = "decode"; 351 | break; 352 | case Type.tags.struct: 353 | this.addStruct(type.getStruct().getBrand(), acc); 354 | //TODO: Eslint rule for `//fall through` switch statements. 355 | break; 356 | case Type.tags.interface: 357 | acc.value["reader-core"]["CapValue"] = this.mangle("CapValue"); 358 | break; 359 | case Type.tags.anyPointer: 360 | { 361 | const anyPointerGroup = Type.groups.anyPointer; 362 | const anyPointer = type.getAnyPointer(); 363 | switch (anyPointer.tag()) { 364 | case anyPointerGroup.tags.unconstrained: 365 | { 366 | const unconstrainedGroup = anyPointerGroup.groups.unconstrained; 367 | const unconstrained = anyPointer.getUnconstrained(); 368 | switch (unconstrained.tag()) { 369 | case unconstrainedGroup.tags.anyKind: 370 | acc.value["reader-core"]["AnyValue"] = this.mangle("AnyValue"); 371 | break; 372 | case unconstrainedGroup.tags.struct: 373 | acc.value["reader-core"]["StructValue"] = this.mangle("StructValue"); 374 | break; 375 | case unconstrainedGroup.tags.list: 376 | acc.value["reader-core"]["ListValue"] = this.mangle("ListValue"); 377 | break; 378 | case unconstrainedGroup.tags.capability: 379 | acc.value["reader-core"]["CapValue"] = this.mangle("CapValue"); 380 | break; 381 | default: 382 | throw new Error("Unrecognized unconstrained-AnyPointer tag."); 383 | } 384 | } 385 | case anyPointerGroup.tags.parameter: 386 | break; //TODO: Can a parameter name collide with anything? My hunch is no given the underscores. If collisions can occur, then consider `__r` instead of `_r`. 387 | case anyPointerGroup.tags.implicitMethodParameter: 388 | //TODO: I substitute AnyValue for now. An RPC implementation will 389 | // probably provide requirements for interface values. 390 | acc.value["reader-core"]["AnyValue"] = this.mangle("AnyValue"); 391 | break; 392 | default: 393 | throw new Error("Unrecognized any pointer tag."); 394 | } 395 | } 396 | break; 397 | default: 398 | throw new Error("Unrecognized type tag."); 399 | } 400 | } 401 | 402 | addParameterList(elementType: null | Type__InstanceR, acc: Acc): void { 403 | if (elementType === null) { 404 | elementType = Type.empty(); 405 | } 406 | 407 | switch (elementType.tag()) { 408 | case Type.tags.void: 409 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 410 | acc.value["reader-core"]["VoidList"] = this.mangle("VoidList"); 411 | break; 412 | case Type.tags.bool: 413 | acc.type["reader-core"]["BoolListGutsR"] = this.mangle("BoolListGutsR"); 414 | acc.value["reader-core"]["BoolList"] = this.mangle("BoolList"); 415 | break; 416 | case Type.tags.int8: 417 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 418 | acc.value["reader-core"]["Int8List"] = this.mangle("Int8List"); 419 | break; 420 | case Type.tags.int16: 421 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 422 | acc.value["reader-core"]["Int16List"] = this.mangle("Int16List"); 423 | break; 424 | case Type.tags.int32: 425 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 426 | acc.value["reader-core"]["Int32List"] = this.mangle("Int32List"); 427 | break; 428 | case Type.tags.int64: 429 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 430 | acc.value["reader-core"]["Int64List"] = this.mangle("Int64List"); 431 | break; 432 | case Type.tags.uint8: 433 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 434 | acc.value["reader-core"]["UInt8List"] = this.mangle("UInt8List"); 435 | break; 436 | case Type.tags.uint16: 437 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 438 | acc.value["reader-core"]["UInt16List"] = this.mangle("UInt16List"); 439 | break; 440 | case Type.tags.uint32: 441 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 442 | acc.value["reader-core"]["UInt32List"] = this.mangle("UInt32List"); 443 | break; 444 | case Type.tags.uint64: 445 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 446 | acc.value["reader-core"]["UInt64List"] = this.mangle("UInt64List"); 447 | break; 448 | case Type.tags.float32: 449 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 450 | acc.value["reader-core"]["Float32List"] = this.mangle("Float32List"); 451 | break; 452 | case Type.tags.float64: 453 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 454 | acc.value["reader-core"]["Float64List"] = this.mangle("Float64List"); 455 | break; 456 | case Type.tags.text: 457 | acc.type["reader-core"]["PointerListR"] = this.mangle("PointerListR"); 458 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 459 | acc.value["reader-core"]["Text"] = this.mangle("Text"); 460 | acc.value["reader-core"]["pointers"] = "pointers"; 461 | break; 462 | case Type.tags.data: 463 | acc.type["reader-core"]["PointerListR"] = this.mangle("PointerListR"); 464 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 465 | acc.value["reader-core"]["Data"] = this.mangle("Data"); 466 | acc.value["reader-core"]["pointers"] = "pointers"; 467 | break; 468 | case Type.tags.list: 469 | acc.type["reader-core"]["PointerListR"] = this.mangle("PointerListR"); 470 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 471 | acc.value["reader-core"]["pointers"] = "pointers"; 472 | this.addList(elementType.getList().getElementType(), acc); 473 | break; 474 | case Type.tags.enum: 475 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 476 | acc.type["reader-core"]["UInt16List"] = this.mangle("UInt16List"); 477 | break; 478 | case Type.tags.struct: 479 | acc.type["reader-core"]["StructGutsR"] = this.mangle("StructGutsR"); 480 | acc.type["reader-core"]["StructListR"] = this.mangle("StructListR"); 481 | acc.value["reader-core"]["structs"] = "structs"; 482 | break; 483 | case Type.tags.interface: 484 | throw new Error("TODO"); 485 | case Type.tags.anyPointer: 486 | { 487 | const anyPointerGroup = Type.groups.anyPointer; 488 | const anyPointer = elementType.getAnyPointer(); 489 | switch (anyPointer.tag()) { 490 | case anyPointerGroup.tags.unconstrained: 491 | { 492 | const unconstrainedGroup = anyPointerGroup.groups.unconstrained; 493 | const unconstrained = anyPointer.getUnconstrained(); 494 | switch (unconstrained.tag()) { 495 | case unconstrainedGroup.tags.anyKind: 496 | throw new Error("Forbidden type: List(AnyPointer)."); 497 | case unconstrainedGroup.tags.struct: 498 | throw new Error("Forbidden type: List(AnyStruct)."); 499 | case unconstrainedGroup.tags.list: 500 | //TODO: None of my current schemata use a `List(AnyList)`. Be sure that this gets tested. 501 | acc.type["reader-core"]["BoolListGutsR"] = this.mangle("BoolListGutsR"); 502 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 503 | acc.value["reader-core"]["ListValue"] = this.mangle("ListValue"); 504 | break; 505 | case unconstrainedGroup.tags.capability: 506 | throw new Error("TODO"); 507 | default: 508 | throw new Error("Unrecognized unconstrained-AnyPointer tag."); 509 | } 510 | } 511 | break; 512 | case anyPointerGroup.tags.parameter: 513 | throw new Error("Forbidden type: List(T) for some parameter T"); 514 | case anyPointerGroup.tags.implicitMethodParameter: 515 | throw new Error("TODO"); 516 | default: 517 | throw new Error("Unrecognized any pointer tag."); 518 | } 519 | } 520 | break; 521 | default: 522 | throw new Error("Unrecognized type tag."); 523 | } 524 | } 525 | 526 | //TODO: Flag on Flow to stop treating uncalled functions as any. If you forget the parens, then you get errors silenced. 527 | addList(elementType: null | Type__InstanceR, acc: Acc): void { 528 | if (elementType === null) { 529 | elementType = Type.empty(); 530 | } 531 | 532 | switch (elementType.tag()) { 533 | case Type.tags.void: 534 | acc.value["reader-core"]["VoidList"] = this.mangle("VoidList"); 535 | break; 536 | case Type.tags.bool: 537 | acc.value["reader-core"]["BoolList"] = this.mangle("BoolList"); 538 | break; 539 | case Type.tags.int8: 540 | acc.value["reader-core"]["Int8List"] = this.mangle("Int8List"); 541 | break; 542 | case Type.tags.int16: 543 | acc.value["reader-core"]["Int16List"] = this.mangle("Int16List"); 544 | break; 545 | case Type.tags.int32: 546 | acc.value["reader-core"]["Int32List"] = this.mangle("Int32List"); 547 | break; 548 | case Type.tags.int64: 549 | acc.value["reader-core"]["Int64List"] = this.mangle("Int64List"); 550 | break; 551 | case Type.tags.uint8: 552 | acc.value["reader-core"]["UInt8List"] = this.mangle("UInt8List"); 553 | break; 554 | case Type.tags.uint16: 555 | acc.value["reader-core"]["UInt16List"] = this.mangle("UInt16List"); 556 | break; 557 | case Type.tags.uint32: 558 | acc.value["reader-core"]["UInt32List"] = this.mangle("UInt32List"); 559 | break; 560 | case Type.tags.uint64: 561 | acc.value["reader-core"]["UInt64List"] = this.mangle("UInt64List"); 562 | break; 563 | case Type.tags.float32: 564 | acc.value["reader-core"]["Float32List"] = this.mangle("Float32List"); 565 | break; 566 | case Type.tags.float64: 567 | acc.value["reader-core"]["Float64List"] = this.mangle("Float64List"); 568 | break; 569 | case Type.tags.text: 570 | acc.type["reader-core"]["PointerListR"] = this.mangle("PointerListR"); 571 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 572 | acc.value["reader-core"]["Text"] = this.mangle("Text"); 573 | acc.value["reader-core"]["pointers"] = "pointers"; 574 | break; 575 | case Type.tags.data: 576 | acc.type["reader-core"]["PointerListR"] = this.mangle("PointerListR"); 577 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 578 | acc.value["reader-core"]["Data"] = this.mangle("Data"); 579 | acc.value["reader-core"]["pointers"] = "pointers"; 580 | break; 581 | case Type.tags.list: 582 | acc.type["reader-core"]["PointerListR"] = this.mangle("PointerListR"); 583 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 584 | acc.value["reader-core"]["pointers"] = "pointers"; 585 | this.addList(elementType.getList().getElementType(), acc); 586 | break; 587 | case Type.tags.enum: 588 | acc.type["reader-core"]["UInt16List"] = this.mangle("UInt16List"); 589 | break; 590 | case Type.tags.struct: 591 | acc.type["reader-core"]["StructListR"] = this.mangle("StructListR"); 592 | acc.value["reader-core"]["structs"] = "structs"; 593 | break; 594 | case Type.tags.interface: 595 | throw new Error("TODO"); 596 | case Type.tags.anyPointer: 597 | { 598 | const anyPointerGroup = Type.groups.anyPointer; 599 | const anyPointer = elementType.getAnyPointer(); 600 | switch (anyPointer.tag()) { 601 | case anyPointerGroup.tags.unconstrained: 602 | { 603 | const unconstrainedGroup = anyPointerGroup.groups.unconstrained; 604 | const unconstrained = anyPointer.getUnconstrained(); 605 | switch (unconstrained.tag()) { 606 | case unconstrainedGroup.tags.anyKind: 607 | throw new Error("Forbidden type: List(AnyPointer)."); 608 | case unconstrainedGroup.tags.struct: 609 | throw new Error("Forbidden type: List(AnyStruct)."); 610 | case unconstrainedGroup.tags.list: 611 | //TODO: None of my current schemata use a `List(AnyList)`. Be sure that this gets tested. 612 | acc.type["reader-core"]["BoolListGutsR"] = this.mangle("BoolListGutsR"); 613 | acc.type["reader-core"]["NonboolListGutsR"] = this.mangle("NonboolListGutsR"); 614 | acc.value["reader-core"]["ListValue"] = this.mangle("ListValue"); 615 | break; 616 | case unconstrainedGroup.tags.capability: 617 | throw new Error("TODO"); 618 | default: 619 | throw new Error("Unrecognized unconstrained-AnyPointer tag."); 620 | } 621 | } 622 | break; 623 | case anyPointerGroup.tags.parameter: 624 | throw new Error("Forbidden type: List(T) for some parameter T"); 625 | case anyPointerGroup.tags.implicitMethodParameter: 626 | throw new Error("TODO"); 627 | default: 628 | throw new Error("Unrecognized any pointer tag."); 629 | } 630 | } 631 | break; 632 | default: 633 | throw new Error("Unrecognized type tag."); 634 | } 635 | } 636 | 637 | addStruct(brand: null | Brand__InstanceR, acc: Acc): void { 638 | if (brand !== null) { 639 | const scopes = brand.getScopes(); 640 | if (scopes !== null) { 641 | scopes.forEach(scope => { 642 | if (scope.tag() === Brand.Scope.tags.bind) { 643 | const bind = scope.getBind(); 644 | if (bind !== null) { 645 | bind.forEach(binding => { 646 | if (binding.tag() === Brand.Binding.tags.type) { 647 | this.addParameterType(binding.getType(), acc); 648 | } 649 | }); 650 | } 651 | } 652 | }); 653 | } 654 | } 655 | } 656 | } 657 | 658 | export default function accumulateReaderLibs(index: Index, fileId: UInt64, names: Set): Libs { 659 | const internalAcc = new LibsVisitor(index, names).visit(fileId, { 660 | aliases: {}, 661 | type: { 662 | int64: {}, 663 | uint64: {}, 664 | layout: {}, 665 | memory: {}, 666 | "reader-core": {}, 667 | "builder-core": {}, 668 | }, 669 | value: { 670 | int64: {}, 671 | uint64: {}, 672 | layout: {}, 673 | memory: {}, 674 | "reader-core": {}, 675 | "builder-core": {}, 676 | "reader-arena": {}, 677 | }, 678 | "all-value": { 679 | "read-data": null, 680 | "write-data": null, 681 | }, 682 | }); 683 | 684 | const libNames = new Set(); 685 | 686 | addNames(internalAcc.type.int64, libNames); 687 | addNames(internalAcc.type.uint64, libNames); 688 | addNames(internalAcc.type.layout, libNames); 689 | addNames(internalAcc.type.memory, libNames); 690 | addNames(internalAcc.type["reader-core"], libNames); 691 | addNames(internalAcc.type["builder-core"], libNames); 692 | addNames(internalAcc.value.int64, libNames); 693 | addNames(internalAcc.value.uint64, libNames); 694 | addNames(internalAcc.value.layout, libNames); 695 | addNames(internalAcc.value.memory, libNames); 696 | addNames(internalAcc.value["reader-core"], libNames); 697 | addNames(internalAcc.value["builder-core"], libNames); 698 | 699 | return { ...internalAcc, names: libNames }; 700 | } 701 | -------------------------------------------------------------------------------- /src/serialization/accumulateUsers.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type { UInt64 } from "@capnp-js/uint64"; 4 | 5 | import type { default as Index, Scope } from "../Index"; 6 | import type { Node__InstanceR, Type__InstanceR } from "../schema.capnp-r"; 7 | 8 | import { toHex } from "@capnp-js/uint64"; 9 | 10 | import Visitor from "../Visitor"; 11 | import { Field, Type } from "../schema.capnp-r"; 12 | 13 | type Acc = { [uuid: string]: $ReadOnlyArray }; 14 | 15 | interface Users { 16 | +imports: { 17 | [fileUuid: string]: { 18 | [naive: string]: string, 19 | }, 20 | }; 21 | +identifiers: { [uuid: string]: string }; 22 | } 23 | 24 | class UsersVisitor extends Visitor { 25 | struct(node: Node__InstanceR, acc: Acc): Acc { 26 | const struct = node.getStruct(); 27 | const fields = struct.getFields(); 28 | if (fields !== null) { 29 | fields.forEach(field => { 30 | switch (field.tag()) { 31 | case Field.tags.slot: 32 | this.addType(field.getSlot().getType(), acc); 33 | break; 34 | case Field.tags.group: 35 | { 36 | /* Dig into the struct's groups for their field types too. */ 37 | //TODO: Grep for this.struct calls that should be this.visit calls. 38 | this.visit(field.getGroup().getTypeId(), acc); 39 | } 40 | break; 41 | default: throw new Error("Unrecognized field tag."); 42 | } 43 | }); 44 | } 45 | 46 | return super.struct(node, acc); 47 | } 48 | 49 | interface(node: Node__InstanceR, acc: Acc): Acc { 50 | const methods = node.getInterface().getMethods(); 51 | if (methods !== null) { 52 | methods.forEach(method => { 53 | const paramId = method.getParamStructType(); 54 | const param = this.index.getNode(paramId); 55 | const paramScopeId = param.getScopeId(); 56 | if (paramScopeId[0] === 0 && paramScopeId[1] === 0) { 57 | acc = this.visit(paramId, acc); 58 | } else { 59 | acc[toHex(paramId)] = this.index.getScopes(paramId); 60 | } 61 | 62 | const resultId = method.getResultStructType(); 63 | const result = this.index.getNode(resultId); 64 | const resultScopeId = result.getScopeId(); 65 | if (resultScopeId[0] === 0 && resultScopeId[1] === 0) { 66 | acc = this.visit(paramId, acc); 67 | } else { 68 | acc[toHex(resultId)] = this.index.getScopes(resultId); 69 | } 70 | }); 71 | } 72 | 73 | return super.interface(node, acc); 74 | } 75 | 76 | addType(type: null | Type__InstanceR, acc: Acc): void { 77 | if (type === null) { 78 | type = Type.empty(); 79 | } 80 | 81 | switch (type.tag()) { 82 | case Type.tags.void: 83 | case Type.tags.bool: 84 | case Type.tags.int8: 85 | case Type.tags.int16: 86 | case Type.tags.int32: 87 | case Type.tags.int64: 88 | case Type.tags.uint8: 89 | case Type.tags.uint16: 90 | case Type.tags.uint32: 91 | case Type.tags.uint64: 92 | case Type.tags.float32: 93 | case Type.tags.float64: 94 | case Type.tags.text: 95 | case Type.tags.data: 96 | case Type.tags.enum: 97 | break; 98 | 99 | case Type.tags.list: 100 | this.addType(type.getList().getElementType(), acc); 101 | break; 102 | 103 | case Type.tags.struct: 104 | { 105 | const id = type.getStruct().getTypeId(); 106 | acc[toHex(id)] = this.index.getScopes(id); 107 | } 108 | break; 109 | 110 | case Type.tags.interface: 111 | //TODO: Eventually I might associate capabilities to particular interfaces 112 | // similar to how Orphan<> works. 113 | break; 114 | 115 | case Type.tags.anyPointer: 116 | break; 117 | 118 | default: 119 | throw new Error("Unrecognized type tag."); 120 | } 121 | } 122 | } 123 | 124 | function shortestUniques(uuids: Array): { +[uuid: string]: string } { 125 | const fixedWidthUuids = uuids.map(uuid => { 126 | /* Remove the leading `0x`. */ 127 | const narrow = uuid.slice(2); 128 | 129 | const pad = "0000000000000000"; 130 | 131 | return narrow + pad.slice(narrow.length); 132 | }); 133 | 134 | for (let t=1; t<16; ++t) { 135 | /* Hypothesize that I've already found a truncated length under which all of 136 | the uuids remain unique. */ 137 | let unique = true; 138 | 139 | /* Exhaustively search for a collision under truncated length `t`. */ 140 | for (let i=0; i, collisions: NameCollisions): void { 179 | const naive = scopes[0].name; 180 | const uuid = toHex(scopes[0].node.getId()); 181 | 182 | if (!collisions[naive]) { 183 | collisions[naive] = {}; 184 | } 185 | 186 | if (!collisions[naive][uuid]) { 187 | collisions[naive][uuid] = { 188 | fileId: null, 189 | subscopes: {}, 190 | }; 191 | } 192 | 193 | if (scopes.length === 1) { 194 | collisions[naive][uuid].fileId = fileId; 195 | } else { 196 | insertCollision(fileId, scopes.slice(1), collisions[naive][uuid].subscopes); 197 | } 198 | } 199 | 200 | type Path = { 201 | naive: Array, 202 | local: Array, 203 | }; 204 | 205 | function mangle(names: Set, path: Path, collisions: NameCollisions, mangled: Users): void { 206 | Object.keys(collisions).forEach(naive => { 207 | const uuids = Object.keys(collisions[naive]); 208 | 209 | /* Create a speculative base name for now. I may append some UUID characters 210 | at its tail to obtain the actual base name. */ 211 | const baseName = path.local.length === 0 ? naive : path.local.join("_") + "_" + naive; 212 | 213 | if (uuids.length === 1 && !names.has(baseName)) { 214 | const uuid = uuids[0]; 215 | 216 | /* There's no name collision, so my `baseName` can get used as-is. */ 217 | path = { 218 | naive: path.naive.concat([naive]), 219 | local: path.local.concat([naive]), 220 | }; 221 | const singleton = collisions[naive][uuid]; 222 | if (singleton.fileId !== null) { 223 | /* The current path is itself imported, so I add it to the `mangled` 224 | data structure. */ 225 | const fileUuid = toHex(singleton.fileId); 226 | if (!mangled.imports[fileUuid]) { 227 | mangled.imports[fileUuid] = {}; 228 | } 229 | mangled.imports[fileUuid][path.naive.join("_")] = path.local.join("_"); 230 | mangled.identifiers[uuid] = path.local.join("_"); 231 | } 232 | mangle(names, path, singleton.subscopes, mangled); 233 | } else { 234 | const uniques = shortestUniques(uuids); 235 | for (let i=0; i): Users { 259 | const scopes = new UsersVisitor(index).visit(fileId, {}); 260 | 261 | const collisions = {}; 262 | for (let uuid in scopes) { 263 | const path = scopes[uuid]; 264 | const hostFileId = path[0].node.getId(); 265 | 266 | //TODO: Clobber util/hostFile.js 267 | if (!(hostFileId[0] === fileId[0] && hostFileId[1] === fileId[1])) { 268 | insertCollision(hostFileId, path.slice(1), collisions); 269 | } 270 | } 271 | 272 | const mangled = { 273 | imports: {}, 274 | identifiers: {}, 275 | }; 276 | mangle(names, { naive: [], local: [] }, collisions, mangled); 277 | 278 | return mangled; 279 | } 280 | -------------------------------------------------------------------------------- /src/serialization/accumulateValues.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type { UInt64 } from "@capnp-js/uint64"; 4 | import type { SegmentB, Word } from "@capnp-js/memory"; 5 | 6 | import type Index from "../Index"; 7 | import type { Node__InstanceR, Value__InstanceR } from "../schema.capnp-r"; 8 | 9 | import { toHex } from "@capnp-js/uint64"; 10 | import { AnyValue } from "@capnp-js/reader-core"; 11 | import { Unlimited } from "@capnp-js/base-arena"; 12 | import { Builder } from "@capnp-js/builder-arena"; 13 | import { create, getSubarray } from "@capnp-js/bytes"; 14 | 15 | import { array as injectArray } from "@capnp-js/trans-inject"; 16 | import { startEncodeSync as startStream } from "@capnp-js/trans-stream"; 17 | import { transEncodeSync as packing } from "@capnp-js/trans-packing"; 18 | import { transEncodeSync as alignment } from "@capnp-js/trans-align-bytes"; 19 | import { finishEncodeSync as base64 } from "@capnp-js/trans-base64"; 20 | import { concat } from "@capnp-js/trans-concat"; 21 | 22 | import Visitor from "../Visitor"; 23 | import { nonnull } from "@capnp-js/nullary"; 24 | import { Field, Value } from "../schema.capnp-r"; 25 | 26 | type uint = number; 27 | type u32 = number; 28 | 29 | export type MetaWord = { 30 | segmentId: u32, 31 | position: uint, 32 | }; 33 | 34 | //TODO: Should the blob from an earlier visitor intertwine with the logic here? 35 | // At least it decides whether to begin this stage at all. 36 | export type Values = { 37 | blob: string, 38 | defaults: { 39 | [hostUuid: string]: { 40 | [name: string]: MetaWord, 41 | }, 42 | }, 43 | constants: { 44 | [uuid: string]: MetaWord, 45 | }, 46 | }; 47 | 48 | type Acc = { 49 | blob: null | Builder, 50 | defaults: { 51 | [hostUuid: string]: { 52 | [name: string]: MetaWord, 53 | }, 54 | }, 55 | constants: { 56 | [uuid: string]: MetaWord, 57 | }, 58 | }; 59 | 60 | class ValuesVisitor extends Visitor { 61 | allocateDefault(hostUuid: string, field: string, acc: Acc): Word { 62 | if (acc.blob === null) { 63 | acc.blob = Builder.fresh(2048, new Unlimited()); 64 | } 65 | 66 | if (!acc.defaults[hostUuid]) { 67 | acc.defaults[hostUuid] = {}; 68 | } 69 | 70 | const ref = acc.blob.allocate(8); 71 | acc.defaults[hostUuid][field] = { 72 | segmentId: ref.segment.id, 73 | position: ref.position, 74 | }; 75 | 76 | return ref; 77 | } 78 | 79 | allocateConstant(uuid: string, acc: Acc): Word { 80 | if (acc.blob === null) { 81 | acc.blob = Builder.fresh(2048, new Unlimited()); 82 | } 83 | 84 | const ref = acc.blob.allocate(8); 85 | acc.constants[uuid] = { 86 | segmentId: ref.segment.id, 87 | position: ref.position, 88 | }; 89 | 90 | return ref; 91 | } 92 | 93 | getValue(value: Value__InstanceR): null | AnyValue { 94 | switch (value.tag()) { 95 | case Value.tags.void: 96 | case Value.tags.bool: 97 | case Value.tags.int8: 98 | case Value.tags.int16: 99 | case Value.tags.int32: 100 | case Value.tags.int64: 101 | case Value.tags.uint8: 102 | case Value.tags.uint16: 103 | case Value.tags.uint32: 104 | case Value.tags.uint64: 105 | case Value.tags.float32: 106 | case Value.tags.float64: 107 | return null; 108 | 109 | case Value.tags.text: return AnyValue.intern(nonnull(value.getText()).guts); 110 | case Value.tags.data: return AnyValue.intern(nonnull(value.getData()).guts); 111 | case Value.tags.list: return nonnull(value.getList()); 112 | case Value.tags.enum: 113 | return null; 114 | case Value.tags.struct: return nonnull(value.getStruct()); 115 | case Value.tags.interface: 116 | return null; 117 | case Value.tags.anyPointer: return nonnull(value.getAnyPointer()); 118 | default: 119 | throw new Error("Unrecognized value tag."); 120 | } 121 | } 122 | 123 | struct(node: Node__InstanceR, acc: Acc): Acc { 124 | const hostUuid = toHex(node.getId()); 125 | const struct = node.getStruct(); 126 | const fields = struct.getFields(); 127 | if (fields !== null) { 128 | fields.forEach(field => { 129 | const name = nonnull(field.getName()).toString(); 130 | switch (field.tag()) { 131 | case Field.tags.slot: 132 | { 133 | const slot = field.getSlot(); 134 | if (slot.getHadExplicitDefault()) { 135 | const value = this.getValue(nonnull(slot.getDefaultValue())); 136 | if (value !== null) { 137 | const ref = this.allocateDefault(hostUuid, name, acc); 138 | value.guts.set(0, ((acc.blob: any): Builder), ref); // eslint-disable-line flowtype/no-weak-types 139 | } 140 | } 141 | } 142 | break; 143 | case Field.tags.group: 144 | { 145 | /* Dig into the struct's groups for their defaults too. */ 146 | this.visit(field.getGroup().getTypeId(), acc); 147 | } 148 | break; 149 | default: 150 | throw new Error("Unrecognized field tag"); 151 | } 152 | }); 153 | } 154 | 155 | return super.struct(node, acc); 156 | } 157 | 158 | //TODO: Interfaces can contain constants. Implement the interface handler. 159 | 160 | const(node: Node__InstanceR, acc: Acc): Acc { 161 | let value = node.getConst().getValue(); 162 | if (value === null) { 163 | value = Value.empty(); 164 | } 165 | 166 | value = this.getValue(value); 167 | if (value !== null) { 168 | const uuid = toHex(node.getId()).toString(); 169 | const ref = this.allocateConstant(uuid, acc); 170 | value.guts.set(0, ((acc.blob: any): Builder), ref); // eslint-disable-line flowtype/no-weak-types 171 | } 172 | 173 | return super.const(node, acc); 174 | } 175 | } 176 | 177 | /* I reuse the same buffers for everything. Before calling `header` or 178 | `segment`, I must complete iterating prior call results. Otherwise data will 179 | get clobbered. */ 180 | const start = startStream(create(2048)); 181 | const pack = packing(create(2048)); 182 | const align = alignment(3); 183 | 184 | export default function accumulateValues(index: Index, fileId: UInt64): null | Values { 185 | const internalAcc = new ValuesVisitor(index).visit(fileId, { 186 | blob: null, 187 | defaults: {}, 188 | constants: {}, 189 | }); 190 | 191 | if (internalAcc.blob === null) { 192 | return null; 193 | } else { 194 | const raws = internalAcc.blob.segments.map(s => getSubarray(0, s.end, s.raw)); 195 | const b64 = base64(align(pack(concat(start(raws), injectArray(raws))))); 196 | if (b64 instanceof Error) { 197 | throw b64; 198 | } else { 199 | return { 200 | blob: b64, 201 | defaults: internalAcc.defaults, 202 | constants: internalAcc.constants, 203 | }; 204 | } 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /src/serialization/generate.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type Index from "../Index"; 4 | import type { CodeGeneratorRequest_RequestedFile__InstanceR } from "../schema.capnp-r"; 5 | import type { Values } from "./accumulateValues"; 6 | 7 | import * as path from "path"; 8 | import { writeFile } from "fs"; 9 | import { nonnull } from "@capnp-js/nullary"; 10 | import { toHex } from "@capnp-js/uint64"; 11 | 12 | import Printer from "../Printer"; 13 | import accumulateLocals from "./accumulateLocals"; 14 | import accumulateReaderLibs from "./accumulateReaderLibs"; 15 | import accumulateBuilderLibs from "./accumulateBuilderLibs"; 16 | import accumulateUsers from "./accumulateUsers"; 17 | import accumulateValues from "./accumulateValues"; 18 | import accumulateParameters from "./accumulateParameters"; 19 | import printReaderBodies from "./printReaderBodies"; 20 | import printBuilderBodies from "./printBuilderBodies"; 21 | import printReaderInstantiations from "./printReaderInstantiations"; 22 | import printBuilderInstantiations from "./printBuilderInstantiations"; 23 | 24 | type RequestedFile = CodeGeneratorRequest_RequestedFile__InstanceR; 25 | 26 | function baseFilename(file: RequestedFile): string { 27 | const source = nonnull(file.getFilename()).toString(); 28 | const prefix = source.charAt(0) === "." ? "" : "./"; 29 | 30 | return prefix + source; 31 | } 32 | 33 | export function values(index: Index, file: RequestedFile): null | Values { 34 | const vs = accumulateValues(index, file.getId()); 35 | if (vs !== null) { 36 | const p = new Printer(2); 37 | 38 | p.line("/* @flow */"); 39 | p.interrupt(); 40 | p.line("import type { Reader } from \"@capnp-js/reader-arena\";"); 41 | p.line("import { deserializeUnsafe } from \"@capnp-js/reader-arena\";"); 42 | p.interrupt(); 43 | p.line(`const blob: Reader = deserializeUnsafe("${vs.blob}");`); 44 | p.line("export default blob;"); 45 | 46 | const filename = baseFilename(file) + "-blob.js"; 47 | writeFile(filename, p.text, { encoding: "utf8" }, err => { 48 | if (err) { 49 | throw err; 50 | } 51 | }); 52 | 53 | return vs; 54 | } else { 55 | return null; 56 | } 57 | } 58 | 59 | export type Strategy = { 60 | tag: "reader" | "builder", 61 | filename(base: string): string, 62 | suffix(base: string): string, 63 | }; 64 | 65 | export function classes(index: Index, values: null | Values, strategy: Strategy, file: RequestedFile): void { 66 | const p = new Printer(2); 67 | 68 | p.line("/* @flow */"); 69 | 70 | /* Accumulator for names so that I can test for name collisions. */ 71 | const names = new Set(); 72 | 73 | /* I'll construct the `identifiers` accumulator from seperate dictionaries 74 | once they're all available. */ 75 | 76 | /* The data types constructed within a serialization file never have their 77 | names mangled. Upon collision, the imported name(s) get mangled. Before 78 | generating anything I've got to scan the file's member names. Non- 79 | capitalized names cannot collide by construction (`inject` from 80 | @capnp-js/int64 and @capnp-js/uint64 are exceptions, but I would alias them 81 | for readability even in the absence of the collision). */ 82 | const locals = accumulateLocals(index, file.getId()); 83 | locals.names.forEach(name => names.add(name)); 84 | 85 | /* A serialization file (suffixed `-r` or `-b`) consists of 5 sections. */ 86 | 87 | p.interrupt(); 88 | 89 | /* Section 1: Library Imports 90 | The `@capnp-js` scope contains all sorts of types and helpers that 91 | serialization code uses. The imported types have capitalized names that may 92 | collide with serialization code; such imports get their names mangled. 93 | Since `locals` contains all of the capitalized local base names, it 94 | contains sufficient information to mangle any collisions found among the 95 | imports. User imports and type aliases are left to another section because 96 | I don't need seperate reader and builder versions for those types. */ 97 | let libs; 98 | if (strategy.tag === "reader") { 99 | libs = accumulateReaderLibs(index, file.getId(), names); 100 | } else { 101 | (strategy.tag: "builder"); 102 | libs = accumulateBuilderLibs(index, file.getId(), names); 103 | } 104 | libs.names.forEach(name => names.add(name)); 105 | 106 | /* Library types */ 107 | for (let source in libs.type) { 108 | const lib = libs.type[source]; 109 | if (Object.keys(lib).length === 1) { 110 | Object.keys(lib).forEach(type => { 111 | if (lib[type] === type) { 112 | p.line(`import type { ${type} } from "@capnp-js/${source}";`); 113 | } else { 114 | p.line(`import type { ${type} as ${lib[type]} } from "@capnp-js/${source}";`); 115 | } 116 | }); 117 | } else if (Object.keys(lib).length > 1) { 118 | p.line("import type {"); 119 | const keys = Object.keys(lib); 120 | keys.sort(); 121 | keys.forEach(type => { 122 | p.indent(p => { 123 | if (lib[type] === type) { 124 | p.line(`${type},`); 125 | } else { 126 | p.line(`${type} as ${lib[type]},`); 127 | } 128 | }); 129 | }); 130 | p.line(`} from "@capnp-js/${source}";`); 131 | } 132 | } 133 | 134 | p.interrupt(); 135 | 136 | /* Library indices */ 137 | for (let source in libs["all-value"]) { 138 | const name = libs["all-value"][source]; 139 | if (name !== null) { 140 | p.line(`import * as ${name} from "@capnp-js/${source}";`); 141 | } 142 | } 143 | 144 | /* Library values */ 145 | for (let source in libs.value) { 146 | const lib = libs.value[source]; 147 | if (Object.keys(lib).length === 1) { 148 | Object.keys(lib).forEach(value => { 149 | if (lib[value] === value) { 150 | p.line(`import { ${value} } from "@capnp-js/${source}";`); 151 | } else { 152 | p.line(`import { ${value} as ${lib[value]} } from "@capnp-js/${source}";`); 153 | } 154 | }); 155 | } else if (Object.keys(lib).length > 1) { 156 | p.line("import {"); 157 | const keys = Object.keys(lib); 158 | keys.sort(); 159 | keys.forEach(value => { 160 | p.indent(p => { 161 | if (lib[value] === value) { 162 | p.line(`${value},`); 163 | } else { 164 | p.line(`${value} as ${lib[value]},`); 165 | } 166 | }); 167 | }); 168 | p.line(`} from "@capnp-js/${source}";`); 169 | } 170 | } 171 | 172 | /* pointerCopy */ 173 | if (strategy.tag === "builder" && values !== null) { 174 | if (Object.keys(values.defaults).length > 0) { 175 | p.line("import { pointerCopy } from \"@capnp-js/copy-pointers\";"); 176 | } 177 | } 178 | 179 | p.interrupt(); 180 | 181 | /* Section 2: Reader Imports (builder only) 182 | Each builder instance exposes a `reader` method to derive a read-only 183 | instance for the builder's data. The `reader` method requires the reader's 184 | type. */ 185 | if (strategy.tag === "builder") { 186 | const baseName = path.basename(nonnull(file.getFilename()).toString()); 187 | const source = `./${baseName}-r`; 188 | if (locals.structs.size + locals.paramStructs.size + locals.resultStructs.size === 1) { 189 | locals.structs.forEach(name => { 190 | p.line(`import type { ${name}__InstanceR } from "${source}";`); 191 | }); 192 | locals.paramStructs.forEach(name => { 193 | p.line(`import type { ${name}__ParamInstanceR } from "${source}";`); 194 | }); 195 | locals.resultStructs.forEach(name => { 196 | p.line(`import type { ${name}__ResultInstanceR } from "${source}";`); 197 | }); 198 | } else if (locals.structs.size > 1) { 199 | p.line("import type {"); 200 | p.indent(p => { 201 | locals.structs.forEach(name => { 202 | p.line(`${name}__InstanceR,`); 203 | }); 204 | locals.paramStructs.forEach(name => { 205 | p.line(`${name}__ParamInstanceR,`); 206 | }); 207 | locals.resultStructs.forEach(name => { 208 | p.line(`${name}__ResultInstanceR,`); 209 | }); 210 | }); 211 | p.line(`} from "${source}";`); 212 | } 213 | } 214 | 215 | p.interrupt(); 216 | 217 | /* Section 3: User Imports and Type Aliases 218 | Cap'n Proto schema files admit user imports where the unqualified names may 219 | collide with local names. I scan all of the imports and mangle a name if it 220 | collides with a local name. */ 221 | const users = accumulateUsers(index, file.getId(), names); 222 | const identifiers = { ...locals.identifiers, ...users.identifiers }; 223 | 224 | /* User imports */ 225 | { 226 | const imports = file.getImports(); 227 | const table = {}; 228 | if (imports !== null) { 229 | imports.forEach(import_ => { 230 | table[toHex(import_.getId())] = nonnull(import_.getName()).toString(); 231 | }); 232 | 233 | for (let fileUuid in users.imports) { 234 | let filename = strategy.filename(table[fileUuid]); 235 | if (filename.charAt(0) === "/") { 236 | throw new Error("Non-relative imports are not supported."); 237 | } else if (filename.charAt(0) !== ".") { 238 | filename = "./" + filename; 239 | } 240 | 241 | if (Object.keys(users.imports[fileUuid]).length === 1) { 242 | Object.keys(users.imports[fileUuid]).forEach(naiveBaseName => { 243 | const localBaseName = users.imports[fileUuid][naiveBaseName]; 244 | const naiveName = strategy.suffix(`${naiveBaseName}__Instance`); 245 | if (naiveBaseName === localBaseName) { 246 | p.line(`import type { ${naiveName} } from "${filename}";`); 247 | } else { 248 | const localName = strategy.suffix(`${localBaseName}__Instance`); 249 | p.line(`import type { ${naiveName} as ${localName} } from "${filename}";`); 250 | } 251 | }); 252 | } else { 253 | p.line("import type {"); 254 | p.indent(p => { 255 | Object.keys(users.imports[fileUuid]).forEach(naiveBaseName => { 256 | const localBaseName = users.imports[fileUuid][naiveBaseName]; 257 | const naiveName = strategy.suffix(`${naiveBaseName}__Instance`); 258 | if (naiveBaseName === localBaseName) { 259 | p.line(`${naiveName},`); 260 | } else { 261 | const localName = strategy.suffix(`${localBaseName}__Instance`); 262 | p.line(`${naiveName} as ${localName},`); 263 | } 264 | }); 265 | }); 266 | p.line(`} from "${filename}";`); 267 | } 268 | } 269 | 270 | p.interrupt(); 271 | 272 | for (let fileUuid in users.imports) { 273 | let filename = strategy.filename(table[fileUuid]); 274 | if (filename.charAt(0) === "/") { 275 | throw new Error("Non-relative imports are not supported."); 276 | } else if (filename.charAt(0) !== ".") { 277 | filename = "./" + filename; 278 | } 279 | 280 | if (Object.keys(users.imports[fileUuid]).length === 1) { 281 | Object.keys(users.imports[fileUuid]).forEach(naiveBaseName => { 282 | const localBaseName = users.imports[fileUuid][naiveBaseName]; 283 | const naiveName = strategy.suffix(`${naiveBaseName}__Ctor`); 284 | if (naiveBaseName === localBaseName) { 285 | p.line(`import { ${naiveName} } from "${filename}";`); 286 | } else { 287 | const localName = strategy.suffix(`${localBaseName}__Ctor`); 288 | p.line(`import { ${naiveName} as ${localName} } from "${filename}";`); 289 | } 290 | }); 291 | } else { 292 | p.line("import {"); 293 | p.indent(p => { 294 | Object.keys(users.imports[fileUuid]).forEach(naiveBaseName => { 295 | const localBaseName = users.imports[fileUuid][naiveBaseName]; 296 | const naiveName = strategy.suffix(`${naiveBaseName}__Ctor`); 297 | if (naiveBaseName === localBaseName) { 298 | p.line(`${naiveName},`); 299 | } else { 300 | const localName = strategy.suffix(`${localBaseName}__Ctor`); 301 | p.line(`${naiveName} as ${localName},`); 302 | } 303 | }); 304 | }); 305 | p.line(`} from "${filename}";`); 306 | } 307 | } 308 | } 309 | } 310 | 311 | p.interrupt(); 312 | 313 | /* Constant and default values */ 314 | if (values !== null) { 315 | const baseName = path.basename(nonnull(file.getFilename()).toString()); 316 | const blob = `./${baseName}-blob`; 317 | if (strategy.tag === "reader") { 318 | p.line(`import blob from "${blob}";`); 319 | } else { 320 | (strategy.tag: "builder"); 321 | if (Object.keys(values.defaults).length > 0) { 322 | p.line(`import blob from "${blob}";`); 323 | } 324 | } 325 | } 326 | 327 | p.interrupt(); 328 | 329 | /* Type aliases */ 330 | { 331 | const keys = Object.keys(libs.aliases); 332 | keys.sort(); 333 | keys.forEach(alias => p.line(`type ${alias} = ${libs.aliases[alias]};`)); 334 | } 335 | 336 | p.interrupt(); 337 | 338 | /* Section 4: Translated Nodes 339 | Translate Cap'n Proto schema nodes into JavaScript classes. */ 340 | 341 | /* Generic parametrizations */ 342 | const parameters = accumulateParameters(index); 343 | 344 | /* Print bodies */ 345 | if (strategy.tag === "reader") { 346 | printReaderBodies(index, file.getId(), identifiers, parameters, values, p); 347 | } else { 348 | (strategy.tag: "builder"); 349 | printBuilderBodies(index, file.getId(), identifiers, parameters, values, p); 350 | } 351 | 352 | p.interrupt(); 353 | 354 | /* Section 5: Export instantiations of file scoped types from the schema. */ 355 | if (strategy.tag === "reader") { 356 | printReaderInstantiations(index, file.getId(), parameters, p); 357 | } else { 358 | (strategy.tag: "builder"); 359 | printBuilderInstantiations(index, file.getId(), parameters, p); 360 | } 361 | 362 | const filename = strategy.filename(baseFilename(file)) + ".js"; 363 | writeFile(filename, p.text, { encoding: "utf8" }, err => { 364 | if (err) { 365 | throw err; 366 | } 367 | }); 368 | 369 | /* 370 | * A section of library imports. These imports all begin with a 371 | `@capnp-js/`. 372 | * A section of generated imports. These imports all come from other 373 | generated files. 374 | TODO: What about libs? Suppose that I've got some external library. 375 | NodeJS uses an entry point for exports, but I'd rather not aggregate all of the 376 | generated files into a blob (I suspect that this would foil "tree-shaking" reductions). 377 | How about an annotation? How about rejecting all absolute paths. The user can write 378 | the schema to someplace locally refable. Having a single source of truth is nice, though. 379 | * I think that I can use Flow's name_mapper and babel-plugin-module-resolver to make absolute paths work. 380 | * I'm not so sure about aliasing under TypeScript. 381 | * Reject absolute paths for now? 382 | * A section of type aliases for improved readability, e.g. 383 | `type uint = number`. 384 | * A section of constant and/or default values. 385 | * A section generated from the schema file's nodes. 386 | * A section of constructor instantiations. 387 | */ 388 | //TODO: My struct lists need adoptWithCaveats to work with freshly allocated structs, right? Wrong. The bytes were allocated as part of the list. But I should admit adoption into a list. 389 | } 390 | -------------------------------------------------------------------------------- /src/serialization/libs.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export type Libs = { 4 | +names: Set, 5 | +aliases: { [naive: string]: string }, 6 | +type: { 7 | +int64: { [naive: string]: string }, 8 | +uint64: { [naive: string]: string }, 9 | +layout: { [naive: string]: string }, 10 | +memory: { [naive: string]: string }, 11 | +"reader-core": { [naive: string]: string }, 12 | +"builder-core": { [naive: string]: string }, 13 | }, 14 | +value: { 15 | +int64: { [naive: string]: string }, 16 | +uint64: { [naive: string]: string }, 17 | +layout: { [naive: string]: string }, 18 | +memory: { [naive: string]: string }, 19 | +"reader-core": { [naive: string]: string }, 20 | +"builder-core": { [naive: string]: string }, 21 | +"reader-arena": { [naive: string]: string }, 22 | }, 23 | +"all-value": { 24 | "read-data": null | "decode", 25 | "write-data": null | "encode", 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/serialization/printBuilderInstantiations.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type { UInt64 } from "@capnp-js/uint64"; 4 | 5 | import type Index from "../Index"; 6 | import type Printer from "../Printer"; 7 | import type { ParametersIndex } from "./accumulateParameters"; 8 | 9 | import { nonnull } from "@capnp-js/nullary"; 10 | import { toHex } from "@capnp-js/uint64"; 11 | 12 | import { Node } from "../schema.capnp-r"; 13 | 14 | export default function printReaderInstantiations(index: Index, fileId: UInt64, parameters: ParametersIndex, p: Printer): void { 15 | const file = index.getNode(fileId); 16 | const nestedNodes = file.getNestedNodes(); 17 | if (nestedNodes !== null) { 18 | nestedNodes.forEach(nestedNode => { 19 | const uuid = toHex(nestedNode.getId()); 20 | const node = index.getNode(uuid); 21 | const name = nonnull(nestedNode.getName()).toString(); 22 | switch (node.tag()) { 23 | case Node.tags.file: 24 | throw new Error("Invariant broken: File node occurred within another file node."); 25 | case Node.tags.struct: 26 | case Node.tags.interface: 27 | { 28 | if (parameters[uuid].specialize.length > 0) { 29 | p.line(`export const ${name} = new ${name}__GenericB();`); 30 | } else { 31 | p.line(`export const ${name} = new ${name}__CtorB();`); 32 | } 33 | } 34 | break; 35 | case Node.tags.enum: 36 | p.line(`export const ${name} = ${name}__Enum;`); 37 | break; 38 | case Node.tags.const: 39 | break; 40 | case Node.tags.annotation: 41 | break; 42 | default: 43 | throw new Error("Unrecognized node tag."); 44 | } 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/serialization/printReaderInstantiations.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type { UInt64 } from "@capnp-js/uint64"; 4 | 5 | import type Index from "../Index"; 6 | import type Printer from "../Printer"; 7 | import type { ParametersIndex } from "./accumulateParameters"; 8 | 9 | import { nonnull } from "@capnp-js/nullary"; 10 | import { toHex } from "@capnp-js/uint64"; 11 | 12 | import { Node } from "../schema.capnp-r"; 13 | 14 | export default function printReaderInstantiations(index: Index, fileId: UInt64, parameters: ParametersIndex, p: Printer): void { 15 | const file = index.getNode(fileId); 16 | const nestedNodes = file.getNestedNodes(); 17 | if (nestedNodes !== null) { 18 | nestedNodes.forEach(nestedNode => { 19 | const uuid = toHex(nestedNode.getId()); 20 | const node = index.getNode(nestedNode.getId()); 21 | const name = nonnull(nestedNode.getName()).toString(); 22 | switch (node.tag()) { 23 | case Node.tags.file: 24 | throw new Error("Invariant broken: File node occurred within another file node."); 25 | case Node.tags.struct: 26 | case Node.tags.interface: 27 | { 28 | if (parameters[uuid].specialize.length > 0) { 29 | p.line(`export const ${name} = new ${name}__GenericR();`); 30 | } else { 31 | p.line(`export const ${name} = new ${name}__CtorR();`); 32 | } 33 | } 34 | break; 35 | case Node.tags.enum: 36 | p.line(`export const ${name} = ${name}__Enum;`); 37 | break; 38 | case Node.tags.const: 39 | break; 40 | case Node.tags.annotation: 41 | break; 42 | default: 43 | throw new Error("Unrecognized node tag."); 44 | } 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/util/NonRepeats.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | type uint = number; 4 | 5 | export default class NonRepeats { 6 | +array: $ReadOnlyArray; 7 | position: uint; 8 | 9 | constructor(array: $ReadOnlyArray) { 10 | this.array = array; 11 | this.position = 0; 12 | } 13 | 14 | next(): IteratorResult { 15 | if (this.position >= this.array.length) { 16 | return { done: true }; 17 | } 18 | 19 | const value = this.array[this.position]; 20 | do { 21 | ++this.position; 22 | } while (this.array[this.position] === value); 23 | 24 | return { done: false, value }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/util/capitalize.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export default function capitalize(s: string): string { 4 | return s.charAt(0).toUpperCase() + s.slice(1); 5 | } 6 | -------------------------------------------------------------------------------- /src/util/flatMap.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export default function flatMap(arr: $ReadOnlyArray, map: (T => Array)): Array { 4 | return arr.reduce((flat, element) => { 5 | return flat.concat(map(element)); 6 | }, []); 7 | } 8 | -------------------------------------------------------------------------------- /src/util/paramName.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type { UInt64 } from "@capnp-js/uint64"; 4 | 5 | import type Index from "../Index"; 6 | 7 | import { nonnull } from "@capnp-js/nullary"; 8 | 9 | type u16 = number; 10 | 11 | export default function paramName(index: Index, id: UInt64, position: u16): string { 12 | const source = index.getNode(id); 13 | const parameters = nonnull(source.getParameters()); 14 | const name = nonnull(parameters.get(position).getName()).toString(); 15 | const depth = index.getScopes(id).slice(1).length - 1; 16 | 17 | return `${name}_${depth}`; 18 | } 19 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | /*.js 2 | -------------------------------------------------------------------------------- /test/schema/const-bool.capnp: -------------------------------------------------------------------------------- 1 | @0xcbcdf3ef3bc13413; 2 | 3 | const b :Bool = true; 4 | -------------------------------------------------------------------------------- /test/schema/const-data.capnp: -------------------------------------------------------------------------------- 1 | @0x8953ea1f725601f8; 2 | 3 | const data :Data = 0x"a1 88 9b"; 4 | -------------------------------------------------------------------------------- /test/schema/const-enum.capnp: -------------------------------------------------------------------------------- 1 | @0xc9436397729f4fe7; 2 | 3 | enum Trivial { 4 | e @0; 5 | } 6 | 7 | const t :Trivial = e; 8 | -------------------------------------------------------------------------------- /test/schema/const-float32.capnp: -------------------------------------------------------------------------------- 1 | @0xf36484fc0fdef82a; 2 | 3 | const f32 :Float32 = 78398238922313133134458589.313; 4 | -------------------------------------------------------------------------------- /test/schema/const-float64.capnp: -------------------------------------------------------------------------------- 1 | @0xceb133b1a2869208; 2 | 3 | const f64 :Float64 = 217913984782491938393187994756653.376465151612568278428742; 4 | -------------------------------------------------------------------------------- /test/schema/const-genericStructBoolList.capnp: -------------------------------------------------------------------------------- 1 | @0xc3d6544133e64101; 2 | 3 | struct Trivial(T) {} 4 | 5 | const t :Trivial(List(Bool)) = (); 6 | -------------------------------------------------------------------------------- /test/schema/const-genericStructInt16List.capnp: -------------------------------------------------------------------------------- 1 | @0xf3e9bef65079fe4e; 2 | 3 | struct Trivial(T) {} 4 | 5 | const t :Trivial(List(Int16)) = (); 6 | -------------------------------------------------------------------------------- /test/schema/const-genericStructStruct.capnp: -------------------------------------------------------------------------------- 1 | @0xf6a4ffb7283c5e22; 2 | 3 | struct X {} 4 | struct Trivial(T) {} 5 | 6 | const t :Trivial(X) = (); 7 | -------------------------------------------------------------------------------- /test/schema/const-genericStructText.capnp: -------------------------------------------------------------------------------- 1 | @0xbd3fb2d4fe24296b; 2 | 3 | struct Trivial(T) {} 4 | 5 | const t :Trivial(Text) = (); 6 | -------------------------------------------------------------------------------- /test/schema/const-int16.capnp: -------------------------------------------------------------------------------- 1 | @0x832f8171d7529e3f; 2 | 3 | const i16 :Int16 = 31724; 4 | -------------------------------------------------------------------------------- /test/schema/const-int32.capnp: -------------------------------------------------------------------------------- 1 | @0xeba9c90f12257bf0; 2 | 3 | const i32 :Int32 = -2147474912; 4 | -------------------------------------------------------------------------------- /test/schema/const-int64.capnp: -------------------------------------------------------------------------------- 1 | @0x91b422b839e2bd75; 2 | 3 | const i64 :Int64 = -9223372036854685000; 4 | -------------------------------------------------------------------------------- /test/schema/const-int8.capnp: -------------------------------------------------------------------------------- 1 | @0xec7a6ecb7c77a3db; 2 | 3 | const i8 :Int8 = 118; 4 | -------------------------------------------------------------------------------- /test/schema/const-listBool.capnp: -------------------------------------------------------------------------------- 1 | @0xb3b5e0a6b4e4183d; 2 | 3 | const bl :List(Bool) = [true, false, true, true]; 4 | -------------------------------------------------------------------------------- /test/schema/const-listData.capnp: -------------------------------------------------------------------------------- 1 | @0xaa0a111bdb1eadf2; 2 | 3 | const dl :List(Data) = [0x"11 22", 0x"ab f1"]; 4 | -------------------------------------------------------------------------------- /test/schema/const-listFloat32.capnp: -------------------------------------------------------------------------------- 1 | @0xd44182ff6e81dfa9; 2 | 3 | const fl :List(Float32) = [-19384.3768631, 1838223.23328742]; 4 | -------------------------------------------------------------------------------- /test/schema/const-listFloat64.capnp: -------------------------------------------------------------------------------- 1 | @0xecefa358801dd18e; 2 | 3 | const fl :List(Float64) = [171391839139131.1393737, -198371.3276272764267]; 4 | -------------------------------------------------------------------------------- /test/schema/const-listInt16.capnp: -------------------------------------------------------------------------------- 1 | @0x8b4e0141fc8ec85c; 2 | 3 | const il :List(Int16) = [-29124, 12111, 148, -1]; 4 | -------------------------------------------------------------------------------- /test/schema/const-listInt32.capnp: -------------------------------------------------------------------------------- 1 | @0xf8fb7617ff07cd6d; 2 | 3 | const il :List(Int32) = [-2147483520]; 4 | -------------------------------------------------------------------------------- /test/schema/const-listInt64.capnp: -------------------------------------------------------------------------------- 1 | @0x8a883d02ebcfd051; 2 | 3 | const il :List(Int64) = [-9223372036854757000]; 4 | -------------------------------------------------------------------------------- /test/schema/const-listInt8.capnp: -------------------------------------------------------------------------------- 1 | @0xc8d0e40b936e4a96; 2 | 3 | const il :List(Int8) = [-124, 111, 8, 9]; 4 | -------------------------------------------------------------------------------- /test/schema/const-listText.capnp: -------------------------------------------------------------------------------- 1 | @0xbf83ef20c9646651; 2 | 3 | const tl :List(Text) = ["a string", "another string"]; 4 | -------------------------------------------------------------------------------- /test/schema/const-listUint16.capnp: -------------------------------------------------------------------------------- 1 | @0xff0fa2f5dc1c1ee9; 2 | 3 | const ul :List(UInt16) = [58124, 24132]; 4 | -------------------------------------------------------------------------------- /test/schema/const-listUint32.capnp: -------------------------------------------------------------------------------- 1 | @0xd5e03fed06ed6376; 2 | 3 | const ul :List(UInt32) = [4247488839]; 4 | -------------------------------------------------------------------------------- /test/schema/const-listUint64.capnp: -------------------------------------------------------------------------------- 1 | @0xf95521c4822f9dd2; 2 | 3 | const ul :List(UInt64) = [1838372520339857000]; 4 | -------------------------------------------------------------------------------- /test/schema/const-listUint8.capnp: -------------------------------------------------------------------------------- 1 | @0xe4090931bba4865f; 2 | 3 | const ul :List(UInt8) = [108, 211]; 4 | -------------------------------------------------------------------------------- /test/schema/const-listVoid.capnp: -------------------------------------------------------------------------------- 1 | @0x8bb13f8b27dc9051; 2 | 3 | const vl :List(Void) = [void, void, void]; 4 | -------------------------------------------------------------------------------- /test/schema/const-struct.capnp: -------------------------------------------------------------------------------- 1 | @0x8ec08b30a4934f62; 2 | 3 | struct Trivial {} 4 | 5 | const t :Trivial = (); 6 | -------------------------------------------------------------------------------- /test/schema/const-text.capnp: -------------------------------------------------------------------------------- 1 | @0x91dd71aa345edcb7; 2 | 3 | const text :Text = "some inoffensive text"; 4 | -------------------------------------------------------------------------------- /test/schema/const-uint16.capnp: -------------------------------------------------------------------------------- 1 | @0xdf91d2da6d3e52da; 2 | 3 | const u16 :UInt16 = 64128; 4 | -------------------------------------------------------------------------------- /test/schema/const-uint32.capnp: -------------------------------------------------------------------------------- 1 | @0xb44cddbd7bf4984d; 2 | 3 | const u32 : UInt32 = 4294963559; 4 | -------------------------------------------------------------------------------- /test/schema/const-uint64.capnp: -------------------------------------------------------------------------------- 1 | @0xe3fd7ed1a29806f6; 2 | 3 | const u64 :UInt64 = 18446744073705611000; 4 | -------------------------------------------------------------------------------- /test/schema/const-uint8.capnp: -------------------------------------------------------------------------------- 1 | @0xee4585fb699b1e41; 2 | 3 | const u8 :UInt8 = 253; 4 | -------------------------------------------------------------------------------- /test/schema/const-void.capnp: -------------------------------------------------------------------------------- 1 | @0xf6ecd93e3c444ba5; 2 | 3 | const v :Void = void; 4 | -------------------------------------------------------------------------------- /test/schema/defField-bool.capnp: -------------------------------------------------------------------------------- 1 | @0xeb7a7b886145a6fc; 2 | 3 | struct X { 4 | f @0 :Bool = false; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-data.capnp: -------------------------------------------------------------------------------- 1 | @0xc94e712f860f3c36; 2 | 3 | struct X { 4 | f @0 :Data = 0x"1b 3a"; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-enum.capnp: -------------------------------------------------------------------------------- 1 | @0x86fb9c59e378bdb1; 2 | 3 | enum Trivial { 4 | e @0; 5 | } 6 | 7 | struct X { 8 | f @0 :Trivial = e; 9 | } 10 | -------------------------------------------------------------------------------- /test/schema/defField-float32.capnp: -------------------------------------------------------------------------------- 1 | @0xe6ca4741aaff477c; 2 | 3 | struct X { 4 | f @0 :Float32 = 0.12844; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-float64.capnp: -------------------------------------------------------------------------------- 1 | @0xfd6a4b1b5eb70329; 2 | 3 | struct X { 4 | f @0 :Float64 = 12444.1855323; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-genericStructBoolList.capnp: -------------------------------------------------------------------------------- 1 | @0xd5d8916588bdde36; 2 | 3 | struct Trivial(T) {} 4 | 5 | struct X { 6 | f @0 :Trivial(List(Bool)) = (); 7 | } 8 | -------------------------------------------------------------------------------- /test/schema/defField-genericStructInt16List.capnp: -------------------------------------------------------------------------------- 1 | @0x8238d7a285f62fe6; 2 | 3 | struct Trivial(T) {} 4 | 5 | struct X { 6 | f @0 :Trivial(List(Int16)) = (); 7 | } 8 | -------------------------------------------------------------------------------- /test/schema/defField-genericStructStruct.capnp: -------------------------------------------------------------------------------- 1 | @0x82f1e98dc27909c4; 2 | 3 | struct X {} 4 | struct Trivial(T) {} 5 | 6 | struct Y { 7 | f @0 :Trivial(X) = (); 8 | } 9 | -------------------------------------------------------------------------------- /test/schema/defField-genericStructText.capnp: -------------------------------------------------------------------------------- 1 | @0xde77e41a6280d69b; 2 | 3 | struct Trivial(T) {} 4 | 5 | struct X { 6 | f @0 :Trivial(Text) = (); 7 | } 8 | -------------------------------------------------------------------------------- /test/schema/defField-int16.capnp: -------------------------------------------------------------------------------- 1 | @0xc5d78592a2e45ba2; 2 | 3 | struct X { 4 | f @0 :Int16 = -28833; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-int32.capnp: -------------------------------------------------------------------------------- 1 | @0xab1b2fd5886f4001; 2 | 3 | struct X { 4 | f @0 :Int32 = 927348; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-int64.capnp: -------------------------------------------------------------------------------- 1 | @0x96fb3acfb193a51e; 2 | 3 | struct X { 4 | f @0 :Int64 = 476293292; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-int8.capnp: -------------------------------------------------------------------------------- 1 | @0xbc00fa0c15e3ee4c; 2 | 3 | struct X { 4 | f @0 :Int8 = -45; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-listBool.capnp: -------------------------------------------------------------------------------- 1 | @0xcdcecfc610757335; 2 | 3 | struct X { 4 | f @0 :List(Bool) = [true, false]; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-listData.capnp: -------------------------------------------------------------------------------- 1 | @0xba225c84813d8322; 2 | 3 | struct X { 4 | f @0 :List(Data) = [0x"99 ba"]; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-listFloat32.capnp: -------------------------------------------------------------------------------- 1 | @0xf4bc188859ae9607; 2 | 3 | struct X { 4 | f @0 :List(Float32) = [-17631.33, 199.03]; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-listFloat64.capnp: -------------------------------------------------------------------------------- 1 | @0xf2c23659fc75f678; 2 | 3 | struct X { 4 | f @0 :List(Float64) = [-99327.2344]; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-listInt16.capnp: -------------------------------------------------------------------------------- 1 | @0x93b7261ab2b24388; 2 | 3 | struct X { 4 | f @0 :List(Int16) = [-12874, 9156]; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-listInt32.capnp: -------------------------------------------------------------------------------- 1 | @0xc6782f8751cca73f; 2 | 3 | struct X { 4 | f @0 :List(Int32) = [-9912, 11195]; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-listInt64.capnp: -------------------------------------------------------------------------------- 1 | @0xf74013e71c90f8a1; 2 | 3 | struct X { 4 | f @0 :List(Int64) = [1876434342223]; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-listInt8.capnp: -------------------------------------------------------------------------------- 1 | @0x8a7f32223263c72b; 2 | 3 | struct X { 4 | f @0 :List(Int8) = [-65, 12]; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-listText.capnp: -------------------------------------------------------------------------------- 1 | @0x88b5da7195ec61df; 2 | 3 | struct X { 4 | f @0 :List(Text) = ["yet another string"]; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-listUint16.capnp: -------------------------------------------------------------------------------- 1 | @0xc718e20bc4a517fe; 2 | 3 | struct X { 4 | f @0 :List(UInt16) = [55133, 339]; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-listUint32.capnp: -------------------------------------------------------------------------------- 1 | @0xb3f61a3e646314ae; 2 | 3 | struct X { 4 | f @0 :List(UInt32) = [99999, 123]; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-listUint64.capnp: -------------------------------------------------------------------------------- 1 | @0xc688970246bbfcc2; 2 | 3 | struct X { 4 | f @0 :List(UInt64) = [6112644]; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-listUint8.capnp: -------------------------------------------------------------------------------- 1 | @0xa52973c956c1e3ad; 2 | 3 | struct X { 4 | f @0 :List(UInt8) = [21]; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-listVoid.capnp: -------------------------------------------------------------------------------- 1 | @0xeef4aecb33383bc1; 2 | 3 | struct X { 4 | f @0 :List(Void) = [void, void, void, void]; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-struct.capnp: -------------------------------------------------------------------------------- 1 | @0x9b432b0a49ec0e1c; 2 | 3 | struct Trivial {} 4 | 5 | struct X { 6 | f @0 :Trivial = (); 7 | } 8 | -------------------------------------------------------------------------------- /test/schema/defField-text.capnp: -------------------------------------------------------------------------------- 1 | @0xc0915a54c72eb7da; 2 | 3 | struct X { 4 | f @0 :Text = "some text"; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-uint16.capnp: -------------------------------------------------------------------------------- 1 | @0xa3c29e36147eec1c; 2 | 3 | struct X { 4 | f @0 :UInt16 = 144; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-uint32.capnp: -------------------------------------------------------------------------------- 1 | @0xb03de9ad62d66f21; 2 | 3 | struct X { 4 | f @0 :UInt32 = 834843; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-uint64.capnp: -------------------------------------------------------------------------------- 1 | @0xfec45c9e79610f6b; 2 | 3 | struct X { 4 | f @0 :UInt64 = 6218333; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-uint8.capnp: -------------------------------------------------------------------------------- 1 | @0xb198bcccd3a3d30a; 2 | 3 | struct X { 4 | f @0 :UInt8 = 96; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/defField-void.capnp: -------------------------------------------------------------------------------- 1 | @0xd46a6fed2f8fb6ea; 2 | 3 | struct X { 4 | f @0 :Void = void; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-bool.capnp: -------------------------------------------------------------------------------- 1 | @0xeb7a7b886145a6fc; 2 | 3 | struct X { 4 | f @0 :Bool; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-data.capnp: -------------------------------------------------------------------------------- 1 | @0xc94e712f860f3c36; 2 | 3 | struct X { 4 | f @0 :Data; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-enum.capnp: -------------------------------------------------------------------------------- 1 | @0x86fb9c59e378bdb1; 2 | 3 | enum Trivial { 4 | e @0; 5 | } 6 | 7 | struct X { 8 | f @0 :Trivial; 9 | } 10 | -------------------------------------------------------------------------------- /test/schema/field-float32.capnp: -------------------------------------------------------------------------------- 1 | @0xe6ca4741aaff477c; 2 | 3 | struct X { 4 | f @0 :Float32; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-float64.capnp: -------------------------------------------------------------------------------- 1 | @0xfd6a4b1b5eb70329; 2 | 3 | struct X { 4 | f @0 :Float64; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-genericStructBoolList.capnp: -------------------------------------------------------------------------------- 1 | @0xd5d8916588bdde36; 2 | 3 | struct Trivial(T) {} 4 | 5 | struct X { 6 | f @0 :Trivial(List(Bool)); 7 | } 8 | -------------------------------------------------------------------------------- /test/schema/field-genericStructInt16List.capnp: -------------------------------------------------------------------------------- 1 | @0x8238d7a285f62fe6; 2 | 3 | struct Trivial(T) {} 4 | 5 | struct X { 6 | f @0 :Trivial(List(Int16)); 7 | } 8 | -------------------------------------------------------------------------------- /test/schema/field-genericStructStruct.capnp: -------------------------------------------------------------------------------- 1 | @0x82f1e98dc27909c4; 2 | 3 | struct X {} 4 | struct Trivial(T) {} 5 | 6 | struct Y { 7 | f @0 :Trivial(X); 8 | } 9 | -------------------------------------------------------------------------------- /test/schema/field-genericStructText.capnp: -------------------------------------------------------------------------------- 1 | @0xde77e41a6280d69b; 2 | 3 | struct Trivial(T) {} 4 | 5 | struct X { 6 | f @0 :Trivial(Text); 7 | } 8 | -------------------------------------------------------------------------------- /test/schema/field-int16.capnp: -------------------------------------------------------------------------------- 1 | @0xc5d78592a2e45ba2; 2 | 3 | struct X { 4 | f @0 :Int16; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-int32.capnp: -------------------------------------------------------------------------------- 1 | @0xab1b2fd5886f4001; 2 | 3 | struct X { 4 | f @0 :Int32; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-int64.capnp: -------------------------------------------------------------------------------- 1 | @0x96fb3acfb193a51e; 2 | 3 | struct X { 4 | f @0 :Int64; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-int8.capnp: -------------------------------------------------------------------------------- 1 | @0xbc00fa0c15e3ee4c; 2 | 3 | struct X { 4 | f @0 :Int8; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-listBool.capnp: -------------------------------------------------------------------------------- 1 | @0xcdcecfc610757335; 2 | 3 | struct X { 4 | f @0 :List(Bool); 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-listData.capnp: -------------------------------------------------------------------------------- 1 | @0xba225c84813d8322; 2 | 3 | struct X { 4 | f @0 :List(Data); 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-listFloat32.capnp: -------------------------------------------------------------------------------- 1 | @0xf4bc188859ae9607; 2 | 3 | struct X { 4 | f @0 :List(Float32); 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-listFloat64.capnp: -------------------------------------------------------------------------------- 1 | @0xf2c23659fc75f678; 2 | 3 | struct X { 4 | f @0 :List(Float64); 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-listInt16.capnp: -------------------------------------------------------------------------------- 1 | @0x93b7261ab2b24388; 2 | 3 | struct X { 4 | f @0 :List(Int16); 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-listInt32.capnp: -------------------------------------------------------------------------------- 1 | @0xc6782f8751cca73f; 2 | 3 | struct X { 4 | f @0 :List(Int32); 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-listInt64.capnp: -------------------------------------------------------------------------------- 1 | @0xf74013e71c90f8a1; 2 | 3 | struct X { 4 | f @0 :List(Int64); 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-listInt8.capnp: -------------------------------------------------------------------------------- 1 | @0x8a7f32223263c72b; 2 | 3 | struct X { 4 | f @0 :List(Int8); 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-listText.capnp: -------------------------------------------------------------------------------- 1 | @0x88b5da7195ec61df; 2 | 3 | struct X { 4 | f @0 :List(Text); 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-listUint16.capnp: -------------------------------------------------------------------------------- 1 | @0xc718e20bc4a517fe; 2 | 3 | struct X { 4 | f @0 :List(UInt16); 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-listUint32.capnp: -------------------------------------------------------------------------------- 1 | @0xb3f61a3e646314ae; 2 | 3 | struct X { 4 | f @0 :List(UInt32); 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-listUint64.capnp: -------------------------------------------------------------------------------- 1 | @0xc688970246bbfcc2; 2 | 3 | struct X { 4 | f @0 :List(UInt64); 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-listUint8.capnp: -------------------------------------------------------------------------------- 1 | @0xa52973c956c1e3ad; 2 | 3 | struct X { 4 | f @0 :List(UInt8); 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-listVoid.capnp: -------------------------------------------------------------------------------- 1 | @0xeef4aecb33383bc1; 2 | 3 | struct X { 4 | f @0 :List(Void); 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-struct.capnp: -------------------------------------------------------------------------------- 1 | @0x9b432b0a49ec0e1c; 2 | 3 | struct Trivial {} 4 | 5 | struct X { 6 | f @0 :Trivial; 7 | } 8 | -------------------------------------------------------------------------------- /test/schema/field-text.capnp: -------------------------------------------------------------------------------- 1 | @0xc0915a54c72eb7da; 2 | 3 | struct X { 4 | f @0 :Text; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-uint16.capnp: -------------------------------------------------------------------------------- 1 | @0xa3c29e36147eec1c; 2 | 3 | struct X { 4 | f @0 :UInt16; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-uint32.capnp: -------------------------------------------------------------------------------- 1 | @0xb03de9ad62d66f21; 2 | 3 | struct X { 4 | f @0 :UInt32; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-uint64.capnp: -------------------------------------------------------------------------------- 1 | @0xfec45c9e79610f6b; 2 | 3 | struct X { 4 | f @0 :UInt64; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-uint8.capnp: -------------------------------------------------------------------------------- 1 | @0xb198bcccd3a3d30a; 2 | 3 | struct X { 4 | f @0 :UInt8; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/field-void.capnp: -------------------------------------------------------------------------------- 1 | @0xd46a6fed2f8fb6ea; 2 | 3 | struct X { 4 | f @0 :Void; 5 | } 6 | -------------------------------------------------------------------------------- /test/schema/union1.capnp: -------------------------------------------------------------------------------- 1 | @0xdcfe21753dad09eb; 2 | 3 | struct X { 4 | union { 5 | f @0 :Void; 6 | g @1 :Void; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/schema/union2.capnp: -------------------------------------------------------------------------------- 1 | @0x9516571b52482ad2; 2 | 3 | struct X { 4 | a :union { 5 | b @0 :Void; 6 | c @1 :Void; 7 | } 8 | } 9 | --------------------------------------------------------------------------------