Browse Source

Parser calls AST node creator now

Before this commit, the PEG.js parser always created the AST using a plain JavaSctript object, but allthough simple and effective for the job, this method sacrificies performance slightly.

From now on the parser shall call a Node creator. This should help with performance, as well as in the future move some AST helpers into the new AST functions.
master
Futago-za Ryuu 4 years ago
parent
commit
93cc6c5b26
  1. 4
      gulpfile.js
  2. 28
      lib/parser/ast.js
  3. 94
      lib/parser/index.js
  4. 6
      src/config.json
  5. 91
      src/parser.pegjs

4
gulpfile.js

@ -35,7 +35,7 @@ task( "lint", () => gulp
.src( [
"**/.*rc.js",
"lib/**/*.js",
"!lib/parser.js",
"!lib/parser/index.js",
"test/benchmark/**/*.js",
"test/benchmark/run",
"test/impact",
@ -65,7 +65,7 @@ task( "benchmark", cb => {
// Generate the grammar parser.
task( "build:parser", cb => {
node( "bin/peg src/parser.pegjs -o lib/parser.js -c src/config.json", cb );
node( "bin/peg src/parser.pegjs -o lib/parser/index.js -c src/config.json", cb );
} );

28
lib/parser/ast.js

@ -0,0 +1,28 @@
"use strict";
class Node {
constructor( type, location ) {
this.type = type;
this.location = location;
}
}
exports.Node = Node;
class Grammar extends Node {
// Creates a new AST
constructor( initializer, rules, location ) {
super( "grammar", location );
this.initializer = initializer;
this.rules = rules;
}
}
exports.Grammar = Grammar;

94
lib/parser.js → lib/parser/index.js

@ -4,6 +4,9 @@
"use strict";
var ast = require("./ast");
var util = require("../util");
function peg$subclass(child, parent) {
function C() { this.constructor = child; }
C.prototype = parent.prototype;
@ -138,61 +141,50 @@ function peg$parse(input, options) {
var peg$startRuleFunction = peg$parseGrammar;
var peg$c0 = function(initializer, rules) {
return {
type: "grammar",
initializer: extractOptional(initializer, 0),
rules: extractList(rules, 0),
location: location()
};
return new ast.Grammar(
extractOptional(initializer, 0),
extractList(rules, 0),
location(),
);
};
var peg$c1 = function(code) {
return { type: "initializer", code: code, location: location() };
return createNode( "initializer", { code: code } );
};
var peg$c2 = "=";
var peg$c3 = peg$literalExpectation("=", false);
var peg$c4 = function(name, displayName, expression) {
return {
type: "rule",
return createNode( "rule", {
name: name,
expression: displayName !== null
? {
type: "named",
? createNode( "named", {
name: displayName[0],
expression: expression,
location: location()
}
} )
: expression,
location: location()
};
} );
};
var peg$c5 = "/";
var peg$c6 = peg$literalExpectation("/", false);
var peg$c7 = function(head, tail) {
return tail.length > 0
? {
type: "choice",
? createNode( "choice", {
alternatives: buildList(head, tail, 3),
location: location()
}
} )
: head;
};
var peg$c8 = function(expression, code) {
return code !== null
? {
type: "action",
? createNode( "action", {
expression: expression,
code: code[1],
location: location()
}
} )
: expression;
};
var peg$c9 = function(head, tail) {
return tail.length > 0
? {
type: "sequence",
? createNode( "sequence", {
elements: buildList(head, tail, 1),
location: location()
}
} )
: head;
};
var peg$c10 = ":";
@ -202,19 +194,15 @@ function peg$parse(input, options) {
error(`Label can't be a reserved word "${label[0]}".`, label[1]);
}
return {
type: "labeled",
return createNode( "labeled", {
label: label[0],
expression: expression,
location: location()
};
} );
};
var peg$c13 = function(operator, expression) {
return {
type: OPS_TO_PREFIXED_TYPES[operator],
return createNode( OPS_TO_PREFIXED_TYPES[operator], {
expression: expression,
location: location()
};
} );
};
var peg$c14 = "$";
var peg$c15 = peg$literalExpectation("$", false);
@ -223,11 +211,9 @@ function peg$parse(input, options) {
var peg$c18 = "!";
var peg$c19 = peg$literalExpectation("!", false);
var peg$c20 = function(expression, operator) {
return {
type: OPS_TO_SUFFIXED_TYPES[operator],
return createNode( OPS_TO_SUFFIXED_TYPES[operator], {
expression: expression,
location: location()
};
} );
};
var peg$c21 = "?";
var peg$c22 = peg$literalExpectation("?", false);
@ -245,18 +231,14 @@ function peg$parse(input, options) {
// nodes that already isolate label scope themselves. This leaves us with
// "labeled" and "sequence".
return expression.type === "labeled" || expression.type === "sequence"
? { type: "group", expression: expression, location: location() }
? createNode( "group", { expression: expression } )
: expression;
};
var peg$c32 = function(name) {
return { type: "rule_ref", name: name, location: location() };
return createNode( "rule_ref", { name: name } );
};
var peg$c33 = function(operator, code) {
return {
type: OPS_TO_SEMANTIC_PREDICATE_TYPES[operator],
code: code,
location: location()
};
return createNode( OPS_TO_SEMANTIC_PREDICATE_TYPES[operator], { code: code } );
};
var peg$c34 = peg$anyExpectation();
var peg$c35 = peg$otherExpectation("whitespace");
@ -292,12 +274,10 @@ function peg$parse(input, options) {
var peg$c65 = peg$otherExpectation("literal");
var peg$c66 = "i";
var peg$c67 = function(value, ignoreCase) {
return {
type: "literal",
return createNode( "literal", {
value: value,
ignoreCase: ignoreCase !== null,
location: location()
};
} );
};
var peg$c68 = peg$otherExpectation("string");
var peg$c69 = "\"";
@ -309,13 +289,11 @@ function peg$parse(input, options) {
var peg$c75 = "^";
var peg$c76 = "]";
var peg$c77 = function(inverted, parts, ignoreCase) {
return {
type: "class",
return createNode( "class", {
parts: parts.filter(part => part !== ""),
inverted: inverted !== null,
ignoreCase: ignoreCase !== null,
location: location()
};
} );
};
var peg$c78 = "-";
var peg$c79 = function(begin, end) {
@ -351,7 +329,7 @@ function peg$parse(input, options) {
var peg$c99 = /^[0-9a-f]/i;
var peg$c100 = ".";
var peg$c101 = peg$literalExpectation(".", false);
var peg$c102 = function() { return { type: "any", location: location() }; };
var peg$c102 = function() { return createNode( "any", {} ); };
var peg$c103 = peg$otherExpectation("code block");
var peg$c104 = "{";
var peg$c105 = "}";
@ -3121,6 +3099,12 @@ function peg$parse(input, options) {
return [head].concat(extractList(tail, index));
}
function createNode( type, details ) {
const node = new ast.Node( type, location() );
util.extend( node, details );
return node;
}
peg$begin();
peg$result = peg$startRuleFunction();

6
src/config.json

@ -1,3 +1,7 @@
{
"header": "/* eslint-disable */"
"header": "/* eslint-disable */",
"dependencies": {
"ast": "./ast",
"util": "../util"
}
}

91
src/parser.pegjs

@ -89,23 +89,28 @@
function buildList(head, tail, index) {
return [head].concat(extractList(tail, index));
}
function createNode( type, details ) {
const node = new ast.Node( type, location() );
util.extend( node, details );
return node;
}
}
// ---- Syntactic Grammar -----
Grammar
= __ initializer:(Initializer __)? rules:(Rule __)+ {
return {
type: "grammar",
initializer: extractOptional(initializer, 0),
rules: extractList(rules, 0),
location: location()
};
return new ast.Grammar(
extractOptional(initializer, 0),
extractList(rules, 0),
location(),
);
}
Initializer
= code:CodeBlock EOS {
return { type: "initializer", code: code, location: location() };
return createNode( "initializer", { code: code } );
}
Rule
@ -114,19 +119,15 @@ Rule
"=" __
expression:Expression EOS
{
return {
type: "rule",
return createNode( "rule", {
name: name,
expression: displayName !== null
? {
type: "named",
? createNode( "named", {
name: displayName[0],
expression: expression,
location: location()
}
} )
: expression,
location: location()
};
} );
}
Expression
@ -135,34 +136,28 @@ Expression
ChoiceExpression
= head:ActionExpression tail:(__ "/" __ ActionExpression)* {
return tail.length > 0
? {
type: "choice",
? createNode( "choice", {
alternatives: buildList(head, tail, 3),
location: location()
}
} )
: head;
}
ActionExpression
= expression:SequenceExpression code:(__ CodeBlock)? {
return code !== null
? {
type: "action",
? createNode( "action", {
expression: expression,
code: code[1],
location: location()
}
} )
: expression;
}
SequenceExpression
= head:LabeledExpression tail:(__ LabeledExpression)* {
return tail.length > 0
? {
type: "sequence",
? createNode( "sequence", {
elements: buildList(head, tail, 1),
location: location()
}
} )
: head;
}
@ -172,22 +167,18 @@ LabeledExpression
error(`Label can't be a reserved word "${label[0]}".`, label[1]);
}
return {
type: "labeled",
return createNode( "labeled", {
label: label[0],
expression: expression,
location: location()
};
} );
}
/ PrefixedExpression
PrefixedExpression
= operator:PrefixedOperator __ expression:SuffixedExpression {
return {
type: OPS_TO_PREFIXED_TYPES[operator],
return createNode( OPS_TO_PREFIXED_TYPES[operator], {
expression: expression,
location: location()
};
} );
}
/ SuffixedExpression
@ -198,11 +189,9 @@ PrefixedOperator
SuffixedExpression
= expression:PrimaryExpression __ operator:SuffixedOperator {
return {
type: OPS_TO_SUFFIXED_TYPES[operator],
return createNode( OPS_TO_SUFFIXED_TYPES[operator], {
expression: expression,
location: location()
};
} );
}
/ PrimaryExpression
@ -223,22 +212,18 @@ PrimaryExpression
// nodes that already isolate label scope themselves. This leaves us with
// "labeled" and "sequence".
return expression.type === "labeled" || expression.type === "sequence"
? { type: "group", expression: expression, location: location() }
? createNode( "group", { expression: expression } )
: expression;
}
RuleReferenceExpression
= name:IdentifierName !(__ (StringLiteral __)? "=") {
return { type: "rule_ref", name: name, location: location() };
return createNode( "rule_ref", { name: name } );
}
SemanticPredicateExpression
= operator:SemanticPredicateOperator __ code:CodeBlock {
return {
type: OPS_TO_SEMANTIC_PREDICATE_TYPES[operator],
code: code,
location: location()
};
return createNode( OPS_TO_SEMANTIC_PREDICATE_TYPES[operator], { code: code } );
}
SemanticPredicateOperator
@ -322,12 +307,10 @@ UnicodeConnectorPunctuation
LiteralMatcher "literal"
= value:StringLiteral ignoreCase:"i"? {
return {
type: "literal",
return createNode( "literal", {
value: value,
ignoreCase: ignoreCase !== null,
location: location()
};
} );
}
StringLiteral "string"
@ -351,13 +334,11 @@ CharacterClassMatcher "character class"
"]"
ignoreCase:"i"?
{
return {
type: "class",
return createNode( "class", {
parts: parts.filter(part => part !== ""),
inverted: inverted !== null,
ignoreCase: ignoreCase !== null,
location: location()
};
} );
}
ClassCharacterRange
@ -426,7 +407,7 @@ HexDigit
= [0-9a-f]i
AnyMatcher
= "." { return { type: "any", location: location() }; }
= "." { return createNode( "any", {} ); }
CodeBlock "code block"
= "{" code:Code "}" { return code; }

Loading…
Cancel
Save