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: add module support #301

Closed
wants to merge 13 commits into from
77 changes: 64 additions & 13 deletions lib/webidl2.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const tokenRe = {
"float": /-?(?=[0-9]*\.|[0-9]+[eE])(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/y,
"integer": /-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/y,
"identifier": /[_-]?[A-Za-z][0-9A-Z_a-z-]*/y,
"scopedidentifier": /\.[A-Za-z][0-9A-Z_a-z-]*/y,
"string": /"[^"]*"/y,
"whitespace": /[\t\n\r ]+/y,
"comment": /((\/(\/.*|\*([^*]|\*[^/])*\*\/)[\t\n\r ]*)+)/y,
Expand Down Expand Up @@ -61,6 +62,7 @@ const nonRegexTerminals = [
"legacyiterable",
"long",
"mixin",
"module",
"null",
"octet",
"optional",
Expand Down Expand Up @@ -119,22 +121,35 @@ function tokenise(str) {
}
if (result === -1) {
result = attemptTokenMatch("identifier");
const token = tokens[tokens.length - 1];
if (result !== -1 && nonRegexTerminals.includes(token.value)) {
token.type = token.value;
if (result !== -1) {
const token = tokens[tokens.length - 1];
if (nonRegexTerminals.includes(token.value)) {
token.type = token.value;
} else {
lastCharIndex = result;
const scopedResult = attemptTokenMatch("scopedidentifier");
if (scopedResult !== -1) {
const scoped = tokens.pop();
token.type = scoped.type;
token.value += scoped.value;
result = scopedResult;
}
}
}
}
} else if (nextChar === '"') {
result = attemptTokenMatch("string");
}

for (const punctuation of punctuations) {
if (str.startsWith(punctuation, lastCharIndex)) {
tokens.push({ type: punctuation, value: punctuation, trivia, line, index });
trivia = "";
lastCharIndex += punctuation.length;
result = lastCharIndex;
break;
if (result === -1) {
for (const punctuation of punctuations) {
if (str.startsWith(punctuation, lastCharIndex)) {
tokens.push({ type: punctuation, value: punctuation, trivia, line, index });
trivia = "";
lastCharIndex += punctuation.length;
result = lastCharIndex;
break;
}
}
}

Expand Down Expand Up @@ -195,6 +210,7 @@ function parseByTokens(source) {
const FLOAT = "float";
const INT = "integer";
const ID = "identifier";
const SCOPED = "scopedidentifier";
const STR = "string";

function error(str) {
Expand Down Expand Up @@ -476,7 +492,7 @@ function parseByTokens(source) {
function single_type(typeName) {
let ret = GenericType.parse(typeName) || primitive_type();
if (!ret) {
const base = consume(ID, ...stringTypes);
const base = consume(ID, SCOPED, ...stringTypes);
if (!base) {
return;
}
Expand Down Expand Up @@ -989,7 +1005,7 @@ function parseByTokens(source) {
if (!colon) {
return;
}
const name = consume(ID) || error("No type in inheritance");
const name = consume(ID, SCOPED) || error("No type in inheritance");
return new Inheritance({ tokens: { colon, name } });
}

Expand Down Expand Up @@ -1122,12 +1138,46 @@ function parseByTokens(source) {
}
}

class Module extends Container {
static parse({ partial } = {}) {
function module_interface() {
const partial = consume("partial");
const base = consume("interface");
if (!base) {
if (partial) {
throw new Error("Unsupported partial declaration in a module");
}
return;
}
return Interface.parse(base, { partial });
}
const tokens = { partial };
tokens.base = consume("module");
if (!tokens.base) {
return;
}
return Container.parse(new Module({ tokens }), {
type: "module",
allowedMembers: [
[module_interface],
[Attribute.parse, { noInherit: true, readonly: true }],
[Operation.parse, { regular: true }]
]
});
}

get type() {
return "module";
}
}

function partial() {
const partial = optional_consume("partial");
if (!partial) return;
return Dictionary.parse({ partial }) ||
interface_({ partial }) ||
Namespace.parse({ partial }) ||
Module.parse({ partial }) ||
error("Partial doesn't apply to anything");
}

Expand Down Expand Up @@ -1301,7 +1351,8 @@ function parseByTokens(source) {
Enum.parse() ||
Typedef.parse() ||
Includes.parse() ||
Namespace.parse();
Namespace.parse() ||
Module.parse();
}

function definitions() {
Expand Down
1 change: 1 addition & 0 deletions lib/writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ export function write(ast, { templates: ts = templates } = {}) {
interface: container,
"interface mixin": container,
namespace: container,
module: container,
operation,
attribute,
dictionary: container,
Expand Down
6 changes: 3 additions & 3 deletions test/invalid/baseline/module.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Syntax error at line 2:
module gfx {
^ Unrecognised tokens
Syntax error at line 4, since `module gfx`:
module geom {
^ Missing return type
55 changes: 54 additions & 1 deletion test/syntax/baseline/interface-inherits.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,62 @@
"termination": ""
}
},
{
"type": "interface",
"name": "Bonsai",
"escapedName": "Bonsai",
"inheritance": {
"name": "Tree.Art",
"escapedName": "Tree.Art",
"trivia": {
"colon": " ",
"name": " "
}
},
"members": [
{
"type": "attribute",
"name": "name",
"escapedName": "name",
"idlType": {
"type": "attribute-type",
"extAttrs": null,
"generic": null,
"nullable": null,
"union": false,
"idlType": "DOMString",
"baseName": "DOMString",
"escapedBaseName": "DOMString",
"prefix": null,
"postfix": null,
"separator": null,
"trivia": {
"base": " "
}
},
"extAttrs": null,
"special": null,
"readonly": null,
"trivia": {
"base": "\n ",
"name": " ",
"termination": ""
}
}
],
"extAttrs": null,
"partial": null,
"trivia": {
"base": "\n\n",
"name": " ",
"open": " ",
"close": "\n",
"termination": ""
}
},
{
"type": "eof",
"value": "",
"trivia": ""
"trivia": "\n"
}
]
Loading