Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support Set/Map for binding generator #2340

Draft
wants to merge 20 commits into
base: main
Choose a base branch
from
654 changes: 324 additions & 330 deletions src/bindings/js.ts

Large diffs are not rendered by default.

98 changes: 23 additions & 75 deletions src/bindings/tsd.ts
Original file line number Diff line number Diff line change
@@ -20,9 +20,9 @@ import {
} from "../types";

import {
CharCode,
escapeString,
indent, isIdentifier
indent,
isIdentifier
} from "../util";

import {
@@ -54,28 +54,17 @@ export class TSDBuilder extends ExportsWalker {
var type = element.type;
var tsType = this.toTypeScriptType(type, Mode.EXPORT);
indent(sb, this.indentLevel);
sb.push("/** ");
sb.push(element.internalName);
sb.push(" */\n");
sb.push(`/** ${element.internalName} */\n`);
indent(sb, this.indentLevel);
sb.push("export ");
if (this.esm) sb.push("declare ");
sb.push("const ");
sb.push(name);
sb.push(": {\n");
sb.push(`export ${ this.esm ? "declare " : ""}const ${name}: {\n`);
indent(sb, ++this.indentLevel);
sb.push("/** @type `");
sb.push(type.toString());
sb.push("` */\n");
sb.push(`/** @type \`${type}\` */\n`);
indent(sb, this.indentLevel);
sb.push("get value(): ");
sb.push(tsType);
sb.push(`get value(): ${tsType}`);
if (!element.is(CommonFlags.CONST)) {
sb.push(";\n");
indent(sb, this.indentLevel);
sb.push("set value(value: ");
sb.push(tsType);
sb.push(");\n");
sb.push(`set value(value: ${tsType});\n`);
} else {
sb.push("\n");
}
@@ -86,15 +75,9 @@ export class TSDBuilder extends ExportsWalker {
visitEnum(name: string, element: Enum): void {
var sb = this.sb;
indent(sb, this.indentLevel);
sb.push("/** ");
sb.push(element.internalName);
sb.push(" */\n");
sb.push(`/** ${element.internalName} */\n`);
indent(sb, this.indentLevel++);
sb.push("export ");
if (this.esm) sb.push("declare ");
sb.push("enum ");
sb.push(name);
sb.push(" {\n");
sb.push(`export ${ this.esm ? "declare " : ""}enum ${name} {\n`);
var members = element.members;
if (members) {
// TODO: for (let [memberName, member] of members) {
@@ -105,8 +88,7 @@ export class TSDBuilder extends ExportsWalker {
indent(sb, this.indentLevel);
sb.push("/** @type `i32` */\n");
indent(sb, this.indentLevel);
sb.push(memberName);
sb.push(",\n");
sb.push(`${memberName},\n`);
}
}
indent(sb, --this.indentLevel);
@@ -119,45 +101,30 @@ export class TSDBuilder extends ExportsWalker {
indent(sb, this.indentLevel);
sb.push("/**\n");
indent(sb, this.indentLevel);
sb.push(" * ");
sb.push(element.internalName);
sb.push("\n");
sb.push(` * ${element.internalName}\n`);
var parameterTypes = signature.parameterTypes;
var numParameters = parameterTypes.length;
for (let i = 0; i < numParameters; ++i) {
indent(sb, this.indentLevel);
sb.push(" * @param ");
sb.push(element.getParameterName(i));
sb.push(" `");
sb.push(parameterTypes[i].toString());
sb.push("`\n");
sb.push(` * @param ${element.getParameterName(i)} \`${parameterTypes[i]}\`\n`);
}
var returnType = signature.returnType;
if (returnType != Type.void) {
indent(sb, this.indentLevel);
sb.push(" * @returns `");
sb.push(returnType.toString());
sb.push("`\n");
sb.push(` * @returns \`${returnType}\`\n`);
}
indent(sb, this.indentLevel);
sb.push(" */\n");
indent(sb, this.indentLevel);
sb.push("export ");
if (this.esm) sb.push("declare ");
sb.push("function ");
sb.push(name);
sb.push("(");
sb.push(`export ${this.esm ? "declare " : ""}function ${name}(`);
var requiredParameters = signature.requiredParameters;
for (let i = 0; i < numParameters; ++i) {
if (i) sb.push(", ");
sb.push(element.getParameterName(i));
if (i >= requiredParameters) sb.push("?");
sb.push(": ");
sb.push(this.toTypeScriptType(parameterTypes[i], Mode.IMPORT));
sb.push(`: ${this.toTypeScriptType(parameterTypes[i], Mode.IMPORT)}`);
}
sb.push("): ");
sb.push(this.toTypeScriptType(returnType, Mode.EXPORT));
sb.push(";\n");
sb.push(`): ${this.toTypeScriptType(returnType, Mode.EXPORT)};\n`);
}

visitClass(name: string, element: Class): void {
@@ -205,9 +172,7 @@ export class TSDBuilder extends ExportsWalker {
if (isIdentifier(moduleName)) {
sb.push(moduleName);
} else {
sb.push("\"");
sb.push(escapeString(moduleName, CharCode.DOUBLEQUOTE));
sb.push("\"");
sb.push(`"${escapeString(moduleName)}"`);
}
sb.push(": unknown,\n");
}
@@ -246,9 +211,7 @@ export class TSDBuilder extends ExportsWalker {
clazz.extends(this.program.staticArrayPrototype)
) {
const valueType = clazz.getArrayValueType();
sb.push("Array<");
sb.push(this.toTypeScriptType(valueType, mode));
sb.push(">");
sb.push(`Array<${this.toTypeScriptType(valueType, mode)}>`);
} else if (clazz.extends(this.program.arrayBufferViewInstance.prototype)) {
const valueType = clazz.getArrayValueType();
if (valueType == Type.i8) {
@@ -325,23 +288,14 @@ export class TSDBuilder extends ExportsWalker {
makeRecordType(clazz: Class, mode: Mode): string {
var sb = new Array<string>();
var members = clazz.members;
sb.push("/** ");
sb.push(clazz.internalName);
sb.push(" */\ndeclare interface __Record");
sb.push(clazz.id.toString());
sb.push("<TOmittable> {\n");
sb.push(`/** ${clazz.internalName} */\ndeclare interface __Record${clazz.id}<TOmittable> {\n`);
if (members) {
for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) {
let memberName = _keys[i];
let member = assert(members.get(memberName));
if (member.kind != ElementKind.FIELD) continue;
let field = <Field>member;
sb.push(" /** @type `");
sb.push(field.type.toString());
sb.push("` */\n ");
sb.push(field.name);
sb.push(": ");
sb.push(this.toTypeScriptType(field.type, mode));
sb.push(` /** @type \`${field.type}\` */\n ${field.name}: ${this.toTypeScriptType(field.type, mode)}`);
if (this.fieldAcceptsUndefined(field.type)) {
sb.push(" | TOmittable");
}
@@ -361,17 +315,11 @@ export class TSDBuilder extends ExportsWalker {

makeInternrefType(clazz: Class): string {
var sb = new Array<string>();
sb.push("/** ");
sb.push(clazz.internalName);
sb.push(" */\n");
sb.push("declare class __Internref");
sb.push(clazz.id.toString());
sb.push(" extends Number {\n");
sb.push(`/** ${clazz.internalName} */\n`);
sb.push(`declare class __Internref${clazz.id} extends Number {\n`);
var base: Class | null = clazz;
do {
sb.push(" private __nominal");
sb.push(base.id.toString());
sb.push(": symbol;\n");
sb.push(` private __nominal${base.id}: symbol;\n`);
base = base.base;
} while (base);
sb.push("}\n");
4 changes: 2 additions & 2 deletions src/extra/ast.ts
Original file line number Diff line number Diff line change
@@ -684,7 +684,7 @@ export class ASTBuilder {
visitStringLiteral(str: string): void {
var sb = this.sb;
sb.push("\"");
sb.push(escapeString(str, CharCode.DOUBLEQUOTE));
sb.push(escapeString(str));
sb.push("\"");
}

@@ -1482,7 +1482,7 @@ export class ASTBuilder {
sb.push("declare ");
}
sb.push("module \"");
sb.push(escapeString(node.moduleName, CharCode.DOUBLEQUOTE));
sb.push(escapeString(node.moduleName));
sb.push("\"");
}

2 changes: 1 addition & 1 deletion src/util/text.ts
Original file line number Diff line number Diff line change
@@ -453,7 +453,7 @@ export function indent(sb: string[], level: i32): void {
}

/** Escapes a string using the specified kind of quote. */
export function escapeString(str: string, quote: CharCode): string {
export function escapeString(str: string, quote: CharCode = CharCode.DOUBLEQUOTE): string {
var sb = new Array<string>();
var off = 0;
var i = 0;
66 changes: 60 additions & 6 deletions tests/compiler/bindings/esm.debug.d.ts
Original file line number Diff line number Diff line change
@@ -94,27 +94,81 @@ export declare function staticarrayFunction(a: Array<number>, b: Array<number>):
* @returns `~lib/array/Array<i32>`
*/
export declare function arrayFunction(a: Array<number>, b: Array<number>): Array<number>;
/**
* bindings/esm/setU8Function
* @returns `~lib/set/Set<u8>`
*/
export declare function setU8Function(): __Internref8;
/**
* bindings/esm/setI32Function
* @returns `~lib/set/Set<i32>`
*/
export declare function setI32Function(): __Internref9;
/**
* bindings/esm/setF64Function
* @returns `~lib/set/Set<f64>`
*/
export declare function setF64Function(): __Internref10;
/**
* bindings/esm/mapStringU8Function
* @returns `~lib/map/Map<~lib/string/String,u8>`
*/
export declare function mapStringU8Function(): __Internref11;
/**
* bindings/esm/mapI32F64Function
* @returns `~lib/map/Map<i32,f64>`
*/
export declare function mapI32F64Function(): __Internref12;
/**
* bindings/esm/mapU16I64Function
* @returns `~lib/map/Map<u16,i64>`
*/
export declare function mapU16I64Function(): __Internref13;
/**
* bindings/esm/objectFunction
* @param a `bindings/esm/PlainObject`
* @param b `bindings/esm/PlainObject`
* @returns `bindings/esm/PlainObject`
*/
export declare function objectFunction(a: __Record8<undefined>, b: __Record8<undefined>): __Record8<never>;
export declare function objectFunction(a: __Record14<undefined>, b: __Record14<undefined>): __Record14<never>;
/**
* bindings/esm/newInternref
* @returns `bindings/esm/NonPlainObject`
*/
export declare function newInternref(): __Internref11;
export declare function newInternref(): __Internref17;
/**
* bindings/esm/internrefFunction
* @param a `bindings/esm/NonPlainObject`
* @param b `bindings/esm/NonPlainObject`
* @returns `bindings/esm/NonPlainObject`
*/
export declare function internrefFunction(a: __Internref11, b: __Internref11): __Internref11;
export declare function internrefFunction(a: __Internref17, b: __Internref17): __Internref17;
/** ~lib/set/Set<u8> */
declare class __Internref8 extends Number {
private __nominal8: symbol;
}
/** ~lib/set/Set<i32> */
declare class __Internref9 extends Number {
private __nominal9: symbol;
}
/** ~lib/set/Set<f64> */
declare class __Internref10 extends Number {
private __nominal10: symbol;
}
/** ~lib/map/Map<~lib/string/String,u8> */
declare class __Internref11 extends Number {
private __nominal11: symbol;
}
/** ~lib/map/Map<i32,f64> */
declare class __Internref12 extends Number {
private __nominal12: symbol;
}
/** ~lib/map/Map<u16,i64> */
declare class __Internref13 extends Number {
private __nominal13: symbol;
}
/** bindings/esm/PlainObject */
declare interface __Record8<TOmittable> {
declare interface __Record14<TOmittable> {
/** @type `i8` */
a: number | TOmittable;
/** @type `i16` */
@@ -149,6 +203,6 @@ declare interface __Record8<TOmittable> {
p: Array<string> | null | TOmittable;
}
/** bindings/esm/NonPlainObject */
declare class __Internref11 extends Number {
private __nominal11: symbol;
declare class __Internref17 extends Number {
private __nominal17: symbol;
}
Loading