n-1). The code has been fixed to make it
[1,b](e.g., return a number from 1 to n).
I was curious about the ability to define new syntax for Factor, and to learn a little about how the lexer works. Inspired by a recent project that I've been working on, I thought it would be interesting to define a simple DSL for calculating dice rolls.
We need a way to describe a dice roll. There are various methods used in Python or Ruby. A common example of a common short-hand description is
4d8 -- specifying how many times (
4) to roll a dice with a number (
8) of sides.
Let's setup a vocabulary and a list of dependencies that will be used to implement this functionality:
USING: fry kernel lexer math math.parser peg.ebnf random sequences strings ; IN: dice
EBNF: parse-roll number = ([0-9])+ => [[ >string string>number ]] dice = "d" number => [[ second '[ _ random ] ]] roll = number dice => [[ first2 '[ 0 _ [ @ + 1 + ] times ] ]] error = .* => [[ "unknown dice" throw ]] total = roll | error ;EBNF
We can see how this works by trying it out:
( scratchpad ) "4d8" parse-roll . [ 0 4 [ 8 random + 1 + ] times ] ( scratchpad ) "4d8" parse-roll call . 15 ( scratchpad ) "foo" parse-roll unknown dice
We can now define a piece of SYNTAX: for dice rolls:
SYNTAX: ROLL: scan parse-roll append ;
And using it:
( scratchpad ) ROLL: 4d8 . 13
This could be extended to support other things such as "base" numbers (e.g.,
4d8+10), negative rolls, ranges, and better handling of parse errors. The code for this is available on my Github.