Skip to content

Commit 08a42d9

Browse files
authored
refactor(lib/webidl2): modularize callback+iterable (#343)
* refactor(lib/webidl2): modularize callback+iterable * better messages
1 parent 06dd64a commit 08a42d9

15 files changed

+104
-74
lines changed

lib/productions/callback.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Base } from "./base";
2+
import { return_type, argument_list, unescape } from "./helpers";
3+
4+
export class CallbackFunction extends Base {
5+
/**
6+
* @param {import("../tokeniser.js").Tokeniser} tokeniser
7+
*/
8+
static parse(tokeniser, base) {
9+
const tokens = { base };
10+
const ret = new CallbackFunction({ source: tokeniser.source, tokens });
11+
tokens.name = tokeniser.consume("identifier") || tokeniser.error("Callback lacks a name");
12+
tokeniser.current = ret;
13+
tokens.assign = tokeniser.consume("=") || tokeniser.error("Callback lacks an assignment");
14+
ret.idlType = return_type(tokeniser) || tokeniser.error("Callback lacks a return type");
15+
tokens.open = tokeniser.consume("(") || tokeniser.error("Callback lacks parentheses for arguments");
16+
ret.arguments = argument_list(tokeniser);
17+
tokens.close = tokeniser.consume(")") || tokeniser.error("Unterminated callback");
18+
tokens.termination = tokeniser.consume(";") || tokeniser.error("Unterminated callback, expected `;`");
19+
return ret;
20+
}
21+
22+
get type() {
23+
return "callback";
24+
}
25+
get name() {
26+
return unescape(this.tokens.name.value);
27+
}
28+
}

lib/productions/iterable.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { Base } from "./base";
2+
import { type_with_extended_attributes } from "./helpers";
3+
4+
export class IterableLike extends Base {
5+
/**
6+
* @param {import("../tokeniser.js").Tokeniser} tokeniser
7+
*/
8+
static parse(tokeniser) {
9+
const start_position = tokeniser.position;
10+
const tokens = {};
11+
const ret = new IterableLike({ source: tokeniser.source, tokens });
12+
tokens.readonly = tokeniser.consume("readonly");
13+
tokens.base = tokens.readonly ?
14+
tokeniser.consume("maplike", "setlike") :
15+
tokeniser.consume("iterable", "maplike", "setlike");
16+
if (!tokens.base) {
17+
tokeniser.unconsume(start_position);
18+
return;
19+
}
20+
21+
const { type } = ret;
22+
const secondTypeRequired = type === "maplike";
23+
const secondTypeAllowed = secondTypeRequired || type === "iterable";
24+
25+
tokens.open = tokeniser.consume("<") || tokeniser.error(`Missing less-than sign \`<\` in ${type} declaration`);
26+
const first = type_with_extended_attributes(tokeniser) || tokeniser.error(`Missing a type argument in ${type} declaration`);
27+
ret.idlType = [first];
28+
if (secondTypeAllowed) {
29+
first.tokens.separator = tokeniser.consume(",");
30+
if (first.tokens.separator) {
31+
ret.idlType.push(type_with_extended_attributes(tokeniser));
32+
}
33+
else if (secondTypeRequired)
34+
tokeniser.error(`Missing second type argument in ${type} declaration`);
35+
}
36+
tokens.close = tokeniser.consume(">") || tokeniser.error(`Missing greater-than sign \`>\` in ${type} declaration`);
37+
tokens.termination = tokeniser.consume(";") || tokeniser.error(`Missing semicolon after ${type} declaration`);
38+
39+
return ret;
40+
}
41+
42+
get type() {
43+
return this.tokens.base.value;
44+
}
45+
get readonly() {
46+
return !!this.tokens.readonly;
47+
}
48+
}

lib/webidl2.js

Lines changed: 4 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use strict";
22

3-
import { unescape, argument_list, type_with_extended_attributes, return_type } from "./productions/helpers.js";
3+
import { unescape } from "./productions/helpers.js";
44
import { Tokeniser } from "./tokeniser.js";
55
import { Base } from "./productions/base.js";
66
import { Enum } from "./productions/enum.js";
@@ -11,6 +11,8 @@ import { Operation } from "./productions/operation.js";
1111
import { Constant } from "./productions/constant.js";
1212
import { Typedef } from "./productions/typedef.js";
1313
import { Field } from "./productions/field.js";
14+
import { CallbackFunction } from "./productions/callback.js";
15+
import { IterableLike } from "./productions/iterable.js";
1416

