Pegjs: How to deploy it from the commandline?

Created on 6 Jun 2017  ·  24Comments  ·  Source: pegjs/pegjs

I made a .peg file (online) that validates. I would like to use in at home on the commandline. I installed pegjs from the Ubuntu 16.04 repos. I did pegjs tldr.peg and it produced a tldr.js file.

How do I use that on the commandline? I have files I'd like to check.

question

Most helpful comment

Looks good! Thanks for making a more complete example, @jodevsa. I was assuming he knew JavaScript.

But that kind of brings up the idea that people may want to use PEG.js without even knowing JavaScript at all. I think it would be handy to provide a program that can generically read a grammar and input file, and output to a file or standard output.

All 24 comments

So you want to create a command line tool that use's the .peg you created and validate files based on a command line parameter. am i right?

for ex:
validate_file ~/file.blah

@pepa65

@jodevsa That's what I'm trying to achieve..!

The generated tldr.js is just a general library invoked by parse function, you gotta write a program that does this !

1- read the file
2- send file content to tldr library
3- output result ?

PEG.js generated library function definition:

var parser=require('./tldr').parse;

extract data from the file you want and use parser(fileContent) !

If you're using Node, here's a more concrete example:

#!/usr/bin/env node

'use strict';

//
// echo "2 + 3" | node compile.js arithmetics.pegjs
// echo "2 + 3" | node compile.js javascript.pegjs
//

let fs = require('fs');
let peg = require('../lib/peg');

let grammar = fs.readFileSync(process.argv[2]).toString();
let parser = peg.generate(grammar);
let input = [];

compile(process.stdin);

function compile(stdin) {
  stdin.resume();
  stdin.setEncoding('utf8');

  stdin.on('data', (data) => input.push(data));

  stdin.on('end', () => {
    let output = parser.parse(input.join('').trim());

    console.log(JSON.stringify(output, null, 2));
  });
}

Maybe it would be helpful to have an app that does that more generally.

@mikeaustin Clearly this isn't the easiest way for him to understand what you did
@pepa65 Check this out:

#!/usr/bin/env node
'use strict';

const fs = require('fs');
const parser = require('./tldr.js').parse;

function main() {
    const args = require('process').argv;
    if (args.length != 3) {
        console.error("Enter file Path as argument.")
        return 1;
    }
    let filename = args[2];
    fs.readFile(filename, {encoding: 'utf8'},function(err, data) {
        if (err) {
            console.log("error while reading the file!");
            console.error(err);
            return 1;
        }

        try {
            let output = parser(data);
            console.log(output)

        } catch (e) {
            console.error(e.message);

        }


    });

}

main();

  • put it in a folder with you'r tldr.js lets say you named it check_file

  • chmod +x check_file

  • add folder location to $path in ~/.bashrc and reset terminal

  • now you can use it like this, check_file ~/file.txt

@mikeaustin I don't seem to have ../lib/peg even though I have node-pegjs (and peg) installed.

What I am after is a generalized node script that I could call like: peg-check tldr.pegjs file-to-be-checked where tldr.pegjs is the output of pegjs tldr.peg tldr.pegjs and file-to-be-checked contains the text being checked.

Or, if pegjs could optionally output a script that incorporates tldr.pegjs, so that pegjs tldr.peg -s tldr-check would output a script that could be used like: tldr-check file-to-be-checked, that would raise the usability of pegjs enormously for the uninitiated..!

@jodevsa Thanks!
I got

let output = parser(data);
            ^^^

SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode

So I added 'use strict';, but then I got:

const arguments = require('process').argv;
          ^^^^^^^^^

SyntaxError: Unexpected eval or arguments in strict mode

I guess my javascript-fu is not strong enough...

