git @ Cat's Eye Technologies Fountain / master doc / Tests-for-fountain.md
master

Tree @master (Download .tar.gz)

Tests-for-fountain.md @masterview rendered · raw · history · blame

Tests for `fountain`
====================

<!--
Copyright (c) 2023-2024 Chris Pressey, Cat's Eye Technologies
This file is distributed under a BSD license.  See LICENSES directory:
SPDX-License-Identifier: LicenseRef-BSD-2-Clause-X-Fountain
-->

These tests are specific to the reference implementation
of Fountain, `fountain`, and make reference to implementation
details.  They are thus not part of the main test suite.

    -> Functionality "Load Fountain Grammar" is implemented by
    -> shell command "bin/fountain load %(test-body-file)"

    -> Functionality "Preprocess Fountain Grammar" is implemented by
    -> shell command "bin/fountain preprocess %(test-body-file)"

    -> Functionality "Generate using Fountain Grammar with random choices" is implemented by
    -> shell command "bin/fountain --seed 145 generate %(test-body-file) %(test-input-text)"

### Loading

    -> Tests for functionality "Load Fountain Grammar"

Sequence.

    Goal ::= "f" "o" "o";
    ===> Goal ::= (("f" "o" "o"));

Multi-character terminals.

    Goal ::= "foo" "bar";
    ===> Goal ::= (("f" "o" "o" "b" "a" "r"));

Alternation and recursion.

    Goal ::= "(" Goal ")" | "0";
    ===> Goal ::= (("(" Goal ")") | ("0"));

Repetition.

    Goal ::= "(" {"0"} ")";
    ===> Goal ::= (("(" {(("0"))} ")"));

Constraints.

    Goal ::=
         <. a = 0 .> { "a" <. a += 1 .> } <. a = n .>
         <. b = 0 .> { "b" <. b += 1 .> } <. b = n .>
         <. c = 0 .> { "c" <. c += 1 .> } <. c = n .>
         ;
    ===> Goal ::= ((<. a = 0 .> {(("a" <. a += 1 .>))} <. a = n .> <. b = 0 .> {(("b" <. b += 1 .>))} <. b = n .> <. c = 0 .> {(("c" <. c += 1 .>))} <. c = n .>));

Parameters and multiple productions.

    Goal ::= "Hi" Sp<a> "there" Sp<b> "world" "!";
    Sp<n> ::= <. n = 0 .> { " " <. n += 1 .> } <. n > 0 .>;
    ===> Goal ::= (("H" "i" Sp<a> "t" "h" "e" "r" "e" Sp<b> "w" "o" "r" "l" "d" "!"));
    ===> Sp<n> ::= ((<. n = 0 .> {((" " <. n += 1 .>))} <. n > 0 .>));

Comments.

    // This is my grammar.
    // A comment may come before it.
    
    Goal ::= "foo";  // You see
    // how it is
    A ::= "f"  // You see
    "o" // how
    //
    // There are many ways to place comments.
    "//";
    ===> Goal ::= (("f" "o" "o"));
    ===> A ::= (("f" "o" "/" "/"));

Misplaced semicolon is a syntax error.

    Goal ::= <. x = 0 .> <. a = 0 .> { DogMove<x, d> <. a += 1 .> } <. a = 1000 .>;
    DogMove<x, d> ::= <. d > 0 .> "The dog ran away." #10; <. x += 1 .>
                    | <. d < 0 .> "The dog came back." #10; <. x -= 1 .>
                    ;
    ???> unexpected '<'

### Preprocessing

    -> Tests for functionality "Preprocess Fountain Grammar"

Sequence.

    Goal ::= "f" "o" "o";
    ===> Goal ::= ("f" "o" "o");

Alternation and recursion.

    Goal ::= "(" Goal ")" | "0";
    ===> Goal ::= (("(" Goal ")") | ("0"));

Repetition.

    Goal ::= "(" {"0"} ")";
    ===> Goal ::= ("(" {("0")} ")");

    Goal ::=
         <. a = 0 .> { "a" <. a += 1 .> } <. a = n .>
         <. b = 0 .> { "b" <. b += 1 .> } <. b = n .>
         <. c = 0 .> { "c" <. c += 1 .> } <. c = n .>
         ;
    ===> Goal ::= (<. a = 0 .> {("a" <. a += 1 .>)} <. a = n && b = 0 .> {("b" <. b += 1 .>)} <. b = n && c = 0 .> {("c" <. c += 1 .>)} <. c = n .>);

Coalescing constraints.

    Goal ::= <. a = 0 .> <. b = 0 .> { "a" <. a += 1 .> } <. a > b .>;
    ===> Goal ::= (<. a = 0 && b = 0 .> {("a" <. a += 1 .>)} <. a > b .>);

### Nondeterminism

    -> Tests for functionality "Generate using Fountain Grammar with random choices"

The method used for nondeterministic backtracking is not defined at the language
level.

But the reference implementation of Fountain implements nondeterministic backtracking
by ordering the choices pseudo-randomly, based on a PRNG with a particular seed,
which can be chosen by the user, and processing the choices in that order.

    Goal<n>       ::= <. a = 0 .> Item<a, n>;
    Item<a, n>(*) ::= <. a = n .>
                    | "####" <. a += 4 .> <. a <= n .> Item<a, n>
                    | "ooooo" <. a += 5 .> <. a <= n .> Item<a, n>
                    | "xxxxxxx" <. a += 7 .> <. a <= n .> Item<a, n>;
    <=== n=30
    ===> ####oooooxxxxxxxoooooooooo####