Skip to content

Commit f659888

Browse files
lucacasonatosaschanaz
authored andcommitted
feat: add support for parsing async iterable<T> type
1 parent e4534df commit f659888

13 files changed

+274
-10
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ attached to a field called `idlType`:
236236
Where the fields are as follows:
237237

238238
* `type`: String indicating where this type is used. Can be `null` if not applicable.
239-
* `generic`: String indicating the generic type (e.g. "Promise", "sequence").
239+
* `generic`: String indicating the generic type (e.g. "Promise", "sequence", "async iterable").
240240
* `idlType`: String indicating the type name, or array of subtypes if the type is
241241
generic or a union.
242242
* `nullable`: `true` if the type is nullable.

lib/productions/attribute.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ export class Attribute extends Base {
7575
yield* this.extAttrs.validate(defs);
7676
yield* this.idlType.validate(defs);
7777

78-
if (["sequence", "record"].includes(this.idlType.generic)) {
78+
if (
79+
["async iterable", "sequence", "record"].includes(this.idlType.generic)
80+
) {
7981
const message = `Attributes cannot accept ${this.idlType.generic} types.`;
8082
yield validationError(
8183
this.tokens.name,

lib/productions/callback.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
unescape,
66
autoParenter,
77
} from "./helpers.js";
8+
import { validationError } from "../error.js";
89

910
export class CallbackFunction extends Base {
1011
/**
@@ -44,6 +45,18 @@ export class CallbackFunction extends Base {
4445

4546
*validate(defs) {
4647
yield* this.extAttrs.validate(defs);
48+
for (const arg of this.arguments) {
49+
yield* arg.validate(defs);
50+
if (arg.idlType.generic === "async iterable") {
51+
const message = `Callback function arguments can not be ${arg.idlType.generic} types.`;
52+
yield validationError(
53+
arg.tokens.name,
54+
arg,
55+
"operation-return-invalid-type",
56+
message,
57+
);
58+
}
59+
}
4760
yield* this.idlType.validate(defs);
4861
}
4962

lib/productions/iterable.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,19 @@ export class IterableLike extends Base {
6868
}
6969
}
7070

71-
tokens.termination =
72-
tokeniser.consume(";") ||
71+
tokens.termination = tokeniser.consume(";");
72+
if (
73+
!tokens.termination &&
74+
tokens.async &&
75+
tokens.base.value === "iterable"
76+
) {
77+
// Instead of a missing semicolon, this could be an async iterable return
78+
// type for a regular operation. Let's bail out early in that case.
79+
tokeniser.unconsume(start_position);
80+
return;
81+
} else if (!tokens.termination) {
7382
tokeniser.error(`Missing semicolon after ${type} declaration`);
83+
}
7484

7585
return ret.this;
7686
}

lib/productions/type.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ import { ExtendedAttributes } from "./extended-attributes.js";
1616
* @param {string} typeName
1717
*/
1818
function generic_type(tokeniser, typeName) {
19+
const prevPosition = tokeniser.position;
1920
const base = tokeniser.consume(
21+
"async",
2022
"FrozenArray",
2123
"ObservableArray",
2224
"Promise",
@@ -29,6 +31,14 @@ function generic_type(tokeniser, typeName) {
2931
const ret = autoParenter(
3032
new Type({ source: tokeniser.source, tokens: { base } }),
3133
);
34+
if (base.value === "async") {
35+
ret.tokens.async = base;
36+
ret.tokens.base = tokeniser.consume("iterable");
37+
if (!ret.tokens.base) {
38+
tokeniser.unconsume(prevPosition); // unconsume the "async" token
39+
return;
40+
}
41+
}
3242
ret.tokens.open =
3343
tokeniser.consume("<") ||
3444
tokeniser.error(`No opening bracket after ${base.value}`);
@@ -42,6 +52,7 @@ function generic_type(tokeniser, typeName) {
4252
ret.subtype.push(subtype);
4353
break;
4454
}
55+
case "async":
4556
case "sequence":
4657
case "FrozenArray":
4758
case "ObservableArray": {
@@ -169,6 +180,8 @@ export class Type extends Base {
169180

170181
get generic() {
171182
if (this.subtype.length && this.tokens.base) {
183+
if (this.tokens.base.value === "iterable" && this.tokens.async)
184+
return "async iterable";
172185
return this.tokens.base.value;
173186
}
174187
return "";
@@ -259,6 +272,7 @@ for more information.`;
259272
const type_body = () => {
260273
if (this.union || this.generic) {
261274
return w.ts.wrap([
275+
w.token(this.tokens.async, w.ts.generic),
262276
w.token(this.tokens.base, w.ts.generic),
263277
w.token(this.tokens.open),
264278
...this.subtype.map((t) => t.write(w)),
Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
(attr-invalid-type) Validation error at line 3 in invalid-attribute.webidl, inside `interface sequenceAsAttribute -> attribute invalid`:
22
attribute sequence<short> invalid;
33
^ Attributes cannot accept sequence types.
4-
(attr-invalid-type) Validation error at line 9 in invalid-attribute.webidl, inside `interface recordAsAttribute -> attribute invalid`:
4+
(attr-invalid-type) Validation error at line 9 in invalid-attribute.webidl, inside `interface asyncIterableAsAttribute -> attribute invalid`:
5+
async iterable<short> invalid;
6+
^ Attributes cannot accept async iterable types.
7+
(attr-invalid-type) Validation error at line 15 in invalid-attribute.webidl, inside `interface recordAsAttribute -> attribute invalid`:
58
<DOMString, DOMString> invalid;
69
^ Attributes cannot accept record types.
7-
(attr-invalid-type) Validation error at line 17 in invalid-attribute.webidl, inside `interface dictionaryAsAttribute -> attribute dict`:
10+
(attr-invalid-type) Validation error at line 23 in invalid-attribute.webidl, inside `interface dictionaryAsAttribute -> attribute dict`:
811
attribute Dict dict;
912
^ Attributes cannot accept dictionary types.
10-
(attr-invalid-type) Validation error at line 18 in invalid-attribute.webidl, inside `interface dictionaryAsAttribute -> attribute dictUnion`:
13+
(attr-invalid-type) Validation error at line 24 in invalid-attribute.webidl, inside `interface dictionaryAsAttribute -> attribute dictUnion`:
1114
attribute (Dict or boolean) dictUnion
1215
^ Attributes cannot accept dictionary types.
13-
(attr-invalid-type) Validation error at line 28 in invalid-attribute.webidl, inside `interface EnforceRangeInReadonlyAttribute -> attribute readOnlyAttr1`:
16+
(attr-invalid-type) Validation error at line 34 in invalid-attribute.webidl, inside `interface EnforceRangeInReadonlyAttribute -> attribute readOnlyAttr1`:
1417
readonly attribute [EnforceRange] long readOnlyAttr1;
1518
^ Readonly attributes cannot accept [EnforceRange] extended attribute.
16-
(attr-invalid-type) Validation error at line 29 in invalid-attribute.webidl, inside `interface EnforceRangeInReadonlyAttribute -> attribute readOnlyAttr2`:
19+
(attr-invalid-type) Validation error at line 35 in invalid-attribute.webidl, inside `interface EnforceRangeInReadonlyAttribute -> attribute readOnlyAttr2`:
1720
readonly attribute [EnforceRange] GPUInt32In readOnlyAttr2;
1821
^ Readonly attributes cannot accept [EnforceRange] extended attribute.
19-
(attr-invalid-type) Validation error at line 30 in invalid-attribute.webidl, inside `interface EnforceRangeInReadonlyAttribute -> attribute readOnlyAttr2`:
22+
(attr-invalid-type) Validation error at line 36 in invalid-attribute.webidl, inside `interface EnforceRangeInReadonlyAttribute -> attribute readOnlyAttr2`:
2023
readonly attribute GPUInt32 readOnlyAttr2;
2124
^ Readonly attributes cannot accept [EnforceRange] extended attribute.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(operation-return-invalid-type) Validation error at line 1 in invalid-callback-argument.webidl, inside `callback DoSomething -> argument bool`:
2+
async iterable<DOMString> bool);
3+
^ Callback function arguments can not be async iterable types.

test/invalid/idl/invalid-attribute.webidl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ interface sequenceAsAttribute {
44
attribute (sequence<short> or boolean) invalidUnion; // TODO
55
};
66

7+
[Exposed=Window]
8+
interface asyncIterableAsAttribute {
9+
attribute async iterable<short> invalid;
10+
attribute (async iterable<short> or boolean) invalidUnion; // TODO
11+
};
12+
713
[Exposed=Window]
814
interface recordAsAttribute {
915
attribute record<DOMString, DOMString> invalid;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
callback DoSomething = Promise<DOMString> (async iterable<DOMString> bool);

0 commit comments

Comments
 (0)