This is implemented as a simple post-processing step after partial evaluation
to try compute pre{...} tokens in token sequences. Nothing is done to deal
with intervening free variants.
This was done in response to a query from René T on the gf-dev mailing list.
Becacuse of the new special tokens added to the Symbol type, .gfo and .pgf
files produced with the current version of GF can not always be used with
older versions of GF and the PGF run-time system.
The PGF version number was increased from (2,0) to (2,1). GF can still
read version (2,0) and (1,0), so old PGF files continue to work.
The GFO version was increased from "GF03" to "GF04".
For further separation of pretty printing concerns from conversion concerns,
the Haskell AST and pretty printer has been moved to its own module,
GF.Haskell, also allowing it to be reused in other places where Haskell
code is generated.
If the enumaration of table parameter values fails during the static
traversal phase, try again in the dynamic computation phase, when the values
of bound variables are known.
This is necessary to properly deal with generic table construction in opers,
like the ones found in prelude/Coordination.gf, e.g.
consTable : (P : PType) -> ... = \P ... -> {s1 = table P {...} ; ... }
GF.Compile.Optimize.mkLinReference can fail and cause this error because
the helper function inside it applies msum to a list that might be empty
(if there is a record type that does not contain a field of type Str).
This means that it can return mzero::Err, i.e.
Bad "error (no reason given)"
which can slip through the top level test that only catches Bad "no string".
2 modules: Name clashes caused by Applicative-Monad change in Prelude
2 modules: Ambiguities caused by Foldable/Traversable in Prelude
2 modules: Backwards incompatible changes in time-1.5 for defaultTimeLocale
9 modules: {-# LANGUAGE FlexibleContexts #-} (because GHC checks inferred types
now, in addition to explicitly given type signatures)
Also silenced warnings about tab characters in source files.
+ Some additional simplifying rewrites.
+ Use an intermediate representation for Haskell types, for separation of
concerns and cleaner code.
+ Pretty printer layout tuning
+ Code cleanup.
Introduced an intermediate representation for the generated Haskell expressions.
This allows pretty printing concerns to be separated from conversion concerns,
and makes it easy to apply some simplifying rewrites to the generated
expressions, e.g.
[x] ++ [y] ==> [x,y]
pure f <*> x ==> f <$> x
f <$> pure x ==> pure (f x)
join (pure x) ==> x
By adding the flag -haskell=variants to the command line, GF will now generate
linearization functions in Haskell that support variants. Variants are
represented as lists in Haskell.
Variants inside pre { ... } expressions are still ignored.
TODO: apply some monad laws to generate more compact code (using an
intermediate representation of the generated Haskell code, instead of
pretty printing directly from the GF code).
Move the Haskell representation of the common linearization type {s:T} to the
shared module PGF.Haskell, so that the same overloaded projection function
proj_s can be used for all concrete syntaxes.
Common code has been lifted out from the generated Haskell modules to
an auxiliary module PGF.Haskell, which is currently included in the
regular PGF library, although it is independent of it and probably belongs
in a separate library.
The type Str used by linearization functions is now based on a token
type Tok, which is defined in PGF.Haskell.
PGF.Haskell.Tok is similar to the type GF.Data.Str.Tok, but it has
constructors for the special tokens BIND, SOFT_BIND and CAPIT, and there is
a function
fromStr :: Str -> String
that computes the effects of these special tokens.
+ Instead of including lists of parameter values generated by GF, generate
code to enumerate parameter values (in the same order as GF). This seems
to give a factor of 2-3 code size reduction in the Phrasebook (e.g.
from 84MB to 25MB for Hin, from 338MB to 154MB for Fre).
+ Deduplicate table entries, i.e. convert "table [..,E,..,E,..,E,..]" into
"let x = E in table [..,x,..,x,..,x,..]". This gives even more significant
code size reduction in some cases, e.g. from 569MB to 15MB for
PhrasebookFin.
All phrasebook languages can now be converted to compilable Haskell code,
except PhrasebookPes, which still has the name clash problem.
Many Phrasebook languages can now be converted to compilable Haskell code.
Some languages (Fre, Hin, Snd, Urd) generate too much Haskell code to be
practically useful (e.g. 338MB for Fre). One language (Fin) took too long
to convert to Haskell. One language (Pes) has problems with name clashes in
the generated Haskell code.
STILL TODO:
- variants
- pre { ... }
- reduce code duplication for large tables
- generate qualified names to avoid name clashes
The translation is currently good enough to translate all concrete syntaxes
of the Foods and Letter grammars, and some concrete syntaxes of the Phrasebook
grammar (e.g. PhrasebookEng & PhrasebookSpa works, but there are problems with
e.g. PhrasebookSwe and PhrasebookChi)
This functionality is enabled by running
gf -make -output-format=haskell -haskell=concrete ...
TODO:
- variants
- pre { ... }
- eta expansion of linearization functions
- record subtyping can still cause type errors in the Haskell code
in some cases
- reduce code large tables
It was used only in cases where a lock field needed to be added to a
run-time variable, like e.g. in examples/phrasebook/SentencesTha.gf:
lin
PGreetingMale g = mkText (lin Text g) (lin Text (ss "ครับ")) | g ;
PGreetingFemale g = mkText (lin Text g) (lin Text (ss "ค่ะ")) | g ;
But lock fields are only meaningful during type checking and can safely be
ignored in later passes.
* The following modules are no longer used and have been removed completely:
GF.Compile.Compute.ConcreteLazy
GF.Compile.Compute.ConcreteStrict
GF.Compile.Refresh
* The STM monad has been commented out. It was only used in
GF.Compile.SubExpOpt, where could be replaced with a plain State monad,
since no error handling was needed. One of the functions was hardwired to
the Err monad, but did in fact not use error handling, so it was turned
into a pure function.
* The function errVal has been renamed to fromErr (since it is analogous to
fromMaybe).
* Replaced 'fail' with 'raise' and 'return ()' with 'done' in a few places.
* Some additional old code that was already commented out has been removed.