Skip to content

Commit 9654953

Browse files
committed
Handle nested array types
1 parent 165f796 commit 9654953

File tree

4 files changed

+82
-34
lines changed

4 files changed

+82
-34
lines changed

lib/asbind-instance/bind-function.js

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@ function getFunctionFromKeyPath(baseObject, keys) {
99
// Converts web platform names for the different ArrayBufferViews
1010
// to the names that ASC understands. Currently, that only means
1111
// to cut off the `Big` in `BigInt64Array`.
12+
const stdlibTypedArrayPrefix = "~lib/typedarray/";
1213
function normalizeArrayBufferViewTypeName(typeName) {
14+
// Don’t do anything if this is not a stdlib type.
15+
if (!typeName.startsWith(stdlibTypedArrayPrefix)) {
16+
return typeName;
17+
}
18+
typeName = typeName.slice(stdlibTypedArrayPrefix.length);
1319
if (typeName.startsWith("Big")) {
1420
// Slice off `Big` as the loader doesn’t have that prefix.
1521
typeName = typeName.slice(3);
@@ -21,7 +27,7 @@ function getTypeId(asbindInstance, typeName) {
2127
if (typeName in asbindInstance.typeDescriptor.typeIds) {
2228
return asbindInstance.typeDescriptor.typeIds[typeName];
2329
}
24-
throw Error(`Unknown type ${JSON.stringifty(typeName)}`);
30+
throw Error(`Unknown type ${JSON.stringify(typeName)}`);
2531
}
2632

2733
function nop(asbindInstance, value, typeName) {
@@ -49,11 +55,13 @@ function putArrayBuffer(asbindInstance, value, typeName) {
4955
);
5056
}
5157

58+
const stdlibArray = "~lib/array/Array";
5259
function arrayInnerType(typeName) {
53-
if (!typeName.startsWith("Array<")) {
60+
if (!typeName.startsWith(stdlibArray)) {
5461
throw Error(`${JSON.stringify(typeName)} is not an array type`);
5562
}
56-
return typeName.slice("Array<".length, -1);
63+
// Cut off stdlib path + generic angle brackets.
64+
return typeName.slice(`${stdlibArray}<`.length, -1);
5765
}
5866

5967
function getArray(asbindInstance, value, typeName) {
@@ -81,24 +89,24 @@ const converters = new Map([
8189
[/^void$/, { ascToJs: nop, jsToAsc: nop }],
8290
[/^(i|u)(8|16|32)$/, { ascToJs: nop, jsToAsc: nop }],
8391
[/^f(32|64)$/, { ascToJs: nop, jsToAsc: nop }],
84-
[/^[sS]tring$/, { ascToJs: getString, jsToAsc: putString }],
92+
[/^~lib\/string\/String$/, { ascToJs: getString, jsToAsc: putString }],
8593
[
86-
/^(Ui|I)nt(8|16|32)Array$/,
94+
/^~lib\/typedarray\/(Ui|I)nt(8|16|32)Array$/,
8795
{ ascToJs: getArrayBufferView, jsToAsc: putArrayBuffer }
8896
],
8997
[
90-
/^Big(Ui|I)nt64Array$/,
98+
/^~lib\/typedarray\/Big(Ui|I)nt64Array$/,
9199
{ ascToJs: getArrayBufferView, jsToAsc: putArrayBuffer }
92100
],
93101
[
94-
/^Uint8ClampedArray$/,
102+
/^~lib\/typedarray\/Uint8ClampedArray$/,
95103
{ ascToJs: getArrayBufferView, jsToAsc: putArrayBuffer }
96104
],
97105
[
98-
/^Float(32|64)Array$/,
106+
/^~lib\/typedarray\/Float(32|64)Array$/,
99107
{ ascToJs: getArrayBufferView, jsToAsc: putArrayBuffer }
100108
],
101-
[/^Array<.+>$/, { ascToJs: getArray, jsToAsc: putArray }]
109+
[/^~lib\/array\/Array<.+>$/, { ascToJs: getArray, jsToAsc: putArray }]
102110
]);
103111

104112
const warned = new Set();

test/tests/array/asc.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,13 @@ export function swapAndPad(a: Array<f64>, b: f64[]): Array<f64> {
66
}
77

88
declare function swappedConcat(a: f64[], b: Array<f64>): f64[];
9+
10+
export function join(s: Array<Array<string>>): string {
11+
let result: string = "";
12+
for (let outer = 0; outer < s.length; outer++) {
13+
for (let inner = 0; inner < s[outer].length; inner++) {
14+
result += s[outer][inner];
15+
}
16+
}
17+
return result;
18+
}

test/tests/array/test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,16 @@ describe("as-bind", function() {
1212
[255, 10, 11, 12, 1, 2, 3, 255].join(",")
1313
);
1414
});
15+
16+
it("should handle nested array", async function() {
17+
const instance = await AsBind.instantiate(this.rawModule, {
18+
asc: {
19+
swappedConcat(a, b) {
20+
return [].concat(b, a);
21+
}
22+
}
23+
});
24+
const data = [["a", "b", "c"], ["1"], ["w", "x", "y", "z"]];
25+
assert(instance.exports.join(data) === data.map(s => s.join("")).join(""));
26+
});
1527
});

transform.js

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,7 @@ function elementHasFlag(el, flag) {
1111
}
1212

1313
function typeName(type) {
14-
let name = type.name.text ?? type.name.identifier.text;
15-
if (type.typeArguments.length > 0) {
16-
name = `${name}<${type.typeArguments.map(typeName).join(",")}>`;
17-
}
18-
return name;
14+
return type.getClass()?.internalName ?? type.toString();
1915
}
2016

2117
function containingModule(func) {
@@ -29,26 +25,34 @@ function containingModule(func) {
2925

3026
function getFunctionTypeDescriptor(func) {
3127
return {
32-
returnType: typeName(func.declaration.signature.returnType),
33-
parameters: func.declaration.signature.parameters.map(parameter =>
34-
typeName(parameter.type)
28+
returnType: typeName(func.signature.returnType),
29+
parameters: func.signature.parameterTypes.map(parameter =>
30+
typeName(parameter)
3531
)
3632
};
3733
}
3834

39-
function extractTypeMap(func) {
40-
// TODO: Generics?
41-
func = func.instances.get("");
42-
const result = {
43-
[typeName(
44-
func.declaration.signature.returnType
45-
)]: func.signature.returnType?.getClass?.()?.id
46-
};
47-
func.declaration.signature.parameters.forEach((parameter, i) => {
48-
result[typeName(parameter.type)] = func.signature.parameterTypes[
49-
i
50-
].getClass?.()?.id;
51-
});
35+
function extractTypeIds(type) {
36+
const result = {};
37+
const clazz = type.getClass?.();
38+
if (!clazz) {
39+
return result;
40+
}
41+
result[clazz.internalName] = clazz.id;
42+
if (clazz.typeArguments) {
43+
for (const subType of clazz.typeArguments) {
44+
Object.assign(result, extractTypeIds(subType));
45+
}
46+
}
47+
return result;
48+
}
49+
50+
function extractTypeIdsFromFunction(func) {
51+
const result = {};
52+
Object.assign(result, extractTypeIds(func.signature.returnType));
53+
func.signature.parameterTypes.forEach(paramType =>
54+
Object.assign(result, extractTypeIds(paramType))
55+
);
5256
return result;
5357
}
5458

@@ -78,7 +82,14 @@ class AsBindTransform extends Transform {
7882

7983
const typeIds = {};
8084
const importedFunctions = {};
81-
for (const importedFunction of flatImportedFunctions) {
85+
for (let importedFunction of flatImportedFunctions) {
86+
if (
87+
importedFunction.instances.size > 1 ||
88+
!importedFunction.instances.has("")
89+
) {
90+
throw Error(`Can’t import or export generic functions.`);
91+
}
92+
importedFunction = importedFunction.instances.get("");
8293
// To know under what module name an imported function will be expected,
8394
// we have to find the containing module of the given function, take the
8495
// internal name (which is effectively the file path without extension)
@@ -93,14 +104,21 @@ class AsBindTransform extends Transform {
93104
importedFunctions[moduleName][
94105
importedFunction.name
95106
] = getFunctionTypeDescriptor(importedFunction);
96-
Object.assign(typeIds, extractTypeMap(importedFunction));
107+
Object.assign(typeIds, extractTypeIdsFromFunction(importedFunction));
97108
}
98109
const exportedFunctions = {};
99-
for (const exportedFunction of flatExportedFunctions) {
110+
for (let exportedFunction of flatExportedFunctions) {
111+
if (
112+
exportedFunction.instances.size > 1 ||
113+
!exportedFunction.instances.has("")
114+
) {
115+
throw Error(`Can’t import or export generic functions.`);
116+
}
117+
exportedFunction = exportedFunction.instances.get("");
100118
exportedFunctions[exportedFunction.name] = getFunctionTypeDescriptor(
101119
exportedFunction
102120
);
103-
Object.assign(typeIds, extractTypeMap(exportedFunction));
121+
Object.assign(typeIds, extractTypeIdsFromFunction(exportedFunction));
104122
}
105123
this.typeData = JSON.stringify({
106124
typeIds,

0 commit comments

Comments
 (0)