Skip to content

Commit

Permalink
dhall-to-nix: Encode unions slightly differently for better symbol
Browse files Browse the repository at this point in the history
Symbols in nix can only consist of a very restricted amount of
characters, whereas in dhall they can be basically anything.

When you want to get a value of a union, before it was generated into

```
{ Foo, Bar }: Foo
```

where `Foo` cannot be a complex symbol like `{ Foo/Baz, Bar }:
Foo/Baz`, because nix does not allow it in anonymous record arguments.

So now we generate it as

```
u: u."Foo/Baz"
```

which should always work and is equal (though it loses the information
of what other fields are there in the nix code).

Before I faultily encoded some of these symbols with a Z-encoding, but
that was wrong, so it was undone.
  • Loading branch information
Profpatsch committed Jun 20, 2022
1 parent 09131de commit 2f24a71
Showing 1 changed file with 28 additions and 18 deletions.
46 changes: 28 additions & 18 deletions dhall-nix/src/Dhall/Nix.hs
Original file line number Diff line number Diff line change
Expand Up @@ -336,13 +336,9 @@ dhallToNix e =
loop (Pi _ _ _ _) = return untranslatable
loop (App None _) =
return Nix.mkNull
loop (App (Field (Union kts) (Dhall.Core.fieldSelectionLabel -> k)) v) = do
loop (App (Field (Union _kts) (Dhall.Core.fieldSelectionLabel -> k)) v) = do
v' <- loop v
let e0 = do
k' <- (Dhall.Map.keys kts)
return (k', Nothing)
let e2 = Nix.mkSym k @@ v'
return (Nix.mkParamset e0 False ==> e2)
return (unionChoice k (Just v'))
loop (App a b) = do
a' <- loop a
b' <- loop b
Expand Down Expand Up @@ -607,7 +603,7 @@ dhallToNix e =
-- see https://github.com/dhall-lang/dhall-haskell/issues/2414
nixAttrs pairs =
Fix $ NSet NNonRecursive $
(\(key, val) -> NamedVar (DynamicKey (Plain (DoubleQuoted [Plain key])) :| []) val Nix.nullPos)
(\(key, val) -> NamedVar ((mkDoubleQuoted key) :| []) val Nix.nullPos)
<$> pairs
loop (Union _) = return untranslatable
loop (Combine _ _ a b) = do
Expand Down Expand Up @@ -696,17 +692,8 @@ dhallToNix e =
-- (here "x").
--
-- This translates `< Foo : T >.Foo` to `x: { Foo }: Foo x`
Just (Just _) -> do
let e0 = do
k' <- map zEncodeString (Dhall.Map.keys kts)
return (k', Nothing)
return ("x" ==> Nix.mkParamset e0 False ==> (Nix.mkSym (zEncodeString k) @@ "x"))

_ -> do
let e0 = do
k' <- map zEncodeString (Dhall.Map.keys kts)
return (k', Nothing)
return (Nix.mkParamset e0 False ==> Nix.mkSym (zEncodeString k))
Just (Just _) -> return ("x" ==> (unionChoice k (Just "x")))
_ -> return (unionChoice k Nothing)
loop (Field a (Dhall.Core.fieldSelectionLabel -> b)) = do
a' <- loop a
return (a' @. b)
Expand Down Expand Up @@ -742,6 +729,29 @@ dhallToNix e =
loop (Note _ b) = loop b
loop (Embed x) = absurd x

-- | Previously we turned @<Foo | Bar>.Foo@ into @{ Foo, Bar }: Foo@,
-- but this would not work with <Frob/Baz>.Frob/Baz (cause the slash is not a valid symbol char in nix)
-- so we generate @union: union."Frob/Baz"@ instead.
--
-- If passArgument is @Just@, pass the argument to the union selector.
unionChoice :: Text -> Maybe NExpr -> NExpr
unionChoice chosenKey passArgument =
let selector = Fix (Nix.NSelect (Nix.mkSym "u") (mkDoubleQuoted chosenKey :| []) Nothing)
in Nix.Param "u" ==>
case passArgument of
Nothing -> selector
Just arg -> selector @@ arg


-- | Double-quote a field name (record or union). This makes sure it’s recognized as a valid name by nix, e.g. in
--
-- @{ "foo/bar" = 42; }."foo/bar" }@
--
-- where
--
-- @{ foo/bar = 42; }.foo/bar@ is not syntactically valid nix.
mkDoubleQuoted :: Text -> NKeyName r
mkDoubleQuoted key = DynamicKey (Plain (DoubleQuoted [Plain key]))


-- | Nix does not support symbols like @foo/bar@, but they are allowed in dhall.
Expand Down

0 comments on commit 2f24a71

Please sign in to comment.