Skip to content

Commit 56671fe

Browse files
Add with support for Optional values (#2386)
… as standardized in dhall-lang/dhall-lang#1254 Co-authored-by: David Richey <[email protected]>
1 parent a13c656 commit 56671fe

File tree

11 files changed

+261
-68
lines changed

11 files changed

+261
-68
lines changed

dhall-nix/src/Dhall/Nix.hs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
{-# LANGUAGE OverloadedStrings #-}
44
{-# LANGUAGE QuasiQuotes #-}
55
{-# LANGUAGE RecordWildCards #-}
6+
{-# LANGUAGE TemplateHaskell #-}
67
{-# LANGUAGE TypeFamilies #-}
78
{-# LANGUAGE ViewPatterns #-}
89

@@ -93,24 +94,30 @@ module Dhall.Nix (
9394
) where
9495

9596
import Control.Exception (Exception)
96-
import Data.Fix (Fix (..))
97-
import Data.Foldable (toList)
98-
import Data.Text (Text)
99-
import Data.Traversable (for)
100-
import Data.Typeable (Typeable)
101-
import Data.Void (Void, absurd)
97+
import Data.Fix (Fix (..))
98+
import Data.Foldable (toList)
99+
import Data.List.NonEmpty (NonEmpty(..))
100+
import Data.Text (Text)
101+
import Data.Traversable (for)
102+
import Data.Typeable (Typeable)
103+
import Data.Void (Void, absurd)
104+
import Lens.Family (toListOf)
105+
import Nix.Atoms (NAtom (..))
106+
import Nix (($//), ($==))
107+
102108
import Dhall.Core
103109
( Binding (..)
104110
, Chunks (..)
105111
, DhallDouble (..)
106112
, Expr (..)
113+
, FieldSelection (..)
107114
, FunctionBinding (..)
108115
, MultiLet (..)
109116
, PreferAnnotation (..)
110117
, Var (..)
118+
, WithComponent (..)
111119
)
112-
import Lens.Family (toListOf)
113-
import Nix.Atoms (NAtom (..))
120+
114121
import Nix.Expr
115122
( Antiquoted (..)
116123
, Binding (..)
@@ -670,8 +677,24 @@ dhallToNix e =
670677
return untranslatable
671678
loop (Equivalent _ _ _) =
672679
return untranslatable
673-
loop a@With{} =
674-
loop (Dhall.Core.desugarWith a)
680+
loop (With a (WithLabel k :| []) b) = do
681+
a' <- loop a
682+
b' <- loop b
683+
684+
return (a' $// Nix.attrsE [(k, b')])
685+
loop (With a (WithLabel k :| k' : ks) b) = do
686+
a' <- loop a
687+
b' <- loop (With (Field "_" (FieldSelection Nothing k Nothing)) (k' :| ks) (Dhall.Core.shift 1 "_" b))
688+
689+
return (Nix.letE "_" a' ("_" $// Nix.attrsE [(k, b')]))
690+
loop (With a (WithQuestion :| []) b) = do
691+
a' <- loop a
692+
b' <- loop b
693+
return (Nix.mkIf (a' $== Nix.mkNull) Nix.mkNull b')
694+
loop (With a (WithQuestion :| k : ks) b) = do
695+
a' <- loop a
696+
b' <- loop (With "_" (k :| ks) (Dhall.Core.shift 1 "_" b))
697+
return (Nix.letE "_" a' (Nix.mkIf (a' $== Nix.mkNull) Nix.mkNull b'))
675698
loop (ImportAlt a _) = loop a
676699
loop (Note _ b) = loop b
677700
loop (Embed x) = absurd x

dhall/src/Dhall/Binary.hs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import Dhall.Syntax
4747
, Scheme (..)
4848
, URL (..)
4949
, Var (..)
50+
, WithComponent (..)
5051
)
5152

5253
import Data.Foldable (toList)
@@ -559,7 +560,18 @@ decodeExpressionInternal decodeEmbed = go
559560

560561
n <- Decoding.decodeListLen
561562

562-
ks₀ <- replicateDecoder n Decoding.decodeString
563+
let decodeWithComponent = do
564+
tokenType₂ <- Decoding.peekTokenType
565+
case tokenType₂ of
566+
TypeString -> do
567+
fmap WithLabel Decoding.decodeString
568+
_ -> do
569+
m <- Decoding.decodeInt
570+
571+
case m of
572+
0 -> return WithQuestion
573+
_ -> die ("Unexpected integer encoding a with expression: " <> show n)
574+
ks₀ <- replicateDecoder n decodeWithComponent
563575

564576
ks₁ <- case NonEmpty.nonEmpty ks₀ of
565577
Nothing ->
@@ -1017,8 +1029,11 @@ encodeExpressionInternal encodeEmbed = go
10171029
encodeList4
10181030
(Encoding.encodeInt 29)
10191031
(go l)
1020-
(encodeList (fmap Encoding.encodeString ks))
1032+
(encodeList (fmap encodeWithComponent ks))
10211033
(go r)
1034+
where
1035+
encodeWithComponent WithQuestion = Encoding.encodeInt 0
1036+
encodeWithComponent (WithLabel k ) = Encoding.encodeString k
10221037

10231038
DateLiteral day ->
10241039
encodeList4

dhall/src/Dhall/Core.hs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ module Dhall.Core (
3131
, makeFunctionBinding
3232
, FieldSelection (..)
3333
, makeFieldSelection
34+
, WithComponent (..)
3435
, Expr(..)
3536

3637
-- * Normalization
@@ -76,7 +77,6 @@ module Dhall.Core (
7677
, Eval.textShow
7778
, censorExpression
7879
, censorText
79-
, Syntax.desugarWith
8080
) where
8181

8282
import Control.Exception (Exception)
@@ -92,8 +92,7 @@ import Prettyprinter (Pretty)
9292

9393
import qualified Control.Exception
9494
import qualified Data.Text
95-
import qualified Dhall.Eval as Eval
96-
import qualified Dhall.Syntax as Syntax
95+
import qualified Dhall.Eval as Eval
9796

9897
-- | Pretty-print a value
9998
pretty :: Pretty a => a -> Text

dhall/src/Dhall/Diff.hs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import Dhall.Syntax
3535
, FunctionBinding (..)
3636
, RecordField (..)
3737
, Var (..)
38+
, WithComponent (..)
3839
)
3940
import Numeric.Natural (Natural)
4041
import Prettyprinter (Doc, Pretty)
@@ -1067,12 +1068,15 @@ diffWithExpression (With eL ksL vL) (With eR ksR vR) =
10671068
( format " " (diffImportExpression eL eR)
10681069
<> "with "
10691070
<> align
1070-
( format " " (diffPath ksL ksR)
1071+
( format " " (diffPath (fmap toText ksL) (fmap toText ksR))
10711072
<> "= "
10721073
<> diffOperatorExpression vL vR
10731074
)
10741075
)
10751076
where
1077+
toText WithQuestion = "?"
1078+
toText (WithLabel k ) = k
1079+
10761080
diffPath (kL :| []) (kR :| []) =
10771081
diffLabel kL kR
10781082
diffPath (kL₀ :| kL₁ : ksL') (kR₀ :| kR₁ : ksR') =

dhall/src/Dhall/Eval.hs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ import Dhall.Syntax
6969
, PreferAnnotation (..)
7070
, RecordField (..)
7171
, Var (..)
72+
, WithComponent (..)
7273
)
7374

7475
import qualified Data.Char
@@ -234,7 +235,7 @@ data Val a
234235
| VProject !(Val a) !(Either (Set Text) (Val a))
235236
| VAssert !(Val a)
236237
| VEquivalent !(Val a) !(Val a)
237-
| VWith !(Val a) (NonEmpty Text) !(Val a)
238+
| VWith !(Val a) (NonEmpty WithComponent) !(Val a)
238239
| VEmbed a
239240

240241
-- | For use with "Text.Show.Functions".
@@ -417,16 +418,19 @@ vProjectByFields env t ks =
417418
t' ->
418419
VProject t' (Left ks)
419420

420-
vWith :: Val a -> NonEmpty Text -> Val a -> Val a
421-
vWith (VRecordLit kvs) (k :| [] ) v = VRecordLit (Map.insert k v kvs)
422-
vWith (VRecordLit kvs) (k₀ :| k₁ : ks) v = VRecordLit (Map.insert k₀ e₂ kvs)
421+
vWith :: Val a -> NonEmpty WithComponent -> Val a -> Val a
422+
vWith (VRecordLit kvs) (WithLabel k :| [] ) v = VRecordLit (Map.insert k v kvs)
423+
vWith (VRecordLit kvs) (WithLabel k₀ :| k₁ : ks) v = VRecordLit (Map.insert k₀ e₂ kvs)
423424
where
424425
e₁ =
425426
case Map.lookup k₀ kvs of
426427
Nothing -> VRecordLit mempty
427428
Just e₁' -> e₁'
428429

429430
e₂ = vWith e₁ (k₁ :| ks) v
431+
vWith (VNone _T) (WithQuestion :| _ ) _ = VNone _T
432+
vWith (VSome _) (WithQuestion :| [] ) v = VSome v
433+
vWith (VSome t) (WithQuestion :| k₁ : ks) v = VSome (vWith t (k₁ :| ks) v)
430434
vWith e₀ ks v₀ = VWith e₀ ks v₀
431435

432436
eval :: forall a. Eq a => Environment a -> Expr Void a -> Val a

dhall/src/Dhall/Normalize.hs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import Dhall.Syntax
3838
, FunctionBinding (..)
3939
, PreferAnnotation (..)
4040
, RecordField (..)
41+
, WithComponent (..)
4142
, Var (..)
4243
)
4344

@@ -698,9 +699,9 @@ normalizeWithM ctx e0 = loop (Syntax.denote e0)
698699
case e' of
699700
RecordLit kvs ->
700701
case ks of
701-
k :| [] ->
702+
WithLabel k :| [] ->
702703
return (RecordLit (Dhall.Map.insert k (Syntax.makeRecordField v') kvs))
703-
k₀ :| k₁ : ks' -> do
704+
WithLabel k₀ :| k₁ : ks' -> do
704705
let e₁ =
705706
case Dhall.Map.lookup k₀ kvs of
706707
Nothing -> RecordLit mempty
@@ -709,6 +710,23 @@ normalizeWithM ctx e0 = loop (Syntax.denote e0)
709710
e₂ <- loop (With e₁ (k₁ :| ks') v')
710711

711712
return (RecordLit (Dhall.Map.insert k₀ (Syntax.makeRecordField e₂) kvs))
713+
WithQuestion :| _ -> do
714+
return (With e' ks v')
715+
Some t ->
716+
case ks of
717+
WithQuestion :| [] -> do
718+
return (Some v')
719+
WithQuestion :| k : ks' -> do
720+
w <- loop (With t (k :| ks') v)
721+
return (Some w)
722+
WithLabel _ :| _ ->
723+
return (With e' ks v')
724+
App None _T ->
725+
case ks of
726+
WithQuestion :| _ ->
727+
return (App None _T)
728+
WithLabel _ :| _ ->
729+
return (With e' ks v')
712730
_ ->
713731
return (With e' ks v')
714732
Note _ e' -> loop e'

dhall/src/Dhall/Parser/Expression.hs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,11 @@ parsers embedded = Parsers{..}
388388
bs <- some (do
389389
try (nonemptyWhitespace *> _with *> nonemptyWhitespace)
390390

391-
keys <- Combinators.NonEmpty.sepBy1 anyLabelOrSome (try (whitespace *> _dot) *> whitespace)
391+
let withComponent =
392+
fmap WithLabel anyLabelOrSome
393+
<|> fmap (\_ -> WithQuestion) (text "?")
394+
395+
keys <- Combinators.NonEmpty.sepBy1 withComponent (try (whitespace *> _dot) *> whitespace)
392396

393397
whitespace
394398

dhall/src/Dhall/Pretty/Internal.hs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ escapeLabel :: Bool -> Text -> Text
513513
escapeLabel allowReserved l =
514514
case Text.uncons l of
515515
Just (h, t)
516-
| headCharacter h && Text.all tailCharacter t && (notReservedIdentifier || (allowReserved && someOrNotLanguageKeyword))
516+
| headCharacter h && Text.all tailCharacter t && (notReservedIdentifier || (allowReserved && someOrNotLanguageKeyword)) && l /= "?"
517517
-> l
518518
_ -> "`" <> l <> "`"
519519
where
@@ -829,7 +829,11 @@ prettyPrinters characterSet =
829829
<> Pretty.align (keyword "with" <> " " <> update)
830830

831831
(update, _) =
832-
prettyKeyValue prettyOperatorExpression equals (makeKeyValue b c)
832+
prettyKeyValue prettyOperatorExpression equals
833+
(makeKeyValue (fmap toText b) c)
834+
835+
toText WithQuestion = "?"
836+
toText (WithLabel k ) = k
833837
prettyExpression (Assert a) =
834838
Pretty.group (Pretty.flatAlt long short)
835839
where

dhall/src/Dhall/Syntax.hs

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ module Dhall.Syntax (
3737
, makeFunctionBinding
3838
, FieldSelection(..)
3939
, makeFieldSelection
40+
, WithComponent(..)
4041

4142
-- ** 'Let'-blocks
4243
, MultiLet(..)
@@ -79,9 +80,6 @@ module Dhall.Syntax (
7980
, linesLiteral
8081
, unlinesLiteral
8182

82-
-- * Desugaring
83-
, desugarWith
84-
8583
-- * Utilities
8684
, internalError
8785
-- `shift` should really be in `Dhall.Normalize`, but it's here to avoid a
@@ -118,7 +116,6 @@ import qualified Data.List.NonEmpty as NonEmpty
118116
import qualified Data.Text
119117
import qualified Data.Time as Time
120118
import qualified Dhall.Crypto
121-
import qualified Dhall.Optics as Optics
122119
import qualified Lens.Family as Lens
123120
import qualified Network.URI as URI
124121
import qualified Prettyprinter as Pretty
@@ -429,6 +426,10 @@ data FieldSelection s = FieldSelection
429426
makeFieldSelection :: Text -> FieldSelection s
430427
makeFieldSelection t = FieldSelection Nothing t Nothing
431428

429+
-- | A path component for a @with@ expression
430+
data WithComponent = WithLabel Text | WithQuestion
431+
deriving (Data, Eq, Generic, Lift, NFData, Ord, Show)
432+
432433
{-| Syntax tree for expressions
433434
434435
The @s@ type parameter is used to track the presence or absence of `Src`
@@ -644,7 +645,7 @@ data Expr s a
644645
-- | > Equivalent _ x y ~ x ≡ y
645646
| Equivalent (Maybe CharacterSet) (Expr s a) (Expr s a)
646647
-- | > With x y e ~ x with y = e
647-
| With (Expr s a) (NonEmpty Text) (Expr s a)
648+
| With (Expr s a) (NonEmpty WithComponent) (Expr s a)
648649
-- | > Note s x ~ e
649650
| Note s (Expr s a)
650651
-- | > ImportAlt ~ e1 ? e2
@@ -1464,30 +1465,6 @@ shift d (V x n) (Let (Binding src0 f src1 mt src2 r) e) =
14641465
r' = shift d (V x n) r
14651466
shift d v expression = Lens.over subExpressions (shift d v) expression
14661467

1467-
-- | Desugar all @with@ expressions
1468-
desugarWith :: Expr s a -> Expr s a
1469-
desugarWith = Optics.rewriteOf subExpressions rewrite
1470-
where
1471-
rewrite e@(With record (key :| []) value) =
1472-
Just
1473-
(Prefer
1474-
mempty
1475-
(PreferFromWith e)
1476-
record
1477-
(RecordLit [ (key, makeRecordField value) ])
1478-
)
1479-
rewrite e@(With record (key0 :| key1 : keys) value) =
1480-
Just
1481-
(Let
1482-
(makeBinding "_" record)
1483-
(Prefer mempty (PreferFromWith e) "_"
1484-
(RecordLit
1485-
[ (key0, makeRecordField $ With (Field "_" (FieldSelection Nothing key0 Nothing)) (key1 :| keys) (shift 1 "_" value)) ]
1486-
)
1487-
)
1488-
)
1489-
rewrite _ = Nothing
1490-
14911468
_ERROR :: String
14921469
_ERROR = "\ESC[1;31mError\ESC[0m"
14931470

0 commit comments

Comments
 (0)