Browse Source

Support import syntax

redux
Sven Slootweg 2 years ago
parent
commit
1d3a57d256
  1. 14
      experiments/run-test.js
  2. 5
      experiments/test.pegjs
  3. 1643
      lib/parser.js
  4. 19
      lib/peg.js
  5. 52
      notes.txt
  6. 33
      src/parser.pegjs
  7. 10
      test/unit/parser.spec.js

14
experiments/run-test.js

@ -0,0 +1,14 @@
"use strict";
const fs = require("fs");
const path = require("path");
const util = require("util");
const generate = require("../").generate;
const parser = require("../lib/parser");
let grammar = fs.readFileSync(path.join(__dirname, "test.pegjs"), { encoding: "utf-8" });
// let parseResult = parser.parse(grammar);
let parseResult = generate(grammar);
console.log(util.inspect(parseResult, { depth: null, colors: true }));

5
experiments/test.pegjs

@ -0,0 +1,5 @@
import Foo from "./util.pegjs"
import { CommaDelimited as DelimitedNumber } from "./delimited-number"
TopLevelRule
= "hello"

1643
lib/parser.js

File diff suppressed because one or more lines are too long

19
lib/peg.js

@ -33,10 +33,19 @@ module.exports = {
})
};
return compiler.compile(
config.parser.parse(grammar),
config.passes,
options
);
let parseResult = config.parser.parse(grammar);
if (parseResult.imports.length === 0) {
return compiler.compile(
parseResult,
config.passes,
options
);
} else {
throw new Error("`import` syntax can only be used with `generateFromFile`");
}
},
generateFromFile: function (path, options = {}) {
throw new Error(`Unimplemented`);
}
};

52
notes.txt

@ -0,0 +1,52 @@
Import syntax
import Foo from packagename
import { Foo, Bar } from ./util
import { Foo as Bar, Baz, Qux } from ../quz
need to mangle identifiers declared in the initializer!
===========
Benchmark before internals changes (best of 3):
$ yarn benchmark
yarn run v1.21.1
$ node benchmark/run
┌─────────────────────────────────────┬───────────┬────────────┬──────────────┐
│ Test │ Inp. size │ Avg. time │ Avg. speed │
├─────────────────────────────────────┴───────────┴────────────┴──────────────┤
│ JSON │
├─────────────────────────────────────┬───────────┬────────────┬──────────────┤
│ Example 1 │ 0.69 kB │ 0.40 ms │ 1723.63 kB/s │
│ Example 2 │ 0.24 kB │ 0.10 ms │ 2363.28 kB/s │
│ Example 3 │ 0.59 kB │ 0.40 ms │ 1474.61 kB/s │
│ Example 4 │ 3.39 kB │ 0.90 ms │ 3763.02 kB/s │
│ Example 5 │ 0.85 kB │ 0.20 ms │ 4262.70 kB/s │
├─────────────────────────────────────┼───────────┼────────────┼──────────────┤
│ JSON total │ 5.75 kB │ 2.00 ms │ 2877.44 kB/s │
├─────────────────────────────────────┴───────────┴────────────┴──────────────┤
│ CSS │
├─────────────────────────────────────┬───────────┬────────────┬──────────────┤
│ Blueprint - reset.css (source) │ 1.20 kB │ 3.00 ms │ 401.04 kB/s │
│ Blueprint - typography.css (source) │ 3.11 kB │ 5.00 ms │ 621.48 kB/s │
│ Blueprint - forms.css (source) │ 1.79 kB │ 2.00 ms │ 896.00 kB/s │
│ Blueprint - grid.css (source) │ 9.54 kB │ 6.50 ms │ 1467.25 kB/s │
│ Blueprint - print.css (source) │ 1.78 kB │ 1.10 ms │ 1621.09 kB/s │
│ Blueprint - screen.css (minified) │ 11.83 kB │ 8.00 ms │ 1478.64 kB/s │
│ Blueprint - print.css (minified) │ 1.25 kB │ 0.60 ms │ 2089.84 kB/s │
│ 960.gs - reset.css (source) │ 0.99 kB │ 0.50 ms │ 1980.47 kB/s │
│ 960.gs - text.css (source) │ 0.97 kB │ 0.40 ms │ 2426.76 kB/s │
│ 960.gs - 960.css (source) │ 8.94 kB │ 3.00 ms │ 2979.49 kB/s │
│ 960.gs - 960_24_col.css (source) │ 7.48 kB │ 2.60 ms │ 2877.85 kB/s │
│ 960.gs - reset.css (minified) │ 0.63 kB │ 0.50 ms │ 1265.63 kB/s │
│ 960.gs - text.css (minified) │ 0.41 kB │ 0.40 ms │ 1020.51 kB/s │
│ 960.gs - 960.css (minified) │ 5.21 kB │ 2.60 ms │ 2004.21 kB/s │
│ 960.gs - 960_24_col.css (minified) │ 4.94 kB │ 2.40 ms │ 2057.70 kB/s │
├─────────────────────────────────────┼───────────┼────────────┼──────────────┤
│ CSS total │ 60.08 kB │ 38.60 ms │ 1556.43 kB/s │
├─────────────────────────────────────┼───────────┼────────────┼──────────────┤
│ Total │ 65.83 kB │ 40.60 ms │ 1621.50 kB/s │
└─────────────────────────────────────┴───────────┴────────────┴──────────────┘
Done in 0.60s.

