Parsing and Checking Inputs#

Fandango can also use its specifications to parse given inputs and to check if they conform to the specification - both

  • syntactically (according to the grammar); and

  • semantically (according to the constraints).

The parse command#

To parse an existing input, Fandango provides a parse command. Its arguments are any files to be parsed; if no files are given, parse reads from standard input. As with the fuzz command, providing a specification (with -f FILE.fan) is mandatory.

Let us use parse to check some dates against the ISO 8601 format we have written a Fandango spec for. The command echo -n outputs the string given as argument (-n suppresses the newline it would normally produce); the pipe symbol | feeds this as input into Fandango:

$ echo -n '2025-01-27' | fandango parse -f iso8601.fan

If we do this, nothing happens. That is actually a good sign: it means that Fandango has successfully parsed the input.

If we pass an invalid input, however, Fandango will report this. This holds for syntactically invalid inputs:

$ echo -n '01/27/2025' | fandango parse -f iso8601.fan
FandangoParseError: '<stdin>', line 1, column 4: mismatched input '2'
FandangoParseError: 1 error(s) during parsing

And also for semantically invalid inputs:

$ echo -n '2025-02-29' | fandango parse -f iso8601.fan
FandangoError: '<stdin>': constraint is_valid_iso8601datetime(str(<iso8601datetime>)) not satisfied
FandangoParseError: 1 error(s) during parsing

In both cases, the return code will be non-zero:

$ echo $?
1

Validating Parse Results#

By default, the parse command produces no output. However, to inspect the parse results, you can output the parsed string again. The -o FILE option writes the parsed string to FILE, with - being the standard output.

$ echo -n '2025-01-27' | fandango parse -f iso8601.fan -o -
2025-10-27

We see that input and output are identical (as should always be with parsing and unparsing).

Tip

As it comes to producing and storing outputs, the parse command has the same options as the fuzz command.

Since parsing and unparsing should always be symmetrical to each other, Fandango provides a --validate option to run this check automatically:

$ echo -n '2025-01-27' | fandango parse -f iso8601.fan --validate

Again, if nothing happens, then the (internal) check was successful.

The --validate option can also be passed to the fuzz command; here, it ensures that the produced string can be parsed by the same grammar (again, as should be).

Tip

If you find that --validate fails, please report this as a Fandango bug.

Alternate Output Formats#

In order to debug grammars, Fandango provides a number of alternate formats in which to output the parsed tree, controlled by the --format flag.

String#

The option --format=string outputs the parsed tree as a string. This is the default.

$ echo -n '2025-01-27' | fandango parse -f iso8601.fan -o - --format=string
2025-10-27

Tree#

The option --format=string outputs the parsed tree as a Python Tree() expression. This is useful for evaluating and visualizing the tree.

$ echo -n '2025-01-27' | fandango parse -f iso8601.fan -o - --format=tree
Tree('<start>', Tree('<iso8601datetime>',
  Tree('<iso8601date>', Tree('<iso8601calendardate>',
    Tree('<iso8601year>',
      Tree(''),
      Tree('<digit>', Tree('<_digit>', Tree('2'))),
      Tree('<digit>', Tree('<_digit>', Tree('0'))),
      Tree('<digit>', Tree('<_digit>', Tree('2'))),
      Tree('<digit>', Tree('<_digit>', Tree('5')))
    ),
    Tree('-'),
    Tree('<iso8601month>', Tree('10')),
    Tree('-'),
    Tree('<iso8601day>', Tree('27'))
  )),
  Tree('')
))

Here comes this tree, visualized:

_images/8a2abf9346eca73e3eecb8bb4a4ffa0041af1d7979c688828e21ae8804e7b3e9.png

Grammar#

The option --format=grammar outputs the parsed tree as a (highly specialized) grammar, in which children are indented under their respective parents. This is useful for debugging, but also for creating a grammar from a sample file and then generalizing it.

$ echo -n '2025-01-27' | fandango parse -f iso8601.fan -o - --format=grammar
<start> ::= <iso8601datetime>
  <iso8601datetime> ::= <iso8601date> ''  # Position 0x0000 (0); '2025-10-27'
    <iso8601date> ::= <iso8601calendardate>
      <iso8601calendardate> ::= <iso8601year> '-' <iso8601month> '-' <iso8601day>  # Position 0x0000 (0); '2025-10-27'
        <iso8601year> ::= '' <digit> <digit> <digit> <digit>  # Position 0x0002 (2); '2025'
          <digit> ::= <_digit>
            <_digit> ::= '2'  # Position 0x0002 (2)
          <digit> ::= <_digit>
            <_digit> ::= '0'  # Position 0x0003 (3)
          <digit> ::= <_digit>
            <_digit> ::= '2'  # Position 0x0004 (4)
          <digit> ::= <_digit>
            <_digit> ::= '5'  # Position 0x0005 (5)
        <iso8601month> ::= '10'  # Position 0x0006 (6)
        <iso8601day> ::= '27'  # Position 0x0008 (8)

Bits#

The option --format=bits outputs the parsed tree as a bit sequence.

$ echo -n '2025-01-27' | fandango parse -f iso8601.fan -o - --format=bits
00110010001100000011001000110101001011010011000100110000001011010011001000110111

This is useful for debugging binary formats that contain bits.