Skip to content

Commit

Permalink
Merge pull request AssemblyScript#12 from nearprotocol/json
Browse files Browse the repository at this point in the history
Generate bindings using JSON encoder/decoder
  • Loading branch information
vgrichina committed Jan 11, 2019
2 parents b065403 + d83e96b commit ea8c884
Show file tree
Hide file tree
Showing 7 changed files with 7,669 additions and 6,455 deletions.
2 changes: 1 addition & 1 deletion dist/assemblyscript.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/assemblyscript.js.map

Large diffs are not rendered by default.

101 changes: 70 additions & 31 deletions src/definitions.ts
Expand Up @@ -132,7 +132,6 @@ export class NEARBindingsBuilder extends ExportsWalker {
private typeMapping: { [key: string]: string } = {
"i32": "Integer",
"String": "String",
"Uint8Array": "Uint8Array",
"bool": "Boolean"
};

Expand Down Expand Up @@ -169,9 +168,10 @@ export class NEARBindingsBuilder extends ExportsWalker {
return { simpleName: paramName, type: signature.parameterTypes[i] };
}) : [];
fields.forEach(field => this.generateDecodeFunction(field.type));
this.sb.push(`export class __near_ArgsParser_${element.simpleName} extends ThrowingBSONHandler {
this.sb.push(`export class __near_ArgsParser_${element.simpleName} extends ThrowingJSONHandler {
buffer: Uint8Array;
decoder: BSONDecoder<__near_ArgsParser_${element.simpleName}>;
decoder: JSONDecoder<__near_ArgsParser_${element.simpleName}>;
handledRoot: boolean = false;
`);
if (signature.parameterNames) {
fields.forEach((field) => {
Expand All @@ -189,12 +189,12 @@ export class NEARBindingsBuilder extends ExportsWalker {
let returnType = signature.returnType;
this.generateEncodeFunction(returnType);
this.sb.push(`export function near_func_${element.simpleName}(): void {
let bson = new Uint8Array(input_read_len());
input_read_into(bson.buffer.data);
let json = new Uint8Array(input_read_len());
input_read_into(json.buffer.data);
let handler = new __near_ArgsParser_${element.simpleName}();
handler.buffer = bson;
handler.decoder = new BSONDecoder<__near_ArgsParser_${element.simpleName}>(handler);
handler.decoder.deserialize(bson);`);
handler.buffer = json;
handler.decoder = new JSONDecoder<__near_ArgsParser_${element.simpleName}>(handler);
handler.decoder.deserialize(json);`);
if (returnType.toString() != "void") {
this.sb.push(`let result = ${element.simpleName}(`);
} else {
Expand All @@ -206,9 +206,12 @@ export class NEARBindingsBuilder extends ExportsWalker {
this.sb.push(");");
if (returnType.toString() != "void") {
this.sb.push(`
let encoder = new BSONEncoder();`);
let encoder = new JSONEncoder();
encoder.pushObject(null);
`);
this.generateFieldEncoder(returnType, '"result"', "result");
this.sb.push(`
encoder.popObject();
return_value(near.bufferWithSize(encoder.serialize()).buffer.data);
`);
}
Expand Down Expand Up @@ -243,15 +246,23 @@ export class NEARBindingsBuilder extends ExportsWalker {
super.setNull(name);
}`);

let nonBasicFields = fields.filter(field => !(field.type.toString() in this.typeMapping));
this.sb.push(`
pushObject(name: string): bool {`);
this.generatePushHandler(valuePrefix, fields);
this.sb.push(`if (!this.handledRoot) {
assert(name == null);
this.handledRoot = true;
return true;
} else {
assert(name != null);
}`);
this.generatePushHandler(valuePrefix, nonBasicFields.filter(field => !this.isArrayType(field.type)));
this.sb.push(`
return super.pushObject(name);
}`);
this.sb.push(`
pushArray(name: string): bool {`);
this.generatePushHandler(valuePrefix, fields);
this.generatePushHandler(valuePrefix, nonBasicFields.filter(field => this.isArrayType(field.type)));
this.sb.push(`
return super.pushArray(name);
}`);
Expand All @@ -261,7 +272,7 @@ export class NEARBindingsBuilder extends ExportsWalker {
fields.forEach((field) => {
if (!(field.type.toString() in this.typeMapping)) {
this.sb.push(`if (name == "${field.simpleName}") {
${valuePrefix}${field.simpleName} = __near_decode_${this.encodeType(field.type)}(this.buffer, this.decoder.readIndex);
${valuePrefix}${field.simpleName} = __near_decode_${this.encodeType(field.type)}(this.buffer, this.decoder.state);
return false;
}`);
}
Expand All @@ -272,18 +283,28 @@ export class NEARBindingsBuilder extends ExportsWalker {
let setterType = this.typeMapping[fieldType.toString()];
if (setterType) {
this.sb.push(`set${setterType}(name: string, value: ${fieldType}): void {
${valuePrefix}[i32(parseInt(name))] = value;
${valuePrefix}.push(value);
}
setNull(name: string): void {
${valuePrefix}[i32(parseInt(name))] = <${fieldType}>null;
${valuePrefix}.push(<${fieldType}>null);
}
pushArray(name: string): bool {
assert(name == null && !this.handledRoot);
this.handledRoot = true;
return true;
}`);
} else {
this.sb.push(`pushObject(name: string): bool {
${valuePrefix}[i32(parseInt(name))] = __near_decode_${this.encodeType(fieldType)}(this.buffer, this.decoder.readIndex);
${valuePrefix}.push(__near_decode_${this.encodeType(fieldType)}(this.buffer, this.decoder.state));
return false;
}
pushArray(name: string): bool {
${valuePrefix}[i32(parseInt(name))] = __near_decode_${this.encodeType(fieldType)}(this.buffer, this.decoder.readIndex);
assert(name == null);
if (!this.handledRoot) {
this.handledRoot = true;
return true;
}
${valuePrefix}.push(__near_decode_${this.encodeType(fieldType)}(this.buffer, this.decoder.state));
return false;
}`);
}
Expand All @@ -300,15 +321,15 @@ export class NEARBindingsBuilder extends ExportsWalker {
}
this.generatedEncodeFunctions.add(typeName);

if (type.classReference.prototype.simpleName == "Array" && type.classReference.typeArguments) {
if (this.isArrayType(type)) {
// Array
this.generateEncodeFunction(type.classReference.typeArguments[0]);
this.generateEncodeFunction(type.classReference.typeArguments![0]);

this.sb.push(`export function __near_encode_${typeName}(
value: ${type.toString()},
encoder: BSONEncoder): void {`);
encoder: JSONEncoder): void {`);
this.sb.push(`for (let i = 0; i < value.length; i++) {`);
this.generateFieldEncoder(type.classReference.typeArguments[0], "near.str(i)", "value[i]");
this.generateFieldEncoder(type.classReference.typeArguments![0], "null", "value[i]");
this.sb.push("}");

} else {
Expand All @@ -319,7 +340,7 @@ export class NEARBindingsBuilder extends ExportsWalker {

this.sb.push(`export function __near_encode_${typeName}(
value: ${type.toString()},
encoder: BSONEncoder): void {`);
encoder: JSONEncoder): void {`);
this.getFields(type.classReference).forEach((field) => {
let fieldType = field.type;
let fieldName = field.simpleName;
Expand All @@ -333,11 +354,12 @@ export class NEARBindingsBuilder extends ExportsWalker {

private generateHandler(type: Type) {
let typeName = this.encodeType(type);
this.sb.push(`export class __near_BSONHandler_${typeName} extends ThrowingBSONHandler {
this.sb.push(`export class __near_JSONHandler_${typeName} extends ThrowingJSONHandler {
buffer: Uint8Array;
decoder: BSONDecoder<__near_BSONHandler_${typeName}>;
decoder: JSONDecoder<__near_JSONHandler_${typeName}>;
handledRoot: boolean = false;
value: ${type} = new ${type}();`);
if (type.classReference!.simpleName.startsWith("Array")) {
if (this.isArrayType(type)) {
this.generateArrayHandlerMethods("this.value", type.classReference!.typeArguments![0]);
} else {
this.generateHandlerMethods("this.value.", this.getFields(type.classReference!));
Expand All @@ -357,9 +379,9 @@ export class NEARBindingsBuilder extends ExportsWalker {
this.generatedDecodeFunctions.add(typeName);

this.generateHandler(type);
if (type.classReference.prototype.simpleName == "Array" && type.classReference.typeArguments) {
if (this.isArrayType(type)) {
// Array
this.generateDecodeFunction(type.classReference.typeArguments[0]);
this.generateDecodeFunction(type.classReference.typeArguments![0]);
} else {
// Object
this.getFields(type.classReference).forEach(field => {
Expand All @@ -368,11 +390,11 @@ export class NEARBindingsBuilder extends ExportsWalker {
}

this.sb.push(`export function __near_decode_${typeName}(
buffer: Uint8Array, offset: i32): ${type} {
let handler = new __near_BSONHandler_${typeName}();
buffer: Uint8Array, state: DecoderState): ${type} {
let handler = new __near_JSONHandler_${typeName}();
handler.buffer = buffer;
handler.decoder = new BSONDecoder<__near_BSONHandler_${typeName}>(handler);
handler.decoder.deserialize(buffer, offset);
handler.decoder = new JSONDecoder<__near_JSONHandler_${typeName}>(handler);
handler.decoder.deserialize(buffer, state);
return handler.value;
}\n`);
}
Expand All @@ -381,7 +403,7 @@ export class NEARBindingsBuilder extends ExportsWalker {
let setterType = this.typeMapping[fieldType.toString()];
if (!setterType) {
// Object / array
let pushType = fieldType.classReference!.prototype.simpleName == "Array" ? "Array" : "Object";
let pushType = this.isArrayType(fieldType) ? "Array" : "Object";
this.sb.push(`if (${sourceExpr} != null) {
encoder.push${pushType}(${fieldExpr});
__near_encode_${this.encodeType(fieldType)}(${sourceExpr}, encoder);
Expand Down Expand Up @@ -410,6 +432,10 @@ export class NEARBindingsBuilder extends ExportsWalker {
.replace(/</g, '_');
}

private isArrayType(type: Type): bool {
return !!(type.classReference && type.classReference.prototype.simpleName == "Array" && type.classReference.typeArguments);
}

private getFields(element: Class): Field[] {
if (!element.members) {
return [];
Expand All @@ -431,6 +457,19 @@ export class NEARBindingsBuilder extends ExportsWalker {
}

build(): string {
this.sb.push(`
import { near } from "./near";
import { JSONEncoder} from "./json/encoder"
import { JSONDecoder, ThrowingJSONHandler, DecoderState } from "./json/decoder"
// Runtime functions
@external("env", "return_value")
declare function return_value(value_ptr: u32): void;
@external("env", "input_read_len")
declare function input_read_len(): u32;
@external("env", "input_read_into")
declare function input_read_into(ptr: usize): void;
`);
let mainSource = this.program.sources
.filter(s => s.normalizedPath.indexOf("~lib") != 0)[0];
this.sb.push(mainSource.text);
Expand Down
16 changes: 4 additions & 12 deletions tests/near-bindgen/main.ts
@@ -1,27 +1,19 @@
import "allocator/arena";
// TODO: Why cannot import from index?
// import { BSONEncoder, BSONDecoder } from "./bson";
import { BSONEncoder } from "./bson/encoder";
import { BSONDecoder, ThrowingBSONHandler } from "./bson/decoder";
// import { JSONEncoder, JSONDecoder } from "./json";
import { JSONEncoder } from "./json/encoder";
import { JSONDecoder, DecoderState, JSONHandler, ThrowingJSONHandler } from "./json/decoder";
import { near } from "./near"

@external("env", "log")
declare function log(str: string): void;

// Runtime functions
@external("env", "return_value")
declare function return_value(value_ptr: u32): void;
@external("env", "input_read_len")
declare function input_read_len(): u32;
@external("env", "input_read_into")
declare function input_read_into(ptr: usize): void;

export class FooBar {
foo: i32 = 0;
bar: i32 = 1;
flag: bool;
baz: string = "123";
foobar: Uint8Array;
//foobar: Uint8Array;
arr: Array<Array<string>>;
}

Expand Down

0 comments on commit ea8c884

Please sign in to comment.