33
src/parser.pegjs

@ -55,15 +55,45 @@
// ---- Syntactic Grammar -----
Grammar
= __ initializer:(Initializer __)? rules:(Rule __)+ {
= __ imports:(ImportStatement __)* initializer:(Initializer __)? rules:(Rule __)+ {
return {
type: "grammar",
initializer: extractOptional(initializer, 0),
rules: extractList(rules, 0),
imports: extractList(imports, 0),
location: location()
};
}
ImportStatement
= "import" _ bindings:ImportBindings _ "from" _ path:StringLiteral EOS {
return {
type: "import",
path: path,
bindings: bindings,
location: location()
};
}
ImportBindings
= TopLevelImportBinding
/ NamedImportBindings
TopLevelImportBinding
= binding:ImportBinding {
return { type: "topLevelBinding", binding: binding, location: location() };
}
NamedImportBindings
= "{" __ head:(ImportBinding __) tail:("," __ ImportBinding __)* "}" {
return { type: "namedBindings", bindings: buildList(head[0], tail, 2), location: location() };
}
ImportBinding
= name:IdentifierName alias:(_ "as" _ IdentifierName)? {
return { type: "binding", name: name, alias: extractOptional(alias, 3), location: location() };
}
Initializer
= code:CodeBlock EOS {
return { type: "initializer", code: code, location: location() };
@ -242,6 +272,7 @@ SingleLineComment
Identifier
= !ReservedWord name:IdentifierName { return name; }
// TODO: Can performance here be improved by using $?
IdentifierName "identifier"
= head:IdentifierStart tail:IdentifierPart* { return head + tail.join(""); }

10
test/unit/parser.spec.js

@ -65,6 +65,7 @@ describe("PEG.js grammar parser", function() {
function oneRuleGrammar(expression) {
return {
type: "grammar",
imports: [],
initializer: null,
rules: [{ type: "rule", name: "start", expression: expression }]
};
@ -102,6 +103,7 @@ describe("PEG.js grammar parser", function() {
let trivialGrammar = literalGrammar("abcd", false);
let twoRuleGrammar = {
type: "grammar",
imports: [],
initializer: null,
rules: [ruleA, ruleB]
};
@ -226,20 +228,20 @@ describe("PEG.js grammar parser", function() {
// Canonical Grammar is "a = 'abcd'; b = 'efgh'; c = 'ijkl';".
it("parses Grammar", function() {
expect("\na = 'abcd';\n").to.parseAs(
{ type: "grammar", initializer: null, rules: [ruleA] }
{ type: "grammar", imports: [], initializer: null, rules: [ruleA] }
);
expect("\na = 'abcd';\nb = 'efgh';\nc = 'ijkl';\n").to.parseAs(
{ type: "grammar", initializer: null, rules: [ruleA, ruleB, ruleC] }
{ type: "grammar", imports: [], initializer: null, rules: [ruleA, ruleB, ruleC] }
);
expect("\n{ code };\na = 'abcd';\n").to.parseAs(
{ type: "grammar", initializer: initializer, rules: [ruleA] }
{ type: "grammar", imports: [], initializer: initializer, rules: [ruleA] }
);
});
// Canonical Initializer is "{ code }".
it("parses Initializer", function() {
expect("{ code };start = 'abcd'").to.parseAs(
{ type: "grammar", initializer: initializer, rules: [ruleStart] }
{ type: "grammar", imports: [], initializer: initializer, rules: [ruleStart] }
);
});

Loading…
Cancel
Save