The previous tests for `build . fold` fusion for `Optional` values would
succeed even without fusion. This change updates the tests to only
succeed if fusion is occurring.
This change updates the test to test Dhall source code so that we're
exercising the system from end to end. This also makes it easier to
author tests since expressions can be written as Dhall source code
instead of an abstract syntax tree.
You can now escape an field or variable name using backticks, like this:
```haskell
let `let` = 2
in let `in` = True
in { `True` = `let`
, `Type` = λ(`Kind` : Bool) → `Kind` && `in`
}
```
The main purpose of this is to support arbitrary record field names when
marshalling Dhall into other file formats (such as JSON). For example,
this Dhall configuration file:
```haskell
{ swagger = "2.0"
, parameters = {
foo = {
name = "foo"
, `in` = "path"
, type = "string"
}
}
...
}
```
... can be used to generate this JSON file:
```json
swagger: "2.0"
parameters:
foo:
name: "foo"
in: "path"
type: "string"
```
- Defines a new primitive `OptionalFold`
- Implements normalization:
- inlining of Optional/build if constants are used as args
- fusion of fold/build and build/fold
Part of #31, requested by @scott-fleischman
You can now use `-` in identifier names for all but the first character.
That means that this is now legal code:
```
{ resolver = "lts-8.1", extra-deps = [ "pipes-4.3.1" ] }
```
This primarily serves people who want to use "kebab-case" for their
identifier names
Normally languages do not support dash in identifier names due to
ambiguity with the subtraction operator. For example, an identifier
like `extra-deps` could be interpreted as `extra` minus `deps`.
However, Dhall does not support subtraction and only supports unary
negation so there is no ambiguity.
The original reason for permitting `(` and `)` in paths was due to
Dhall's origins as a fork of Morte/Annah. Morte had no built-in
operators and often imported them via the Prelude, like this:
http://sigil.place/prelude/annah/1.0/List/(++)
Morte also adopted the Haskell convention of using parentheses for
unapplied operators, so paths required parentheses.
However, this came at a price, which was really confusing parsing errors
if the user did something like this:
λ(x : ./type) → x
This is because the `./type)` would be parsed as a single path token and
then you'd get a downstream error due to a missing parenthesis.
Dhall, on the other hand, does not benefit much from parentheses in
paths. Dhall already has several built-in operators and doesn't support
operator names for bound variables. Therefore, this change eliminates
support for parentheses in paths to improve error messages and reduce
the need for explicit whitespace after paths.
The expected use of this operator is to update a record. For example,
you can provide a record with default values, like this:
```bash
$ cat defaults
{ availabilityZone = [] : Optional Text
, placementGroup = [] : Optional Text
}
```
... and then update or extend that record with new values using `(//)`:
```bash
$ dhall
./defaults //
{ ami = "ami-12345" -- Example of adding a new field
, availabilityZone = ["eu-west-1"] : Optional Text -- Overriding field
-- Use the default for placementGroup
}
<Ctrl-D>
{ ami : Text, availabilityZone : Optional Text, placementGroup
: Optional Text }
{ ami = "ami-12345", availabilityZone = ["eu-west-1"] : Optional Text, placementGroup = [] : Optional Text } ```
```
You can also override a field with a new type as well:
```bash
$ dhall
{ foo = 1 } // { foo = "ABC" }
<Ctrl-D>
{ foo : Text }
{ foo = "ABC" }
```
* Add support for importing paths as raw `Text`
Part of #23
You can now add ` as Text` to the end of any path and the raw contents at that
path will be imported as a raw `Text` literal. For example:
```
$ dhall <<< "http://example.com as Text"
Text
"<!doctype html>\n<html>\n<head>\n <title>Example Domain</title>\n\n <meta
charset=\"utf-8\" />\n <meta http-equiv=\"Content-type\" content=\"text/html
; charset=utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width,
initial-scale=1\" />\n <style type=\"text/css\">\n body {\n backgro
und-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-famil
y: \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n
}\n div {\n width: 600px;\n margin: 5em auto;\n paddi
ng: 50px;\n background-color: #fff;\n border-radius: 1em;\n }\n
a:link, a:visited {\n color: #38488f;\n text-decoration: none;
\n }\n @media (max-width: 700px) {\n body {\n background
-color: #fff;\n }\n div {\n width: auto;\n m
argin: 0 auto;\n border-radius: 0;\n padding: 1em;\n
}\n }\n </style> \n</head>\n\n<body>\n<div>\n <h1>Example Domain</
h1>\n <p>This domain is established to be used for illustrative examples in d
ocuments. You may use this\n domain in examples without prior coordination or
asking for permission.</p>\n <p><a href=\"http://www.iana.org/domains/exampl
e\">More information...</a></p>\n</div>\n</body>\n</html>\n"
```
* Remove unnecessary space
Consider the following Haskell program:
```
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
import Dhall hiding (auto)
import qualified Data.Text.Lazy
interpretOptions :: InterpretOptions
interpretOptions = defaultInterpretOptions
{ fieldModifier = Data.Text.Lazy.dropWhile (== '_') }
data GitRepo = GitRepo
{ _host :: Text
, _repo :: Text
} deriving (Generic, Interpret, Show)
data BoxConfig = BoxConfig
{ _userName :: Text
, _dotfilesRepo :: Vector GitRepo
} deriving (Generic, Interpret, Show)
main :: IO ()
main = do
x <- Dhall.input (autoWith interpretOptions) "./config"
print (x :: BoxConfig)
```
Before this change the above program attempts to decode a value of type:
```
{ userName : Text, dotfilesRepo : List { _host : Text, _repo : Text } }
```
... when it should be decoding a value of type:
```
{ userName : Text, dotfilesRepo : List { host : Text, repo : Text } }
```
This change ensures that `InterpretOptions` correctly propagate to elements of
`List` or `Optional` values
Consider the following program which marshals a Dhall record into Haskell:
```haskell
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
import Dhall hiding (auto)
import qualified Data.Text.Lazy
interpretOptions :: InterpretOptions
interpretOptions = defaultInterpretOptions
{ fieldModifier = Data.Text.Lazy.dropWhile (== '_') }
data GitRepo = GitRepo
{ _host :: Text
, _repo :: Text
} deriving (Generic, Interpret, Show)
data BoxConfig = BoxConfig
{ _userName :: Text
, _dotfilesRepo :: GitRepo
} deriving (Generic, Interpret, Show)
main :: IO ()
main = do
x <- Dhall.input (autoWith interpretOptions) "./config"
print (x :: BoxConfig)
```
The above program is a common pattern when mixing Dhall records with lenses
(which typically prefix the original fields with "_").
Before this change, the above program expects a record of the following type:
```
{ userName : Text, dotfilesRepo : { _host : Text, _repo : Text } }
```
Note that the sub-record ignores the `InterpretOptions` and incorrectly includes
the underscore in the expected field names.
This change fixes the derived `Interpret` instance for records to correctly
thread `InterpretOptions` to nested records.
This required a change to the `auto` method of the `Interpret` class to
accept `InterpretOptions`, otherwise there is no way to supply the
`InterpretOptions` record to sub-records. This modified `auto` method is now
called `autoWith`. I still include an `auto` function that uses
`defaultInterpretOptions` consistent with the old behavior.
Now this code:
\(x : Natural) -> x : Natural
... will be treated as equivalent to this code:
\(x : Natural) -> (x : Natural)
This makes the behavior of type annotations consistent with Haskell and also
consistent with parsing annotated list literals, where this code:
\(x : Natural) -> [x] : List Natural
... is equivalent to this code:
\(x : Natural) -> ([x] : List Natural)
This also inadvertently fixes a bug in `if` parsing, which previously would
reject this expression:
if True then True else if True then True else True
... and now the expression parses correctly
Older pre-release versions of `dhall` used to
translate Haskell records to sum-types even if
they only had one alternative. Newer versions
do not, so the example in the `README.md` is
out-of-date and needs to be fixed.
This change updates parsing errors to adopt the same format as a type error,
including a helpful summary of the error (i.e. "Error: Invalid input") before
the details of the error
The `exprD` parser for function application was unnecessarily backtracking when
parsing the first value in the chain. Removing the `try` for the first element
greatly improves parsing error localization.
For example, before this change the following Dhall expression:
```
{ foo = 1, bar = '2' }
```
... would give the following parse error:
```
(stdin):1:1: error: expected: "[",
"\8704", "\955", "\\", "forall",
"if", "let", "merge"
{ foo = 1, bar = '2' }
^
```
After this change, you now get a much better error:
```
$ dist/build/Dhall/dhall
{ foo = 1, bar = '2' }
(stdin):1:18: error: expected: "''",
"(", "+", "-", "[", "\8704",
"\955", "\\", "forall", "if",
"let", "merge", built-in value,
double, import, integer, label,
list literal, natural,
record literal, record type,
string, union literal,
union type
{ foo = 1, bar = '2' }
^
```
This adds a new `deriveAuto` utility that you can customize with
`InterpretOptions` in order to transform the expected field or constructor
labels that Dhall expects
The most common use of this is to support data types that prefix field names
with underscores for lens support
`trifecta` already depends on `lens`, so using `microlens` does not
actually trim down the dependency tree. Quite the opposite: it adds two
unnecessary dependencies.