Home Manual Reference Source

Overview

import { grammar , ll1 } from '@formal-language/grammar' ;
import * as tape from '@async-abstraction/tape' ;

const root = 'root' ;
const start = 'start' ;
const eof = '$' ;
const productions = { 'root' : { 'start' : [ ... , '=$' ] } , ... } ;

const G = grammar.from( { root , start , eof , productions } ) ; // Grammar Object

ll1.is(G); // true

const parser = ll1.from(G); // Parser Object

const replace = async input => {

    const tokens = tape.fromString( ... ) ; // create tokens from string `input`

    const tree = parser.parse( tokens ) ; // root of parsed tree

    const transformed = await ast.transform( tree , ... ) ; // root of transformed tree

    const flattened = ast.flatten( transformed ) ; // async generator of leaves

    const chunks = asyncIterableMap( leaf => leaf.buffer , flattened ) ; // async generator of strings

    const output = tape.fromAsyncIterable( chunks ) ; // tape of chunks

    return await tape.toString( output ) ; // chunks concatenation

} ;

replace('010101').then( output => console.log(output) ) ; // 'ababab'

Installation

Can be managed using yarn, npm, or jspm.

yarn

yarn add @formal-language/grammar

npm

npm install @formal-language/grammar --save

jspm

jspm install npm:@formal-language/grammar

Usage

:warning: Depending on your environment, the code may require regeneratorRuntime to be defined, for instance by importing regenerator-runtime/runtime.

First, require the polyfill at the entry point of your application

await import( 'regenerator-runtime/runtime.js' ) ;
// or
import 'regenerator-runtime/runtime.js' ;

Then, import the library where needed

const grammarToolkit = await import( '@formal-language/grammar' ) ;
// or
import { ast , error , grammar , ll1 , util } from '@formal-language/grammar' ;

Examples

More examples in the test files.

A convoluted '010101'.replace(/0/g, 'a').replace(/1/g, 'b').

import {map} from '@iterable-iterator/map';
import {enumerate} from '@iterable-iterator/zip';
import * as tape from '@async-abstraction/tape' ;
import {asyncIterableMap} from '@async-abstraction/tape';
import { grammar , ll1 , ast } from '@formal-language/grammar' ;

const G = grammar.from( {
    "root" : "root" ,
    "start" : "start" ,
    "eof" : "$" ,
    "productions" : {
        "root" : {
            "start" : [ "&bits" , "=$" ]
        } ,
        "bits" : {
            "add" : [ "&bit" , "&bits" ] ,
            "end" : [ ] ,
        } ,
        "bit" : [
            [ "=0" ] ,
            [ "=1" ] ,
        ] ,
    } ,
} ) ;

const parser = ll1.from(G);

const replace = async input => {

    const tokens = tape.fromIterable(
        map(
            ( [ i , a ] ) => ({
                "type" : "leaf" ,
                "terminal" : a ,
                "buffer" : a ,
                "position" : i ,
            }) ,
            enumerate( input )
        )
    ) ;

    const tree = parser.parse(tokens);

    const m = ( children , match , ctx ) => ast.map( async child => child.type === 'leaf' ? child : await ast.transform( child , match , ctx ) , children ) ;

    const transform = {
        "root" : {
            "start" : ( tree , match ) => ({
                "type" : "node" ,
                "nonterminal" : "root" ,
                "production" : "start" ,
                "children" : m( tree.children , match ) ,
            }) ,
        } ,
        "bits" : {
            "add" : ( tree , match ) =>  ({
                "type" : "node" ,
                "nonterminal" : "letters" ,
                "production" : "yetanotherletter" ,
                "children" : m( tree.children , match ) ,
            }) ,
            "end" : ( ) =>  ({
                "type" : "node" ,
                "nonterminal" : "letters" ,
                "production" : "done" ,
                "children" : [ ] ,
            }) ,
        } ,
        "bit" : [
            tree => ({
                "type" : "node" ,
                "nonterminal" : "letter" ,
                "production" : "aaa" ,
                "children" : ast.map( leaf => ({
                    "type" : "leaf" ,
                    "terminal" : "a" ,
                    "buffer" : "a" ,
                    "position" : leaf.position ,
                }) , tree.children ) ,
            }) ,
            tree => ({
                "type" : "node" ,
                "nonterminal" : "letter" ,
                "production" : "bbb" ,
                "children" : ast.map( leaf => ({
                    "type" : "leaf" ,
                    "terminal" : "b" ,
                    "buffer" : "b" ,
                    "position" : leaf.position ,
                }) , tree.children ) ,
            }) ,
        ] ,
    } ;

    const transformed = await ast.transform( tree , transform ) ;

    const flattened = ast.flatten( transformed ) ;

    const chunks = asyncIterableMap( leaf => leaf.buffer , flattened ) ;

    const output = tape.fromAsyncIterable( chunks ) ;

    return await tape.toString( output ) ;

} ;

replace('010101').then( output => console.log(output) ) ; // 'ababab'