npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

parsey

v0.2.0

Published

A parser for context-free grammars

Downloads

10

Readme

Parsey

NPM Version Build Status Coverage Status Inline Docs

Parsey is a parser for context-free grammars. It utilizes earley parsing, a top-down chart parsing algorithm that can parse a large set of grammars.

Parsey takes a list of rules (which can be defined using the Rule constructor) and some input sentence, then constructs a parse tree for the given language. The many applications of this include abstract syntax tree creation, NLP, and arithmetic, to name a few.

Installation

Install from npm:

npm install parsey --save

Usage

const Rule    = require('parsey').Rule;
const Sym     = require('parsey').Sym;
const parse   = require('parsey').parse;

const sum     = new Sym('sum');
const prod    = new Sym('prod');
const factor  = new Sym('factor');

// Rule( [lhs : Sym], [rhs : Array], [valuator : Function] )

let grammar = [
  // sum
  new Rule(sum    , [sum, '+', prod]    , (x, _, y) => x + y),
  new Rule(sum    , [prod]              , (x) => x),

  // product
  new Rule(prod   , [prod, '*', factor] , (x, _, y) => x * y),
  new Rule(prod   , [factor]            , (x) => x),

  // factor
  new Rule(factor , ['(', sum, ')']     , (_, x) => x),
  new Rule(factor , [/\d+/]             , (n) => parseFloat(n))
];

let expr = '2 + 3 * (1 + 4)';
let parseTree = parse(exp, grammar);

console.log(evaluate(parseTree));
// => 17

Rules and Sym(bol)s

A Sym is nothing more than an object that references a specific symbol for use in grammar rules, with a name attribute that describes the symbol (names need not be unique).

const Sym = require('parsey').Sym;
let sum = new Sym('sum');
let prod = new Sym('prod');

Rules describe the structure of a language. They contain a left-hand side consisting of a sole symbol, a right-hand side consisting of a list of symbols, and an optional evaluation function.

const Rule = require('parsey').Rule;
//                     lhs        rhs               valuator
let sumRule = new Rule(sum, [sum, '+', prod], (x, _, y) => x + y);

This rule states that a sum can be any sum, followed by a +, followed by any prod. The rhs can be populated with Sym objects, strings, or RegExp objects.

This rule's valuator is a function that takes 3 arguments (one for each symbol on the rhs), and adds the first and last (we don't care about the '+').

The Rule class is extended from Array, so the rhs symbols correspond to a Rule's indices and all of the methods on Array.prototype will apply to the rhs.

The CFG

The CFG is a glorified array, a container for your rules. It has some methods like rule() and getSymbols(), which can be handy for creating rules from strings.

const CFG = require('parsey').CFG;
let grammar = new CFG();

grammar.rule('S -> NP VP');
grammar.rule('NP -> Det N');
grammar.rule('VP -> V NP');

grammar.rule('Det -> "the");
grammar.rule('Det -> "a");

grammar.rule('V -> /runs?/');
grammar.rule('V -> "ran"');

rule() will try to find existing symbols in the grammar that have the same names as the ones that appear in a production string, and will create new Sym objects if a symbol could not be found.

It will also treat string-looking symbols like "the" as terminal symbols and leave them as strings, and likewise will turn things like /regex/ into RegExp objects, which are also terminals.

Parsing

Given a list of Rules, parsing becomes as simple as

const parse = require('parsey').parse;
parse('1 + 2 * 3', grammar);

The parse() function returns a parse tree, which is a node of the following structure:

{
  item: [Rule],
  children: [Array]
}

Elements in children can be either nodes of the above structure, or strings.

Example:

// 1 * 2
{
  item: <Rule 'prod' [prod, '*', factor]>,
  children: [
    {
      item: <Rule 'factor' [/\d+/]>,
      children: [ '1' ]
    },
    '*',
    {
      item: <Rule 'factor' [/\d+/]>,
      children: [ '2' ]
    }
  ]
}

Examples

Check out examples to see parsey in action for various use cases!

Testing

Testing parsey requres jasmine (2.0+). All specs can be found in spec/. To run all tests, simply run npm test in the project's root.

License

MIT