Skip to content

Commit 5d7a4e7

Browse files
authored
Merge pull request AssemblyScript#7 from nearprotocol/near-bindgen
Implement nested objects support
2 parents d6c9eef + 4f125e2 commit 5d7a4e7

File tree

5 files changed

+94
-59
lines changed

5 files changed

+94
-59
lines changed

dist/assemblyscript.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/assemblyscript.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/definitions.ts

Lines changed: 64 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -153,52 +153,49 @@ export class NEARBindingsBuilder extends ExportsWalker {
153153
}
154154

155155
visitFunction(element: Function): void {
156-
console.log("visitFunction: " + element.simpleName);
157-
let signature = element.signature;
156+
this.generateArgsParser(element);
157+
this.generateWrapperFunction(element);
158+
}
158159

160+
private generateArgsParser(element: Function) {
161+
let signature = element.signature;
159162
this.sb.push(`export class __near_ArgsParser_${element.simpleName} {
163+
buffer: Uint8Array;
164+
decoder: BSONDecoder<__near_ArgsParser_${element.simpleName}>;
160165
`);
161-
let fields = [];
162166
if (signature.parameterNames) {
163-
for (let i = 0; i < signature.parameterNames.length; i++) {
164-
let paramName = signature.parameterNames[i];
165-
let paramType = signature.parameterTypes[i];
166-
fields.push({
167-
simpleName: paramName,
168-
type: paramType
169-
});
170-
}
171-
}
172-
fields.forEach((field) => {
167+
let fields = signature.parameterNames.map((paramName, i) => {
168+
return { simpleName: paramName, type: signature.parameterTypes[i] };
169+
});
170+
fields.forEach((field) => {
173171
this.sb.push(`__near_param_${field.simpleName}: ${field.type};`);
174-
});
175-
this.generateBSONHandlerMethods("this.__near_param_", fields);
176-
this.sb.push(`}`); // __near_ArgsParser
172+
});
173+
this.generateBSONHandlerMethods("this.__near_param_", fields);
174+
} else {
175+
this.generateBSONHandlerMethods("this.__near_param_", []);
176+
}
177+
this.sb.push(`}`);
178+
}
177179

180+
private generateWrapperFunction(element: Function) {
181+
let signature = element.signature;
178182
let returnType = signature.returnType.toString();
179183
this.sb.push(`export function near_func_${element.simpleName}(): void {
180184
let bson = new Uint8Array(input_read_len());
181185
input_read_into(bson.buffer.data);
182186
let handler = new __near_ArgsParser_${element.simpleName}();
183-
let decoder = new BSONDecoder<__near_ArgsParser_${element.simpleName}>(handler);
184-
decoder.deserialize(bson);`);
187+
handler.buffer = bson;
188+
handler.decoder = new BSONDecoder<__near_ArgsParser_${element.simpleName}>(handler);
189+
handler.decoder.deserialize(bson);`);
185190
if (returnType != "void") {
186191
this.sb.push(`let result = ${element.simpleName}(`);
187192
} else {
188-
this.sb.push(`${element.simpleName}(`)
193+
this.sb.push(`${element.simpleName}(`);
189194
}
190195
if (signature.parameterNames) {
191-
let i = 0;
192-
for (let paramName of signature.parameterNames) {
193-
this.sb.push(`handler.__near_param_${paramName}`);
194-
if (i < signature.parameterNames.length) {
195-
this.sb.push(",")
196-
}
197-
i++;
198-
}
196+
this.sb.push(signature.parameterNames.map(paramName => `handler.__near_param_${paramName}`).join(","));
199197
}
200198
this.sb.push(");");
201-
202199
if (returnType != "void") {
203200
this.sb.push(`
204201
let encoder = new BSONEncoder();`);
@@ -207,7 +204,6 @@ export class NEARBindingsBuilder extends ExportsWalker {
207204
return_value(near.bufferWithSize(encoder.serialize()).buffer.data);
208205
`);
209206
}
210-
211207
this.sb.push(`}`);
212208
}
213209

@@ -217,7 +213,9 @@ export class NEARBindingsBuilder extends ExportsWalker {
217213
this.sb.push(`set${setterType}(name: string, value: ${fieldType}): void {`);
218214
fields.forEach((field) => {
219215
if (field.type.toString() == fieldType) {
220-
this.sb.push(`if (name == "${field.simpleName}") { ${valuePrefix}${field.simpleName} = value; return; }`);
216+
this.sb.push(`if (name == "${field.simpleName}") {
217+
${valuePrefix}${field.simpleName} = value; return;
218+
}`);
221219
}
222220
});
223221
this.sb.push("}");
@@ -230,21 +228,34 @@ export class NEARBindingsBuilder extends ExportsWalker {
230228
});
231229
this.sb.push("}\n"); // setNull
232230

233-
// TODO: Suport nested objects/arrays
234-
// TODO: This needs some way to get current index in buffer (extract parser state into separte class?),
235-
// TODO: so that we can call method to parse object recursively
236-
// TODO: popObject() should also return false to exit nested parser?
237231
this.sb.push(`
238-
pushObject(name: string): bool { return false; }
232+
pushObject(name: string): bool {`);
233+
fields.forEach((field) => {
234+
if (!(field.type.toString() in this.typeMapping)) {
235+
this.sb.push(`if (name == "${field.simpleName}") {
236+
${valuePrefix}${field.simpleName} = __near_decode_${field.type}(this.buffer, this.decoder.readIndex);
237+
return false;
238+
}`);
239+
}
240+
});
241+
// TODO: Support arrays
242+
this.sb.push(`
243+
return false;
244+
}
239245
popObject(): void {}
240246
pushArray(name: string): bool { return false; }
241247
popArray(): void {}
242248
`);
243249
}
244250

