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 10, 2017
1 parent e99b578 commit f6c6a2a
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
index.ids
deploy_key
index.html
/node_modules/
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
language: generic
language: node_js
node_js:
- "node"

script:
- bash ./deploy.sh
Expand Down
48 changes: 48 additions & 0 deletions check-grammar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const Grammar = require("syntax-cli").Grammar;
const LLParsingTable = require("syntax-cli").LLParsingTable;
const jsdom = require("jsdom");

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 = require("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);
}
3 changes: 2 additions & 1 deletion deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ if [[ "$TRAVIS_PULL_REQUEST" != "false" || "$TRAVIS_BRANCH" != "$SOURCE_BRANCH"
echo "Skipping deploy; just doing a build."
mkdir out
doCompile
exit 0
node ./check-grammar.js ./out/index.html
exit $?
fi

# Save some useful information
Expand Down
8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -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 f6c6a2a

Please sign in to comment.