Skip to content

Commit

Permalink
Check grammar is LL(1) as part of Travis builds
Browse files Browse the repository at this point in the history
  • Loading branch information
tobie committed Oct 11, 2017
1 parent e99b578 commit 04e2bdd
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -2,3 +2,4 @@
index.ids
deploy_key
index.html
/node_modules/
4 changes: 3 additions & 1 deletion .travis.yml
@@ -1,4 +1,6 @@
language: generic
language: node_js
node_js:
- "node"

script:
- bash ./deploy.sh
Expand Down
50 changes: 50 additions & 0 deletions check-grammar.js
@@ -0,0 +1,50 @@
"use strict";
const Grammar = require("syntax-cli").Grammar;
const LLParsingTable = require("syntax-cli").LLParsingTable;
const jsdom = require("jsdom");
const fs = require("fs");

function getRulesFromDOM(window) {
let rules = window.document.querySelectorAll("pre.grammar[id]");
return [].map.call(rules, pre => pre.textContent);
}

function processRules(rules) {
const REGEXP = /(\s*:\n\s*)|\b(integer|float|identifier|string|whitespace|comment|other)\b|(\s*\n\s*)|(ε)/g;
return rules.map(rule => {
return rule.trim().replace(REGEXP, m => {
if (/^(integer|float|identifier|string|whitespace|comment|other)$/.test(m)) {
return m.toUpperCase();
}
if (/:\n/.test(m)) { return "\n : "; }
if (/\n/.test(m)) { return "\n | "; }
if (/ε/.test(m)) { return "/* epsilon */"; }
}) + "\n ;";
});
}

function toBNF(rules) {
return "\n%%\n\n" + processRules(rules).join("\n");
}

let path = process.argv[2];
let html = fs.readFileSync(path, "utf8");
let dom = new jsdom.JSDOM(html);
let rules = getRulesFromDOM(dom.window);
let bnf = toBNF(rules);
let data = Grammar.dataFromString(bnf, "bnf");
let grammar = Grammar.fromData(data, { mode: "LL1" });
let table = new LLParsingTable({ grammar: grammar });
let conflicts = table.getConflicts();
if (table.hasConflicts()) {
console.log("The WebIDL grammar is NOT LL(1) due to the following conflicts:");
Object.keys(conflicts).forEach((nt, i) => {
let conflict = conflicts[nt];
let str = Object.keys(conflict).map(k => ` * ${k} (${ conflict[k] })`).join("\n");
console.log(` ${i+1}. ${ nt }:\n${ str }`);
});
process.exit(1);
} else {
console.log("The WebIDL grammar is LL(1).");
process.exit(0);
}
1 change: 1 addition & 0 deletions deploy.sh
Expand Up @@ -6,6 +6,7 @@ TARGET_BRANCH="gh-pages"

function doCompile {
curl https://api.csswg.org/bikeshed/ -F file=@index.bs > out/index.html
node ./check-grammar.js ./out/index.html
}

# Pull requests and commits to other branches shouldn't try to deploy, just build to verify
Expand Down
8 changes: 8 additions & 0 deletions package.json
@@ -0,0 +1,8 @@
{
"private": true,
"description": "Checks that the WebIDL grammar is LL(1)",
"devDependencies": {
"jsdom": "^11.3.0",
"syntax-cli": "0.0.97"
}
}

0 comments on commit 04e2bdd

Please sign in to comment.