Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

help creating peg.js parser

I am wanting to create the parser, and expression syntax in peg.js that would allow me to do these things

basically I want to pass in a mask and have a number output.

the mask has these abilities.

1) generate a random number between 0-9 (character n for expression? )
2) generate a random number between x and y( (x,y) for expression?)
3) literal numbers are valid (hopefully nothing needed for expession?)
4) repeat previous expression x times({x} for expression?)
5) repeat previous expression between x and y times({x,y} for expression?)

so an example expression could be

027n(5,9){4}n12{2,8}(2,4)

the proposed expression syntax above is only an example, it can change.

can anyone provide help in creating the parser for this in peg.js?

like image 708
Hailwood Avatar asked Mar 09 '11 04:03

Hailwood


1 Answers

The idea is to make it generate a JavaScript function, which when executed, will return a random string according to the mask.

A literal number is any character between 0 to 9, so make it generate a function that returns itself.

literal_number
 = num:[0-9]
 { return function() {
     return num;
 }; }

Then n is for a random number. Again, this generates a function to return a random number. I added + '' to convert it to a string before returning.

random_number
 = "n"
 { return function() {
     return Math.floor(Math.random() * 10) + '';
 }; }

In the (a,b) syntax, a and b are numbers, so we need to make it parse and return a number. Using the declaration from the calculator example:

number
 = digits:[0-9]+ { return parseInt(digits.join(""), 10); }

Then we can move on to create a rule for (a,b) syntax.

random_number_between
 = "(" a:number "," b:number ")"
 { return function() {
     return a + Math.floor(Math.random() * (b - a + 1)) + ''
 }; }

So, these 3 things (literal_number, random_number, random_number_between) combine into a single expression that generates a valid function.

single_expression
 = random_number
 / random_number_between
 / literal_number

A single expression, followed by {n} or {a,b} forms a repeated expression. A single expression is also a repeated expression, repeated one time.

The idea of a repeated expression is, given a function, return a function that calls the input function N times, collect the result, and return it.

repeated_expression
 = ex:single_expression "{" n:number "}" {
       return function() {
           var result = '';
           for (var i = 0; i < n; i ++) {
               result += ex();
           }
           return result;
       };
   }
 / ex:single_expression "{" a:number "," b:number "}" {
       return function() {
           var result = '';
           var n = a + Math.floor(Math.random() * (b - a + 1))
           for (var i = 0; i < n; i ++) {
               result += ex();
           }
           return result;
       };
   }
 / ex:single_expression

Finally, repeated expressions can be put next to each other to concatenate.

expression
 = list:repeated_expression* {
       return function() {
           var result = '';
           for (var i = 0; i < list.length; i ++) {
               result += list[i]();
           }
           return result;
       };
   }

Finally, you need a starting point, which defines a mask. This final bit scans the expression which returns a generates a function, and call it. Put the following at the top, and when you try it online, it will generate a string of numbers according to your mask.

mask
 = ex:expression
 { return ex() }

Example run: 027n(5,9){4}n12{2,8}(2,4) gives 0271568891222224.

like image 120
Thai Avatar answered Nov 12 '22 02:11

Thai