245251
visitClass(element: Class): void {
252+
this.generateEncodeFunction(element);
253+
this.generateHandler(element);
254+
this.generateDecodeFunction(element);
255+
}
256+
257+
private generateEncodeFunction(element: Class) {
246258
let className = element.simpleName;
247-
console.log("visitClass: " + className);
248259
this.sb.push(`export function __near_encode_${className}(
249260
value: ${className},
250261
encoder: BSONEncoder): void {`);
@@ -254,18 +265,27 @@ export class NEARBindingsBuilder extends ExportsWalker {
254265
let sourceExpr = `value.${fieldName}`;
255266
this.generateFieldEncoder(fieldType, fieldName, sourceExpr);
256267
});
257-
this.sb.push("}"); // __near_encode
268+
this.sb.push("}");
269+
}
258270

271+
private generateHandler(element: Class) {
272+
let className = element.simpleName;
259273
this.sb.push(`export class __near_BSONHandler_${className} {
274+
buffer: Uint8Array;
275+
decoder: BSONDecoder<__near_BSONHandler_${className}>;
260276
value: ${className} = new ${className}();`);
261277
this.generateBSONHandlerMethods("this.value.", this.getFields(element));
262-
this.sb.push("}\n"); // class __near_BSONHandler_
278+
this.sb.push("}\n");
279+
}
263280

281+
private generateDecodeFunction(element: Class) {
282+
let className = element.simpleName;
264283
this.sb.push(`export function __near_decode_${className}(
265284
buffer: Uint8Array, offset: i32): ${className} {
266285
let handler = new __near_BSONHandler_${className}();
267-
let decoder = new BSONDecoder<__near_BSONHandler_${className}>(handler);
268-
decoder.deserialize(buffer, offset);
286+
handler.buffer = buffer;
287+
handler.decoder = new BSONDecoder<__near_BSONHandler_${className}>(handler);
288+
handler.decoder.deserialize(buffer, offset);
269289
return handler.value;
270290
}\n`);
271291
}
@@ -296,17 +316,11 @@ export class NEARBindingsBuilder extends ExportsWalker {
296316
}
297317

298318
private getFields(element: Class): any[] {
299-
var members = element.members;
300-
var results = [];
301-
if (members) {
302-
for (let member of members.values()) {
303-
if (!(member instanceof Field)) {
304-
continue;
305-
}
306-
results.push(member);
307-
}
319+
if (!element.members) {
320+
return [];
308321
}
309-
return results;
322+
323+
return [...element.members.values()].filter(member => member instanceof Field);
310324
}
311325

312326
visitInterface(element: Interface): void {

tests/near-bindgen/main.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import "allocator/arena";
33
// import { BSONEncoder, BSONDecoder } from "./bson";
44
import { BSONEncoder } from "./bson/encoder";
55
import { BSONDecoder } from "./bson/decoder";
6+
import { near } from "./near"
67

78
@external("env", "log")
89
declare function log(str: string): void;
@@ -15,11 +16,6 @@ declare function input_read_len(): u32;
1516
@external("env", "input_read_into")
1617
declare function input_read_into(ptr: usize): void;
1718

18-
type Address = u64;
19-
20-
export function _init(initialOwner: Address): void {
21-
}
22-
2319
export class FooBar {
2420
foo: i32 = 0;
2521
bar: i32 = 1;
@@ -32,10 +28,20 @@ export class ContainerClass {
3228
foobar: FooBar
3329
}
3430

31+
export class AnotherContainerClass {
32+
foobar: FooBar
33+
}
34+
35+
export function doNothing(): void {
36+
37+
}
38+
3539
export function add(x: i32, y: i32): i32 {
3640
return x + y;
3741
}
3842

39-
export function getFoobar(container: ContainerClass): FooBar {
40-
return container.foobar;
43+
export function getFoobar(container: ContainerClass): AnotherContainerClass {
44+
let result = new AnotherContainerClass();
45+
result.foobar = container.foobar;
46+
return result;
4147
}

tests/near-bindgen/near.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export namespace near {
2+
export function bufferWithSizeFromPtr(ptr: usize, length: usize): Uint8Array {
3+
let withSize = new Uint8Array(length + 4);
4+
store<u32>(withSize.buffer.data, length);
5+
// TODO: Should use better copy routine or better avoid copy altogether
6+
for (let i = <usize>0; i < length; i++) {
7+
withSize[i + 4] = load<u8>(ptr + i);
8+
}
9+
return withSize;
10+
}
11+
12+
export function bufferWithSize(buf: Uint8Array): Uint8Array {
13+
return bufferWithSizeFromPtr(buf.buffer.data, buf.byteLength);
14+
}
15+
}

0 commit comments

Comments
 (0)