Tree @master (Download .tar.gz)
Tests-for-fountain.md @master — view markup · raw · history · blame
Tests for 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.
This shows internal structure after converting loops to recursion.
Goal ::= "(" {"0"} ")";
===> Goal ::= ("(" WASALOOPHERE0 ")");
===> WASALOOPHERE0 ::= ((<. ~generating && ?("0") || generating && ~T .> ("0") WASALOOPHERE0) | (<. ~generating && ~?("0") || generating && T .>));
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 .> WASALOOPHERE0<a> <. a = n && b = 0 .> WASALOOPHERE1<b> <. b = n && c = 0 .> WASALOOPHERE2<c> <. c = n .>);
===> WASALOOPHERE2<c> ::= ((<. ~generating && ?("c" <. c += 1 .>) || generating && ~T .> ("c" <. c += 1 .>) WASALOOPHERE2<c>) | (<. ~generating && ~?("c" <. c += 1 .>) || generating && T .>));
===> WASALOOPHERE1<b> ::= ((<. ~generating && ?("b" <. b += 1 .>) || generating && ~T .> ("b" <. b += 1 .>) WASALOOPHERE1<b>) | (<. ~generating && ~?("b" <. b += 1 .>) || generating && T .>));
===> WASALOOPHERE0<a> ::= ((<. ~generating && ?("a" <. a += 1 .>) || generating && ~T .> ("a" <. a += 1 .>) WASALOOPHERE0<a>) | (<. ~generating && ~?("a" <. a += 1 .>) || generating && T .>));
Coalescing constraints.
This shows internal structure after converting loops to recursion.
Goal ::= <. a = 0 .> <. b = 0 .> { "a" <. a += 1 .> } <. a > b .>;
===> Goal ::= (<. a = 0 && b = 0 .> WASALOOPHERE0<a> <. a > b .>);
===> WASALOOPHERE0<a> ::= ((<. ~generating && ?("a" <. a += 1 .>) || generating && ~T .> ("a" <. a += 1 .>) WASALOOPHERE0<a>) | (<. ~generating && ~?("a" <. a += 1 .>) || generating && T .>));
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.
FIXME: since this test relies on a particular PRNG implementation (whatever is
bundled with ghc 9.2.8) it is not expected to pass on other implementations.
Falderal should handle this gracefully, but doesn't. So this is temporarily disabled.
> 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####
Fuel Consumption During Parsing
-> Functionality "Parse using Fountain Grammar with fuel constraints" is implemented by
-> shell command "echo -n '((*))' | bin/fountain --dump-state %(test-input-text) parse %(test-body-file) -- n=2"
-> Tests for functionality "Parse using Fountain Grammar with fuel constraints"
Fuel factor 0 won't ever be enough to sustain anything.
Goal<n> ::= <. a = 0 .> Item<a, n>;
Item<a, n>(*) ::= <. a = n .> "*" | <. a < n .> "(" <. a += 1 .> Item<a, n> ")";
<=== --initial-fuel 0 --fuel-factor 0
???> Out of fuel
But if you have enough fuel initially, it doesn't have to be sustainable.
Goal<n> ::= <. a = 0 .> Item<a, n>;
Item<a, n>(*) ::= <. a = n .> "*" | <. a < n .> "(" <. a += 1 .> Item<a, n> ")";
<=== --initial-fuel 4 --fuel-factor 0
===> Right (Parsing {input = "", store = fromList [(Var "a",2),(Var "n",2)], fuel = FuelState {currentFuel = 1, fuelFactor = Just 0}})
Fuel factor 1 is sufficient for this parsing problem.
Goal<n> ::= <. a = 0 .> Item<a, n>;
Item<a, n>(*) ::= <. a = n .> "*" | <. a < n .> "(" <. a += 1 .> Item<a, n> ")";
<=== --initial-fuel 1 --fuel-factor 1
===> Right (Parsing {input = "", store = fromList [(Var "a",2),(Var "n",2)], fuel = FuelState {currentFuel = 3, fuelFactor = Just 1}})
If you can do something with fuel factor 1, you can do it with fuel factor 2 as well.
Goal<n> ::= <. a = 0 .> Item<a, n>;
Item<a, n>(*) ::= <. a = n .> "*" | <. a < n .> "(" <. a += 1 .> Item<a, n> ")";
<=== --initial-fuel 1 --fuel-factor 2
===> Right (Parsing {input = "", store = fromList [(Var "a",2),(Var "n",2)], fuel = FuelState {currentFuel = 8, fuelFactor = Just 2}})
Fuel Consumption During Generation
-> Functionality "Generate using Fountain Grammar with fuel constraints, n=3" is implemented by
-> shell command "bin/fountain %(test-input-text) generate %(test-body-file) n=3"
-> Tests for functionality "Generate using Fountain Grammar with fuel constraints, n=3"
Given enough fuel, it does generate.
Goal<n> ::= <. a = 0 .> Item<a, n>;
Item<a, n>(*) ::= <. a = n .> "*" | <. a < n .> "(" <. a += 1 .> Item<a, n> ")";
<=== --fuel-factor 1 --initial-fuel 4
===> (((*)))
It does need some initial fuel.
Goal<n> ::= <. a = 0 .> Item<a, n>;
Item<a, n>(*) ::= <. a = n .> "*" | <. a < n .> "(" <. a += 1 .> Item<a, n> ")";
<=== --fuel-factor 1 --initial-fuel 0
???> Failure
-> Functionality "Generate using Fountain Grammar with fuel constraints, n=10" is implemented by
-> shell command "bin/fountain %(test-input-text) generate %(test-body-file) n=10"
-> Tests for functionality "Generate using Fountain Grammar with fuel constraints, n=10"
Fuel gain, and usage, is proportional to the given n in this case.
Goal<n> ::= <. a = 0 .> Item<a, n>;
Item<a, n>(*) ::= <. a = n .> "*" | <. a < n .> "(" <. a += 1 .> Item<a, n> ")";
<=== --fuel-factor 1 --initial-fuel 4
===> ((((((((((*))))))))))
If fuel factor is 0 it is reliant on the initial fuel.
Goal<n> ::= <. a = 0 .> Item<a, n>;
Item<a, n>(*) ::= <. a = n .> "*" | <. a < n .> "(" <. a += 1 .> Item<a, n> ")";
<=== --fuel-factor 0 --initial-fuel 4
???> Failure
Goal<n> ::= <. a = 0 .> Item<a, n>;
Item<a, n>(*) ::= <. a = n .> "*" | <. a < n .> "(" <. a += 1 .> Item<a, n> ")";
<=== --fuel-factor 0 --initial-fuel 15
===> ((((((((((*))))))))))