1517
/**
1618
* @param {Tokeniser} tokeniser
@@ -30,41 +32,14 @@ function parseByTokens(tokeniser, options) {
3032
return tokeniser.consume(...candidates);
3133
}
3234

33-
function unconsume(position) {
34-
return tokeniser.unconsume(position);
35-
}
36-
37-
class CallbackFunction extends Base {
38-
static parse(base) {
39-
const tokens = { base };
40-
const ret = new CallbackFunction({ source, tokens });
41-
tokens.name = consume(ID) || error("No name for callback");
42-
tokeniser.current = ret;
43-
tokens.assign = consume("=") || error("No assignment in callback");
44-
ret.idlType = return_type(tokeniser) || error("Missing return type");
45-
tokens.open = consume("(") || error("No arguments in callback");
46-
ret.arguments = argument_list(tokeniser);
47-
tokens.close = consume(")") || error("Unterminated callback");
48-
tokens.termination = consume(";") || error("Unterminated callback");
49-
return ret;
50-
}
51-
52-
get type() {
53-
return "callback";
54-
}
55-
get name() {
56-
return unescape(this.tokens.name.value);
57-
}
58-
}
59-
6035
function callback() {
6136
const callback = consume("callback");
6237
if (!callback) return;
6338
const tok = consume("interface");
6439
if (tok) {
6540
return Interface.parse(tok, { callback });
6641
}
67-
return CallbackFunction.parse(callback);
42+
return CallbackFunction.parse(tokeniser, callback);
6843
}
6944

7045
function static_member() {
@@ -85,49 +60,6 @@ function parseByTokens(tokeniser, options) {
8560
return member;
8661
}
8762

88-
class IterableLike extends Base {
89-
static parse() {
90-
const start_position = tokeniser.position;
91-
const tokens = {};
92-
const ret = new IterableLike({ source, tokens });
93-
tokens.readonly = consume("readonly");
94-
tokens.base = tokens.readonly ?
95-
consume("maplike", "setlike") :
96-
consume("iterable", "maplike", "setlike");
97-
if (!tokens.base) {
98-
unconsume(start_position);
99-
return;
100-
}
101-
102-
const { type } = ret;
103-
const secondTypeRequired = type === "maplike";
104-
const secondTypeAllowed = secondTypeRequired || type === "iterable";
105-
106-
tokens.open = consume("<") || error(`Error parsing ${type} declaration`);
107-
const first = type_with_extended_attributes(tokeniser) || error(`Error parsing ${type} declaration`);
108-
ret.idlType = [first];
109-
if (secondTypeAllowed) {
110-
first.tokens.separator = consume(",");
111-
if (first.tokens.separator) {
112-
ret.idlType.push(type_with_extended_attributes(tokeniser));
113-
}
114-
else if (secondTypeRequired)
115-
error(`Missing second type argument in ${type} declaration`);
116-
}
117-
tokens.close = consume(">") || error(`Unterminated ${type} declaration`);
118-
tokens.termination = consume(";") || error(`Missing semicolon after ${type} declaration`);
119-
120-
return ret;
121-
}
122-
123-
get type() {
124-
return this.tokens.base.value;
125-
}
126-
get readonly() {
127-
return !!this.tokens.readonly;
128-
}
129-
}
130-
13163
function inheritance() {
13264
const colon = consume(":");
13365
if (!colon) {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Syntax error at line 1, since `callback MyCallback`:
2+
callback MyCallback;
3+
^ Callback lacks an assignment
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Syntax error at line 1, since `callback YourCall`:
2+
callback YourCall = void;
3+
^ Callback lacks parentheses for arguments
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Syntax error at line 1, since `callback MyCall`:
2+
callback MyCall = ;
3+
^ Callback lacks a return type
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Syntax error at line 1, since `callback TotheFuture`:
2+
TotheFuture = void ()
3+
^ Unterminated callback, expected `;`
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
Syntax error at line 2, since `interface X`:
22
iterable<>;
3-
^ Error parsing iterable declaration
3+
^ Missing a type argument in iterable declaration
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Syntax error at line 2, since `interface X`:
2+
iterable;
3+
^ Missing less-than sign `<` in iterable declaration
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
Syntax error at line 2, since `interface SetLikeTwoTypes`:
22
setlike<long, long>;
3-
^ Unterminated setlike declaration
3+
^ Missing greater-than sign `>` in setlike declaration

0 commit comments

Comments
 (0)