@pepa65 i updated the code, check it again
my bad :(

@pepa65 i'm using node v 8.0.0 , if another error pop's out just replace each "let" and "const" with var

@pepa65
NVM, just try this

#!/usr/bin/env node

  'use strict';

  var fs = require('fs');
  var parser = require('./tldr.js').parse;

  function main() {
      var args = require('process').argv;
      if (args.length != 3) {
          console.error("Enter file Path as argument.")
          return 1;
      }
      var filename = args[2];
      fs.readFile(filename, {encoding: 'utf8'},function(err, data) {
          if (err) {
              console.log("error while reading the file!");
              console.error(err);
              return 1;
          }

          try {
              var output = parser(data);
              console.log(output)

          } catch (e) {
              console.error(e.message);

          }


      });

  }

  main();

const works fine here. The only snag I hit was that tldr.js contained printf (which I replaced with console.log), but then it works!
The only thing I don't understand that it ends the output with undefined no matter what.

weird, javascript doesn't even contain a "printf" function; even older versions
if you'r okay with posting your grammar public, it would be easier for me to help

O, sorry, reviewing my peg, I saw that I had wrongly added { printf("OK");}, so I changed that.
But it still ends with undefined. My grammar:

page = header description examples eof { console.log("OK");}
header = command nl underline nl nl
description = (descriptor nolowercase any dot nl)+
examples = example (nl example)*
example = example_description nl example_command
example_description = nolowercase any colon nl
example_command = fourspace any nl
command = [a-zA-Z0-9_][-a-zA-Z0-9_ ]*
underline = '='+
any = [a-z ()-,-.={}/_0-9A-Z]*
nolowercase = [^a-z]
descriptor = '> '
fourspace = '    '
dot = .
colon = ':'
nl = [\n]
eof = !.

@pepa65 That's because the running script that @jodevsa gave you logs the result of running the peg grammar; because your top-level page rule ends with a console.log, the PEG will return undefined to the running script.

You can either change the console.log(OK) to return "OK";, ignore the undefined that's printed, or remove the console.log(output) line from the running script.

Hope that helps!

@hawkrives :+1:

Right, silly of me. Makes it easier! I think I got things to where I can proceed. Thank you all!

I guess, as a summary to those who come here looking for the final answer, use this script, perhaps call it grammar-check:

#!/usr/bin/env node
'use strict';

const fs = require('fs');
const parser = require('./grammar.js').parse;

function main() {
  const args = require('process').argv;
  if (args.length != 3) {
    console.error("Only 1 argument needed: file-path")
    return 1;
  }
  const filename = args[2];
  fs.readFile(filename, {encoding: 'utf8'}, function(err, data) {
    if (err) {
      console.log("Error reading file", filename);
      console.error(err);
      return 1;
    }
    try {
      let output = parser(data);
      console.log(output);
    }
    catch (e) {
      console.error(e.message);
    }
  });
}

main();

Do chmod +x grammar-check and compile your grammar like: pegjs your-grammar.peg grammar.js and after that you can deploy like: grammar-check filename (where filename is the location of the file to be checked).

Looks good! Thanks for making a more complete example, @jodevsa. I was assuming he knew JavaScript.

But that kind of brings up the idea that people may want to use PEG.js without even knowing JavaScript at all. I think it would be handy to provide a program that can generically read a grammar and input file, and output to a file or standard output.

I think it would be handy to provide a program that can generically read a grammar and input file, and output to a file or standard output.

Shall this issue be reopened, then?

@mikeaustin @waldyrious perhaps instead of making a separate "program" - this can just be mentioned in the readme? With an example of implementing such a thing.

Feel free to use the working example above..!

perhaps instead of making a separate "program" - this can just be mentioned in the readme?

@mikeaustin's comment suggests that a separate program does have a convenience benefit for end users, and I agree with that.

@waldyrious This issue was a question, I'm going to open a new issue for what @mikeaustin suggested, one that should see the feature implemented for 0.11 (if it's a simple addition with no problems), but might be pushed to 1.0 (if it raises some error's, I'll push it back to sort out later). Should be simple to implement though after I'm done with the command line tool rewrite.

Sorry @pepa65 for not replying earlier, but to be honest with you, until @waldyrious posted his comment today, I didn't even know the issue existed 😆

Was this page helpful?
0 / 5 - 0 ratings