Moved AST and visitor classes

master
Futago-za Ryuu 6 years ago
parent f41ef82ce9
commit 5476eca59f

@ -66,7 +66,7 @@ task( "benchmark", cb => {
// Generate the grammar parser. // Generate the grammar parser.
task( "build:parser", cb => { task( "build:parser", cb => {
node( "bin/peg src/grammar.pegjs -o lib/parser/grammar.js -c src/pegjs.config.js", cb ); node( "bin/peg src/parser.pegjs -o lib/parser.js -c src/pegjs.config.js", cb );
} ); } );

@ -1,20 +1,9 @@
"use strict"; "use strict";
const visitor = require( "../compiler/visitor" ); const Node = require( "./Node" );
const visitor = require( "./visitor" );
const util = require( "../util" ); const util = require( "../util" );
class Node {
constructor( type, location ) {
this.type = type;
this.location = location;
}
}
exports.Node = Node;
class Grammar extends Node { class Grammar extends Node {
// Creates a new AST // Creates a new AST
@ -57,7 +46,8 @@ class Grammar extends Node {
} }
} }
exports.Grammar = Grammar;
module.exports = Grammar;
/* ***************************** @private ***************************** */ /* ***************************** @private ***************************** */

@ -0,0 +1,14 @@
"use strict";
class Node {
constructor( type, location ) {
this.type = type;
this.location = location;
}
}
module.exports = Node;

@ -0,0 +1,5 @@
"use strict";
exports.visitor = require( "./visitor" );
exports.Node = require( "./Node" );
exports.Grammar = require( "./Grammar" );

@ -10,32 +10,34 @@ class ASTVisitor {
visit( node ) { visit( node ) {
// istanbul ignore next // istanbul ignore next
if ( ! node ) throw new Error( "Visitor function called with no or `null` node" ); if ( ! node ) throw new Error( "Visitor function called with no arguments or a `falsy` node" );
const func = this[ node.type ]; const fn = this[ node.type ];
// istanbul ignore next // istanbul ignore next
if ( ! func ) throw new Error( "Visitor function for node type '" + node.type + " not defined" ); if ( ! fn ) throw new Error( `Visitor function for node type "${ node.type }" not defined` );
const args = __slice.call( arguments, 0 ); return fn.apply( this, arguments );
return func.apply( this, args );
} }
}
module.exports = {
ASTVisitor,
// Simple AST node visitor builder for PEG.js // Simple AST node visitor builder for PEG.js
static build( functions ) { build( functions ) {
let visitor = new ASTVisitor(); let visitor = new ASTVisitor();
util.extend( visitor, functions ); util.extend( visitor, functions );
visitor = util.enforceFastProperties( visitor ); visitor = util.enforceFastProperties( visitor );
return visitor.visit.bind( visitor ); return visitor.visit.bind( visitor );
} },
} };
ASTVisitor.ASTVisitor = ASTVisitor;
module.exports = ASTVisitor;
// Helper's to create visitor's for use with the ASTVisitor class // Helper's to create visitor's for use with the ASTVisitor class
const on = ASTVisitor.for = { const on = ASTVisitor.for = {
@ -99,17 +101,19 @@ const DEFAULT_FUNCTIONS = {
grammar( node ) { grammar( node ) {
const extraArgs = __slice.call( arguments, 1 ); const args = [ void 0 ].concat( __slice.call( arguments, 1 ) );
if ( node.initializer ) { if ( node.initializer ) {
this.visit.apply( this, [ node.initializer ].concat( extraArgs ) ); args[ 0 ] = node.initializer;
this.visit.apply( this, args );
} }
node.rules.forEach( rule => { node.rules.forEach( rule => {
this.visit.apply( this, [ rule ].concat( extraArgs ) ); args[ 0 ] = rule;
this.visit.apply( this, args );
} ); } );

@ -10,7 +10,6 @@ const reportInfiniteRecursion = require( "./passes/report-infinite-recursion" );
const reportInfiniteRepetition = require( "./passes/report-infinite-repetition" ); const reportInfiniteRepetition = require( "./passes/report-infinite-repetition" );
const reportUndefinedRules = require( "./passes/report-undefined-rules" ); const reportUndefinedRules = require( "./passes/report-undefined-rules" );
const inferenceMatchResult = require( "./passes/inference-match-result" ); const inferenceMatchResult = require( "./passes/inference-match-result" );
const visitor = require( "./visitor" );
const util = require( "../util" ); const util = require( "../util" );
function processOptions( options, defaults ) { function processOptions( options, defaults ) {
@ -25,9 +24,6 @@ function processOptions( options, defaults ) {
} }
const compiler = { const compiler = {
// AST node visitor builder. Useful mainly for plugins which manipulate the
// AST.
visitor: visitor,
// Compiler passes. // Compiler passes.
// //
@ -96,6 +92,7 @@ const compiler = {
} }
} }
}; };
module.exports = compiler; module.exports = compiler;

@ -1,6 +1,6 @@
"use strict"; "use strict";
const visitor = require( "../visitor" ); const visitor = require( "../../ast" ).visitor;
// Determines if rule always used in disabled report failure context, // Determines if rule always used in disabled report failure context,
// that means, that any failures, reported within it, are never will be // that means, that any failures, reported within it, are never will be

@ -1,7 +1,7 @@
"use strict"; "use strict";
const op = require( "../opcodes" ); const op = require( "../opcodes" );
const visitor = require( "../visitor" ); const visitor = require( "../../ast" ).visitor;
const util = require( "../../util" ); const util = require( "../../util" );
// Generates bytecode. // Generates bytecode.

@ -1,6 +1,6 @@
"use strict"; "use strict";
const visitor = require( "../visitor" ); const visitor = require( "../../ast" ).visitor;
const GrammarError = require( "../../grammar-error" ); const GrammarError = require( "../../grammar-error" );
// Inference match result of the rule. Can be: // Inference match result of the rule. Can be:

@ -1,6 +1,6 @@
"use strict"; "use strict";
const visitor = require( "../visitor" ); const visitor = require( "../../ast" ).visitor;
// Removes proxy rules -- that is, rules that only delegate to other rule. // Removes proxy rules -- that is, rules that only delegate to other rule.
function removeProxyRules( ast, options ) { function removeProxyRules( ast, options ) {

@ -1,7 +1,7 @@
"use strict"; "use strict";
const GrammarError = require( "../../grammar-error" ); const GrammarError = require( "../../grammar-error" );
const visitor = require( "../visitor" ); const visitor = require( "../../ast" ).visitor;
const util = require( "../../util" ); const util = require( "../../util" );
const __hasOwnProperty = Object.prototype.hasOwnProperty; const __hasOwnProperty = Object.prototype.hasOwnProperty;

@ -1,7 +1,7 @@
"use strict"; "use strict";
const GrammarError = require( "../../grammar-error" ); const GrammarError = require( "../../grammar-error" );
const visitor = require( "../visitor" ); const visitor = require( "../../ast" ).visitor;
const __hasOwnProperty = Object.prototype.hasOwnProperty; const __hasOwnProperty = Object.prototype.hasOwnProperty;
// Checks that each rule is defined only once. // Checks that each rule is defined only once.

@ -1,7 +1,7 @@
"use strict"; "use strict";
const GrammarError = require( "../../grammar-error" ); const GrammarError = require( "../../grammar-error" );
const visitor = require( "../visitor" ); const visitor = require( "../../ast" ).visitor;
// Reports left recursion in the grammar, which prevents infinite recursion in // Reports left recursion in the grammar, which prevents infinite recursion in
// the generated parser. // the generated parser.

@ -1,7 +1,7 @@
"use strict"; "use strict";
const GrammarError = require( "../../grammar-error" ); const GrammarError = require( "../../grammar-error" );
const visitor = require( "../visitor" ); const visitor = require( "../../ast" ).visitor;
// Reports expressions that don't consume any input inside |*| or |+| in the // Reports expressions that don't consume any input inside |*| or |+| in the
// grammar, which prevents infinite loops in the generated parser. // grammar, which prevents infinite loops in the generated parser.

@ -1,7 +1,7 @@
"use strict"; "use strict";
const GrammarError = require( "../../grammar-error" ); const GrammarError = require( "../../grammar-error" );
const visitor = require( "../visitor" ); const visitor = require( "../../ast" ).visitor;
// Checks that all referenced rules exist. // Checks that all referenced rules exist.
function reportUndefinedRules( ast, options ) { function reportUndefinedRules( ast, options ) {

@ -5,7 +5,7 @@
"use strict"; "use strict";
var ast = require("./ast"); var ast = require("./ast");
var util = require("../util"); var util = require("./util");
function peg$subclass(child, parent) { function peg$subclass(child, parent) {
function C() { this.constructor = child; } function C() { this.constructor = child; }

@ -1,9 +0,0 @@
"use strict";
const ast = require( "./ast" );
const parser = require( "./grammar" );
parser.Grammar = ast.Grammar;
parser.Node = ast.Node;
module.exports = parser;

@ -1,6 +1,7 @@
"use strict"; "use strict";
const GrammarError = require( "./grammar-error" ); const GrammarError = require( "./grammar-error" );
const ast = require( "./ast" );
const compiler = require( "./compiler" ); const compiler = require( "./compiler" );
const parser = require( "./parser" ); const parser = require( "./parser" );
const util = require( "./util" ); const util = require( "./util" );
@ -10,6 +11,7 @@ const peg = {
VERSION: "0.11.0-dev", VERSION: "0.11.0-dev",
GrammarError: GrammarError, GrammarError: GrammarError,
ast: ast,
parser: parser, parser: parser,
compiler: compiler, compiler: compiler,
util: util, util: util,

344
lib/typings/api.d.ts vendored

@ -5,7 +5,7 @@ export as namespace peg;
declare namespace peg { declare namespace peg {
type AST = parser.Grammar; type Grammar = ast.Grammar;
type GeneratedParser<T = any> = gp.API<T>; type GeneratedParser<T = any> = gp.API<T>;
type SyntaxError = gp.SyntaxErrorConstructor; type SyntaxError = gp.SyntaxErrorConstructor;
type SourceLocation = gp.SourceLocation; type SourceLocation = gp.SourceLocation;
@ -28,13 +28,10 @@ declare namespace peg {
} }
/** namespace ast {
* A generated PEG.js parser to parse PEG.js grammar source's.
*/
namespace parser {
/** /**
* PEG.js node constructor, used internally by the PEG.js to create nodes. * PEG.js node constructor, used internally by the PEG.js parser to create nodes.
*/ */
class Node { class Node {
@ -54,20 +51,20 @@ declare namespace peg {
private readonly _alwaysConsumesOnSuccess: any; private readonly _alwaysConsumesOnSuccess: any;
type: "grammar"; type: "grammar";
comments?: CommentMao; comments?: Comment;
initializer?: ast.Initializer; initializer?: Initializer;
rules: ast.Rule[]; rules: Rule[];
constructor( constructor(
initializer: void | ast.Initializer, initializer: void | Initializer,
rules: ast.Rule[], rules: Rule[],
comments: void | CommentMao, comments: void | Comment,
location: SourceLocation, location: SourceLocation,
); );
findRule( name: string ): ast.Rule | void; findRule( name: string ): Rule | void;
indexOfRule( name: string ): number; indexOfRule( name: string ): number;
alwaysConsumesOnSuccess( node: ast.Node ): boolean; alwaysConsumesOnSuccess( node: Object ): boolean;
// Added by Bytecode generator // Added by Bytecode generator
@ -82,7 +79,7 @@ declare namespace peg {
} }
interface CommentMao { interface Comment {
[ offset: number ]: { [ offset: number ]: {
@ -94,189 +91,234 @@ declare namespace peg {
} }
interface INode extends peg.ast.Node { }
/** /**
* Interface's that describe the abstact sytax tree used by PEG.js * This type represent's all PEG.js AST node's.
*/ */
namespace ast { type Object
= Grammar
| Initializer
| Rule
| Named
| Expression;
interface INode extends parser.Node { } interface Initializer extends INode {
/** type: "initializer";
* Unlike `parser.Node` this interface represent's all PEG.js node's. code: string;
*/
type Node
= parser.Grammar
| Initializer
| Rule
| Named
| Expression;
interface Initializer extends INode { }
type: "initializer"; interface Rule extends INode {
code: string;
} // Default properties
interface Rule extends INode { type: "rule",
name: string;
expression: Named | Expression;
// Default properties // Added by calc-report-failures pass
type: "rule", reportFailures?: boolean;
name: string;
expression: Named | Expression;
// Added by calc-report-failures pass // Added by inference-match-result pass
reportFailures?: boolean; match?: number;
// Added by inference-match-result pass // Added by generate-bytecode pass
match?: number; bytecode?: number[];
// Added by generate-bytecode pass }
bytecode?: number[]; interface Named extends INode {
} type: "named";
name: string;
expression: Expression;
interface Named extends INode { }
type: "named"; type Expression
name: string; = ChoiceExpression
expression: Expression; | ActionExpression
| SequenceExpression
| LabeledExpression
| PrefixedExpression
| SuffixedExpression
| PrimaryExpression;
} interface ChoiceExpression extends INode {
type Expression type: "choice";
= ChoiceExpression alternatives: (
| ActionExpression ActionExpression
| SequenceExpression | SequenceExpression
| LabeledExpression | LabeledExpression
| PrefixedExpression | PrefixedExpression
| SuffixedExpression | SuffixedExpression
| PrimaryExpression; | PrimaryExpression
)[];
interface ChoiceExpression extends INode { }
type: "choice"; interface ActionExpression extends INode {
alternatives: (
ActionExpression
| SequenceExpression
| LabeledExpression
| PrefixedExpression
| SuffixedExpression
| PrimaryExpression
)[];
} type: "action";
expression: (
SequenceExpression
| LabeledExpression
| PrefixedExpression
| SuffixedExpression
| PrimaryExpression
);
code: string;
interface ActionExpression extends INode { }
type: "action"; interface SequenceExpression extends INode {
expression: (
SequenceExpression
| LabeledExpression
| PrefixedExpression
| SuffixedExpression
| PrimaryExpression
);
code: string;
} type: "sequence",
elements: (
LabeledExpression
| PrefixedExpression
| SuffixedExpression
| PrimaryExpression
)[];
interface SequenceExpression extends INode { }
type: "sequence", interface LabeledExpression extends INode {
elements: (
LabeledExpression
| PrefixedExpression
| SuffixedExpression
| PrimaryExpression
)[];
} type: "labeled";
label: string;
expression: (
PrefixedExpression
| SuffixedExpression
| PrimaryExpression
);
interface LabeledExpression extends INode { }
type: "labeled"; interface PrefixedExpression extends INode {
label: string;
expression: (
PrefixedExpression
| SuffixedExpression
| PrimaryExpression
);
} type: "text" | "simple_and" | "simple_not";
expression: SuffixedExpression | PrimaryExpression;
}
interface PrefixedExpression extends INode { interface SuffixedExpression extends INode {
type: "text" | "simple_and" | "simple_not"; type: "optional" | "zero_or_more" | "one_or_more";
expression: SuffixedExpression | PrimaryExpression; expression: PrimaryExpression;
} }
interface SuffixedExpression extends INode { type PrimaryExpression
= LiteralMatcher
| CharacterClassMatcher
| AnyMatcher
| RuleReferenceExpression
| SemanticPredicateExpression
| GroupExpression;
type: "optional" | "zero_or_more" | "one_or_more"; interface LiteralMatcher extends INode {
expression: PrimaryExpression;
} type: "literal";
value: string;
ignoreCase: boolean;
type PrimaryExpression }
= LiteralMatcher
| CharacterClassMatcher
| AnyMatcher
| RuleReferenceExpression
| SemanticPredicateExpression
| GroupExpression;
interface LiteralMatcher extends INode { interface CharacterClassMatcher extends INode {
type: "literal"; type: "class";
value: string; parts: ( string[] | string )[];
ignoreCase: boolean; inverted: boolean;
ignoreCase: boolean;
} }
interface CharacterClassMatcher extends INode { interface AnyMatcher extends INode {
type: "class"; type: "any";
parts: ( string[] | string )[];
inverted: boolean;
ignoreCase: boolean;
} }
interface AnyMatcher extends INode { interface RuleReferenceExpression extends INode {
type: "any"; type: "rule_ref";
name: string;
} }
interface SemanticPredicateExpression extends INode {
type: "semantic_and" | "semantic_not";
code: string;
}
interface RuleReferenceExpression extends INode { interface GroupExpression extends INode {
type: "rule_ref"; type: "group";
name: string; expression: LabeledExpression | SequenceExpression;
}
namespace visitor {
interface IVisitorMap<U = void> {
[ key: string ]: any;
grammar?<R = U>( node: Grammar, ...args ): R;
initializer?<R = U>( node: Initializer, ...args ): R;
rule?<R = U>( node: Rule, ...args ): R;
named?<R = U>( node: Named, ...args ): R;
choice?<R = U>( node: ChoiceExpression, ...args ): R;
action?<R = U>( node: ActionExpression, ...args ): R;
sequence?<R = U>( node: SequenceExpression, ...args ): R;
labeled?<R = U>( node: LabeledExpression, ...args ): R;
text?<R = U>( node: PrefixedExpression, ...args ): R;
simple_and?<R = U>( node: PrefixedExpression, ...args ): R;
simple_not?<R = U>( node: PrefixedExpression, ...args ): R;
optional?<R = U>( node: SuffixedExpression, ...args ): R;
zero_or_more?<R = U>( node: SuffixedExpression, ...args ): R;
one_or_more?<R = U>( node: SuffixedExpression, ...args ): R;
literal?<R = U>( node: LiteralMatcher, ...args ): R;
class?<R = U>( node: CharacterClassMatcher, ...args ): R;
any?<R = U>( node: AnyMatcher, ...args ): R;
rule_ref?<R = U>( node: RuleReferenceExpression, ...args ): R;
semantic_and?<R = U>( node: SemanticPredicateExpression, ...args ): R;
semantic_not?<R = U>( node: SemanticPredicateExpression, ...args ): R;
group?<R = U>( node: GroupExpression, ...args ): R;
} }
interface SemanticPredicateExpression extends INode { class ASTVisitor implements IVisitorMap {
type: "semantic_and" | "semantic_not"; visit<R = any>( node: Object, ...args ): R;
code: string;
} }
interface GroupExpression extends INode { interface IVisitor<R = any> {
type: "group"; ( node: Object, ...args ): R;
expression: LabeledExpression | SequenceExpression;
} }
function build<T = void, R = any>( functions: IVisitorMap<T> ): IVisitor<R>;
} }
}
/**
* A generated PEG.js parser to parse PEG.js grammar source's.
*/
namespace parser {
const SyntaxError: SyntaxError; const SyntaxError: SyntaxError;
function parse( input: string, options?: gp.IOptions ): Grammar; function parse( input: string, options?: gp.IOptions ): Grammar;
@ -330,48 +372,6 @@ declare namespace peg {
} }
interface IVisitor<R = any> {
( node: parser.ast.Node, ...args ): R;
}
interface IVisitorMap<U = void> {
[ key: string ]: any;
grammar?<R = U>( node: Grammar, ...args ): R;
initializer?<R = U>( node: parser.ast.Initializer, ...args ): R;
rule?<R = U>( node: parser.ast.Rule, ...args ): R;
named?<R = U>( node: parser.ast.Named, ...args ): R;
choice?<R = U>( node: parser.ast.ChoiceExpression, ...args ): R;
action?<R = U>( node: parser.ast.ActionExpression, ...args ): R;
sequence?<R = U>( node: parser.ast.SequenceExpression, ...args ): R;
labeled?<R = U>( node: parser.ast.LabeledExpression, ...args ): R;
text?<R = U>( node: parser.ast.PrefixedExpression, ...args ): R;
simple_and?<R = U>( node: parser.ast.PrefixedExpression, ...args ): R;
simple_not?<R = U>( node: parser.ast.PrefixedExpression, ...args ): R;
optional?<R = U>( node: parser.ast.SuffixedExpression, ...args ): R;
zero_or_more?<R = U>( node: parser.ast.SuffixedExpression, ...args ): R;
one_or_more?<R = U>( node: parser.ast.SuffixedExpression, ...args ): R;
literal?<R = U>( node: parser.ast.LiteralMatcher, ...args ): R;
class?<R = U>( node: parser.ast.CharacterClassMatcher, ...args ): R;
any?<R = U>( node: parser.ast.AnyMatcher, ...args ): R;
rule_ref?<R = U>( node: parser.ast.RuleReferenceExpression, ...args ): R;
semantic_and?<R = U>( node: parser.ast.SemanticPredicateExpression, ...args ): R;
semantic_not?<R = U>( node: parser.ast.SemanticPredicateExpression, ...args ): R;
group?<R = U>( node: parser.ast.GroupExpression, ...args ): R;
}
class visitor implements IVisitorMap {
visit: IVisitor;
static build<T = void, R = any>( functions: IVisitorMap<T> ): IVisitor<R>;
static ASTVisitor: visitor;
}
namespace passes { namespace passes {
namespace check { namespace check {

@ -18,22 +18,40 @@ declare module "pegjs/lib/parser" {
} }
declare module "pegjs/lib/parser/ast" { declare module "pegjs/lib/peg" {
export const Node: peg.parser.Node; export default peg;
export const Grammar: peg.parser.Grammar;
} }
declare module "pegjs/lib/parser/index" { declare module "pegjs/lib/ast" {
export default peg.parser; export const Node: peg.ast.Node;
export const Grammar: peg.ast.Grammar;
export const visitor: {
ASTVisitor: peg.ast.visitor.ASTVisitor;
build<T = void, R = any>( functions: peg.ast.visitor.IVisitorMap<T> ): peg.ast.visitor.IVisitor<R>;
};
} }
declare module "pegjs/lib/peg" { declare module "pegjs/lib/ast/Grammar" {
export default peg; export default peg.ast.Grammar;
}
declare module "pegjs/lib/ast/Node" {
export default peg.ast.Node;
}
declare module "pegjs/lib/ast/visitor" {
export default peg.ast.visitor;
} }
@ -68,12 +86,6 @@ declare module "pegjs/lib/compiler/opcodes" {
} }
declare module "pegjs/lib/compiler/visitor" {
export default peg.compiler.visitor;
}
declare module "pegjs/lib/compiler/passes/calc-report-failures" { declare module "pegjs/lib/compiler/passes/calc-report-failures" {
export default peg.compiler.passes.generate.calcReportFailures; export default peg.compiler.passes.generate.calcReportFailures;

@ -7,7 +7,7 @@ module.exports = {
dependencies: { dependencies: {
ast: "./ast", ast: "./ast",
util: "../util" util: "./util"
}, },

@ -103,11 +103,11 @@ describe( "plugin API", function () {
config.parser = peg.generate( ` config.parser = peg.generate( `
{ {
const pp = require( process.cwd() + "/lib/peg" ).parser; const ast = require( process.cwd() + "/lib/ast" );
} }
start = .* { start = .* {
return new pp.Grammar( void 0, [{ return new ast.Grammar( void 0, [{
type: "rule", type: "rule",
name: "start", name: "start",
expression: { expression: {

@ -3,6 +3,7 @@
const chai = require( "chai" ); const chai = require( "chai" );
const parser = require( "pegjs-dev" ).parser; const parser = require( "pegjs-dev" ).parser;
const util = require( "pegjs-dev" ).util; const util = require( "pegjs-dev" ).util;
const visitor = require( "pegjs-dev" ).ast.visitor;
const expect = chai.expect; const expect = chai.expect;
@ -167,16 +168,6 @@ describe( "PEG.js grammar parser", function () {
let strip; let strip;
function buildVisitor( functions ) {
return function ( node ) {
return functions[ node.type ].apply( null, arguments );
};
}
function stripLeaf( node ) { function stripLeaf( node ) {
delete node.location; delete node.location;
@ -203,7 +194,7 @@ describe( "PEG.js grammar parser", function () {
} }
strip = buildVisitor( { strip = visitor.build( {
grammar( node ) { grammar( node ) {
delete node.location; delete node.location;

Loading…
Cancel
Save