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
.