Skip to content

Commit 09e98ed

Browse files
authored
Merge pull request #180 from phantamanta44/majestic
majestic: fix bubbling + type annotations for option metadata
2 parents e54f748 + f64d6b0 commit 09e98ed

File tree

7 files changed

+115
-61
lines changed

7 files changed

+115
-61
lines changed

src/compiler/api/GF/Compile/Compute/Concrete2.hs

Lines changed: 75 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,22 @@
33
module GF.Compile.Compute.Concrete2
44
(Env, Scope, Value(..), Variants(..), Constraint, OptionInfo(..), ChoiceMap, cleanOptions,
55
ConstValue(..), ConstVariants(..), Globals(..), PredefTable, EvalM,
6-
mapVariants, unvariants, variants2consts, consts2variants,
7-
runEvalM, runEvalMWithOpts, stdPredef, globals, withState,
6+
mapVariants, mapVariantsC, unvariants, variants2consts,
7+
mapConstVs, mapConstVsC, unconstVs, consts2variants,
8+
runEvalM, runEvalMWithOpts, reset, reset1, stdPredef, globals, withState,
89
PredefImpl, Predef(..), ($\),
910
pdCanonicalArgs, pdArity,
1011
normalForm, normalFlatForm,
1112
eval, apply, value2term, value2termM, bubble, patternMatch, vtableSelect, State(..),
1213
newResiduation, getMeta, setMeta, MetaState(..), variants, try,
13-
evalError, evalWarn, ppValue, Choice(..), unit, poison, split, split3, split4, mapC, mapCM) where
14+
evalError, evalWarn, ppValue, Choice(..), unit, poison, split, split3, split4,
15+
mapC, forC, mapCM, forCM) where
1416

1517
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
1618
import GF.Infra.Ident
1719
import GF.Infra.CheckM
1820
import GF.Data.Operations(Err(..))
19-
import GF.Data.Utilities(maybeAt,splitAt',(<||>),anyM)
21+
import GF.Data.Utilities(maybeAt,splitAt',(<||>),anyM,secondM,bimapM)
2022
import GF.Grammar.Lookup(lookupResDef,lookupOrigInfo)
2123
import GF.Grammar.Grammar
2224
import GF.Grammar.Macros
@@ -94,17 +96,23 @@ data Value
9496
| VCRecType [(Label, Bool, Value)]
9597
| VCInts (Maybe Integer) (Maybe Integer)
9698

99+
third f (a,b,c) = (a, b, f c)
100+
97101
data Variants
98102
= VarFree [Value]
99-
| VarOpts Value [(Value, Value)]
103+
| VarOpts Value Value [(Value, Value, Value)]
100104

101105
mapVariants :: (Value -> Value) -> Variants -> Variants
102-
mapVariants f (VarFree vs) = VarFree (f <$> vs)
103-
mapVariants f (VarOpts n cs) = VarOpts n (second f <$> cs)
106+
mapVariants f (VarFree vs) = VarFree (f <$> vs)
107+
mapVariants f (VarOpts nty n cs) = VarOpts nty n (third f <$> cs)
108+
109+
mapVariantsC :: (Choice -> Value -> Value) -> Choice -> Variants -> Variants
110+
mapVariantsC f c (VarFree vs) = VarFree (mapC f c vs)
111+
mapVariantsC f c (VarOpts nty n cs) = VarOpts nty n (mapC (third . f) c cs)
104112

105113
unvariants :: Variants -> [Value]
106-
unvariants (VarFree vs) = vs
107-
unvariants (VarOpts n cs) = snd <$> cs
114+
unvariants (VarFree vs) = vs
115+
unvariants (VarOpts nty n cs) = cs <&> \(_,_,v) -> v
108116

109117
isCanonicalForm :: Bool -> Value -> Bool
110118
isCanonicalForm flat (VClosure {}) = True
@@ -136,15 +144,19 @@ data ConstValue a
136144

137145
data ConstVariants a
138146
= ConstFree [ConstValue a]
139-
| ConstOpts Value [(Value, ConstValue a)]
147+
| ConstOpts Value Value [(Value, Value, ConstValue a)]
140148

141149
mapConstVs :: (ConstValue a -> ConstValue b) -> ConstVariants a -> ConstVariants b
142-
mapConstVs f (ConstFree vs) = ConstFree (f <$> vs)
143-
mapConstVs f (ConstOpts n cs) = ConstOpts n (second f <$> cs)
150+
mapConstVs f (ConstFree vs) = ConstFree (f <$> vs)
151+
mapConstVs f (ConstOpts nty n cs) = ConstOpts nty n (third f <$> cs)
152+
153+
mapConstVsC :: (Choice -> ConstValue a -> ConstValue b) -> Choice -> ConstVariants a -> ConstVariants b
154+
mapConstVsC f c (ConstFree vs) = ConstFree (mapC f c vs)
155+
mapConstVsC f c (ConstOpts nty n cs) = ConstOpts nty n (mapC (third . f) c cs)
144156

145157
unconstVs :: ConstVariants a -> [ConstValue a]
146-
unconstVs (ConstFree vs) = vs
147-
unconstVs (ConstOpts n cs) = snd <$> cs
158+
unconstVs (ConstFree vs) = vs
159+
unconstVs (ConstOpts nty n cs) = cs <&> \(_,_,v) -> v
148160

149161
instance Functor ConstValue where
150162
fmap f (Const c) = Const (f c)
@@ -167,12 +179,12 @@ instance Applicative ConstValue where
167179
_ <*> RunTime = RunTime
168180

169181
variants2consts :: (Value -> ConstValue a) -> Variants -> ConstVariants a
170-
variants2consts f (VarFree vs) = ConstFree (f <$> vs)
171-
variants2consts f (VarOpts n os) = ConstOpts n (second f <$> os)
182+
variants2consts f (VarFree vs) = ConstFree (f <$> vs)
183+
variants2consts f (VarOpts nty n os) = ConstOpts nty n (third f <$> os)
172184

173185
consts2variants :: (ConstValue a -> Value) -> ConstVariants a -> Variants
174-
consts2variants f (ConstFree vs) = VarFree (f <$> vs)
175-
consts2variants f (ConstOpts n os) = VarOpts n (second f <$> os)
186+
consts2variants f (ConstFree vs) = VarFree (f <$> vs)
187+
consts2variants f (ConstOpts nty n os) = VarOpts nty n (third f <$> os)
176188

177189
normalForm :: Globals -> Term -> Check Term
178190
normalForm g t = value2term g [] (bubble (eval g [] unit t []))
@@ -326,14 +338,17 @@ eval g env c (Markup tag as ts) [] =
326338
in (VMarkup tag vas vs)
327339
eval g env c (Reset ctl mb_ct t qid) [] = VReset ctl (fmap (\t -> eval g env c t []) mb_ct) (eval g env c t []) qid
328340
eval g env c (TSymCat d r rs) []= VSymCat d r [(i,(fromJust (lookup pv env),ty)) | (i,(pv,ty)) <- rs]
329-
eval g env c t@(Opts n cs) vs = if null cs
330-
then VError ("No options in expression:" $$ ppTerm Unqualified 0 t)
331-
else let (c1,c2,c3) = split3 c
332-
vn = eval g env c1 n []
333-
vcs = mapC evalOpt c cs
334-
in VFV c3 (VarOpts vn vcs)
335-
where evalOpt c' (l,t) = let (c1,c2) = split c' in (eval g env c1 l [], eval g env c2 t vs)
336-
eval g env c t vs = VError ("Cannot reduce term" <+> pp t)
341+
eval g env c t@(Opts (nty,n) cs) vs = if null cs
342+
then VError ("No options in expression:" $$ ppTerm Unqualified 0 t)
343+
else let (c1,c2,c3) = split3 c
344+
(c1ty,c1t) = split c1
345+
vnty = eval g env c1ty (fromJust nty) []
346+
vn = eval g env c1t n []
347+
vcs = mapC evalOpt c2 cs
348+
in VFV c3 (VarOpts vnty vn vcs)
349+
where evalOpt c' ((lty,l),t) = let (c1,c2,c3) = split3 c'
350+
in (eval g env c1 (fromJust lty) [], eval g env c2 l [], eval g env c3 t vs)
351+
eval g env c t vs = VError ("Cannot reduce term" <+> pp t)
337352

338353
evalPredef :: Globals -> Choice -> Ident -> [Value] -> Value
339354
evalPredef g@(Gl gr pds) c n args =
@@ -381,7 +396,7 @@ apply g v [] = v
381396

382397
data BubbleVariants
383398
= BubbleFree Int
384-
| BubbleOpts Value [Value]
399+
| BubbleOpts Value Value [(Value, Value)]
385400

386401
bubble v = snd (bubble v)
387402
where
@@ -411,11 +426,15 @@ bubble v = snd (bubble v)
411426
bubble v@(VFV c (VarFree vs))
412427
| null vs = (Map.empty, v)
413428
| otherwise = let (union,vs') = mapAccumL descend Map.empty vs
414-
in (Map.insert c (BubbleFree (length vs),1) union, addVariants (VFV c (VarFree vs')) union)
415-
bubble v@(VFV c (VarOpts n os))
429+
b = BubbleFree (length vs)
430+
v' = addVariants (VFV c (VarFree vs')) union
431+
in (Map.insert c (b,1) union, v')
432+
bubble v@(VFV c (VarOpts nty n os))
416433
| null os = (Map.empty, v)
417-
| otherwise = let (union,os') = mapAccumL (\acc (k,v) -> second (k,) $ descend acc v) Map.empty os
418-
in (Map.insert c (BubbleOpts n (fst <$> os),1) union, addVariants (VFV c (VarOpts n os')) union)
434+
| otherwise = let (union,os') = mapAccumL (\acc (lty,l,v) -> second (lty,l,) $ descend acc v) Map.empty os
435+
b = BubbleOpts nty n (os <&> \(lty,l,_) -> (lty,l))
436+
v' = addVariants (VFV c (VarOpts nty n os')) union
437+
in (Map.insert c (b,1) union, v')
419438
bubble (VAlts v vs) = lift1L2 VAlts v vs
420439
bubble (VStrs vs) = liftL VStrs vs
421440
bubble (VMarkup tag attrs vs) =
@@ -500,8 +519,8 @@ bubble v = snd (bubble v)
500519
where
501520
addVariant c (bvs,cnt) v
502521
| cnt > 1 = VFV c $ case bvs of
503-
BubbleFree k -> VarFree (replicate k v)
504-
BubbleOpts n os -> VarOpts n ((,v) <$> os)
522+
BubbleFree k -> VarFree (replicate k v)
523+
BubbleOpts nty n os -> VarOpts nty n (os <&> \(lty,l) -> (lty,l,v))
505524
| otherwise = v
506525

507526
unitfy = fmap (\(n,_) -> (n,1))
@@ -669,9 +688,10 @@ data MetaState
669688
| Residuation Scope (Maybe Constraint)
670689
data OptionInfo
671690
= OptionInfo
672-
{ optChoice :: Choice
673-
, optLabel :: Value
674-
, optChoices :: [Value]
691+
{ optChoice :: Choice
692+
, optLabelType :: Value
693+
, optLabel :: Value
694+
, optChoices :: [(Value, Value)]
675695
}
676696
type ChoiceMap = Map.Map Choice Int
677697
data State
@@ -738,6 +758,12 @@ reset (EvalM f) = EvalM $ \g k state r ws ->
738758
Fail msg ws -> Fail msg ws
739759
Success xs ws -> k (reverse xs) state r ws
740760

761+
reset1 :: EvalM a -> EvalM (Maybe a)
762+
reset1 (EvalM f) = EvalM $ \g k state r ws ->
763+
case f g (\x' state x ws -> Success (x <|> Just x') ws) state Nothing ws of
764+
Fail msg ws -> Fail msg ws
765+
Success x ws -> k x state r ws
766+
741767
globals :: EvalM Globals
742768
globals = EvalM (\g k -> k g)
743769

@@ -907,13 +933,13 @@ value2termM True xs (VFV i (VarFree vs)) = do
907933
v <- variants i vs
908934
value2termM True xs v
909935
value2termM False xs (VFV i (VarFree vs)) = variants' i (value2termM False xs) vs
910-
value2termM flat xs (VFV i (VarOpts n os)) =
936+
value2termM flat xs (VFV i (VarOpts nty n os)) =
911937
EvalM $ \g k (State choices metas opts) r msgs ->
912938
let j = fromMaybe 0 (Map.lookup i choices)
913939
in case os `maybeAt` j of
914-
Just (l,t) -> case value2termM flat xs t of
915-
EvalM f -> let oi = OptionInfo i n (fst <$> os)
916-
in f g k (State choices metas (oi:opts)) r msgs
940+
Just (lty,l,t) -> case value2termM flat xs t of
941+
EvalM f -> let oi = OptionInfo i nty n (os <&> \(lty,l,_) -> (lty,l))
942+
in f g k (State choices metas (oi:opts)) r msgs
917943
Nothing -> Fail ("Index" <+> j <+> "out of bounds for option:" $$ ppValue Unqualified 0 n) msgs
918944
value2termM flat xs (VPatt min max p) = return (EPatt min max p)
919945
value2termM flat xs (VPattType v) = do t <- value2termM flat xs v
@@ -1020,7 +1046,9 @@ ppValue q d (VC v1 v2) = prec d 1 (hang (ppValue q 2 v1) 2 ("++" <+> ppValue q 1
10201046
ppValue q d (VGlue v1 v2) = prec d 2 (ppValue q 3 v1 <+> '+' <+> ppValue q 2 v2)
10211047
ppValue q d (VPatt _ _ _) = pp "VPatt"
10221048
ppValue q d (VPattType _) = pp "VPattType"
1023-
ppValue q d (VFV i vs) = prec d 4 ("variants" <+> pp i <+> braces (fsep (punctuate ';' (map (ppValue q 0) (unvariants vs)))))
1049+
ppValue q d (VFV i (VarFree vs)) = prec d 4 ("variants" <+> pp i <+> braces (fsep (punctuate ';' (map (ppValue q 0) vs))))
1050+
ppValue q d (VFV i (VarOpts _ n os)) = prec d 4 ("option" <+> ppValue q 0 n <+> "of" <+> pp i <+> braces (fsep (punctuate ';'
1051+
(map (\(_,l,v) -> parens (ppValue q 0 l) <+> "=>" <+> ppValue q 0 v) os))))
10241052
ppValue q d (VAlts e xs) = prec d 4 ("pre" <+> braces (ppValue q 0 e <> ';' <+> fsep (punctuate ';' (map (ppAltern q) xs))))
10251053
ppValue q d (VStrs _) = pp "VStrs"
10261054
ppValue q d (VMarkup _ _ _) = pp "VMarkup"
@@ -1129,6 +1157,9 @@ mapC f c (x:xs) =
11291157
let (!c1,!c2) = split c
11301158
in f c1 x : mapC f c2 xs
11311159

1160+
forC :: Choice -> [a] -> (Choice -> a -> b) -> [b]
1161+
forC c xs f = mapC f c xs
1162+
11321163
mapCM :: Monad m => (Choice -> a -> m b) -> Choice -> [a] -> m [b]
11331164
mapCM f c [] = return []
11341165
mapCM f c [x] = do y <- f c x
@@ -1138,3 +1169,6 @@ mapCM f c (x:xs) = do
11381169
y <- f c1 x
11391170
ys <- mapCM f c2 xs
11401171
return (y:ys)
1172+
1173+
forCM :: Monad m => Choice -> [a] -> (Choice -> a -> m b) -> m [b]
1174+
forCM c xs f = mapCM f c xs

src/compiler/api/GF/Compile/Repl.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import GF.Compile.Compute.Concrete2
2323
, ChoiceMap
2424
, Globals(Gl)
2525
, OptionInfo(..)
26+
, bubble
2627
, stdPredef
2728
, unit
2829
, eval
@@ -57,7 +58,6 @@ import GF.Infra.Ident (moduleNameS)
5758
import GF.Infra.Option (noOptions)
5859
import GF.Infra.UseIO (justModuleName)
5960
import GF.Text.Pretty (render)
60-
import Debug.Trace
6161

6262
data ReplOpts = ReplOpts
6363
{ lang :: Lang
@@ -282,11 +282,11 @@ runRepl' opts@ReplOpts { lang, evalToFlat } gl@(Gl g _) = do
282282
outputStrLn $ show i ++ (if null opts then ". " else "*. ") ++ render (ppTerm Unqualified 0 r)
283283

284284
outputOptions ois os =
285-
forM_ ois $ \(OptionInfo c n ls) -> do
285+
forM_ ois $ \(OptionInfo c _ n ls) -> do
286286
outputStrLn ""
287287
outputStrLn $ show (unchoice c) ++ ") " ++ render (ppValue Unqualified 0 n)
288288
let sel = fromMaybe 0 (Map.lookup c os) + 1
289-
forM_ (zip [1..] ls) $ \(i, l) ->
289+
forM_ (zip [1..] ls) $ \(i, (_,l)) ->
290290
outputStrLn $ (if i == sel then "->" else " ") ++ show i ++ ". " ++ render (ppValue Unqualified 0 l)
291291

292292
runRepl :: ReplOpts -> IO ()

src/compiler/api/GF/Compile/TypeCheck/ConcreteNew.hs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -407,12 +407,17 @@ tcRho scope c (Reset ctl mb_ct t qid) mb_ty
407407
VApp c qid [] -> return (Reset ctl mb_ct t qid, ty)
408408
_ -> evalError (pp "Needs atomic type"<+>ppValue Unqualified 0 ty)
409409
| otherwise = evalError (pp "Operator" <+> pp ctl <+> pp "is not defined")
410-
tcRho scope s (Opts n cs) mb_ty = do
410+
tcRho scope s (Opts (nty,n) cs) mb_ty = do
411+
gl <- globals
411412
let (s1,s2,s3) = split3 s
412-
(n,_) <- tcRho scope s1 n Nothing
413-
(ls,_) <- tcUnifying scope s2 (fst <$> cs) Nothing
413+
(n,nty) <- tcRho scope s1 n (nty <&> \ty -> eval gl [] poison ty [])
414+
nty <- value2termM True [] nty
415+
ls <- forCM s2 cs $ \s' ((lty,l),_) -> do
416+
(l,lty) <- tcRho scope s' l (lty <&> \ty -> eval gl [] poison ty [])
417+
lty <- value2termM True [] lty
418+
return (Just lty, l)
414419
(ts,ty) <- tcUnifying scope s3 (snd <$> cs) mb_ty
415-
return (Opts n (zip ls ts), ty)
420+
return (Opts (Just nty, n) (zip ls ts), ty)
416421
tcRho scope s t _ = unimplemented ("tcRho "++show t)
417422

418423
evalCodomain :: Scope -> Ident -> Value -> EvalM Value
@@ -1179,9 +1184,9 @@ quantify scope t tvs ty = do
11791184
check m n xs (VFV c (VarFree vs)) = do
11801185
(xs,vs) <- mapAccumM (check m n) xs vs
11811186
return (xs,VFV c (VarFree vs))
1182-
check m n xs (VFV c (VarOpts name os)) = do
1183-
(xs,os) <- mapAccumM (\acc (l,v) -> second (l,) <$> check m n acc v) xs os
1184-
return (xs,VFV c (VarOpts name os))
1187+
check m n xs (VFV c (VarOpts nty name os)) = do
1188+
(xs,os) <- mapAccumM (\acc (lty,l,v) -> second (lty,l,) <$> check m n acc v) xs os
1189+
return (xs,VFV c (VarOpts nty name os))
11851190
check m n xs (VAlts v vs) = do
11861191
(xs,v) <- check m n xs v
11871192
(xs,vs) <- mapAccumM (\xs (v1,v2) -> do (xs,v1) <- check m n xs v1

src/compiler/api/GF/Data/Utilities.hs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
-- Basic functions not in the standard libraries
1212
-----------------------------------------------------------------------------
1313

14-
14+
{-# LANGUAGE TupleSections #-}
1515
module GF.Data.Utilities(module GF.Data.Utilities) where
1616

1717
import Data.Bifunctor (first)
1818
import Data.Maybe
1919
import Data.List
20-
import Control.Monad (MonadPlus(..),foldM,liftM,when)
20+
import Control.Monad (MonadPlus(..),foldM,liftM,liftM2,when)
2121
import Control.Applicative(liftA2)
2222
import qualified Data.Set as Set
2323

@@ -128,7 +128,7 @@ compareBy f = both f compare
128128
both :: (a -> b) -> (b -> b -> c) -> a -> a -> c
129129
both f g x y = g (f x) (f y)
130130

131-
-- * functions on pairs
131+
-- * functions on tuples
132132

133133
apFst :: (a -> a') -> (a, b) -> (a', b)
134134
apFst f (a, b) = (f a, b)
@@ -174,6 +174,18 @@ allM p = foldM (\b x -> if b then p x else return False) True
174174
anyM :: (Foldable f, Monad m) => (a -> m Bool) -> f a -> m Bool
175175
anyM p = foldM (\b x -> if b then return True else p x) False
176176

177+
-- | Lifts a monadic action to pairs in the first element.
178+
firstM :: Monad m => (a -> m a') -> (a, b) -> m (a', b)
179+
firstM f (a, b) = (,b) <$> f a
180+
181+
-- | Lifts a monadic action to pairs in the second element.
182+
secondM :: Monad m => (b -> m b') -> (a, b) -> m (a, b')
183+
secondM f (a, b) = (a,) <$> f b
184+
185+
-- | Lifts a pair of monadic actions to an action on pairs, sequencing left-to-right.
186+
bimapM :: Monad m => (a -> m a') -> (b -> m b') -> (a, b) -> m (a', b')
187+
bimapM f g (a, b) = liftM2 (,) (f a) (g b)
188+
177189
-- * functions on Maybes
178190

179191
-- | Returns the argument on the right, or a default value on the left.

src/compiler/api/GF/Grammar/Grammar.hs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -343,9 +343,10 @@ data Info =
343343
| AnyInd Bool ModuleName -- ^ (/INDIR/) the 'Bool' says if canonical
344344
deriving Show
345345

346-
type Type = Term
347-
type Cat = QIdent
348-
type Fun = QIdent
346+
type Type = Term
347+
type MTyTerm = (Maybe Term, Term)
348+
type Cat = QIdent
349+
type Fun = QIdent
349350

350351
type QIdent = (ModuleName,Ident)
351352

@@ -373,7 +374,7 @@ data Term =
373374
| P Term Label -- ^ projection: @r.p@
374375
| ExtR Term Term -- ^ extension: @R ** {x : A}@ (both types and terms)
375376

376-
| Opts Term [Option] -- ^ options: @options s in { e => x ; ... }@
377+
| Opts MTyTerm [Option] -- ^ options: @options s in { e => x ; ... }@
377378

378379
| Table Term Term -- ^ table type: @P => A@
379380
| T TInfo [Case] -- ^ table: @table {p => c ; ...}@
@@ -466,7 +467,7 @@ type Equation = ([Patt],Term)
466467

467468
type Labelling = (Label, Type)
468469
type Assign = (Label, (Maybe Type, Term))
469-
type Option = (Term, Term)
470+
type Option = (MTyTerm, Term)
470471
type Case = (Patt, Term)
471472
--type Cases = ([Patt], Term)
472473
type LocalDef = (Ident, (Maybe Type, Term))

src/compiler/api/GF/Grammar/Parser.y

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ Exp4 :: { Term }
452452
Exp4
453453
: Exp4 Exp5 { App $1 $2 }
454454
| Exp4 '{' Exp '}' { App $1 (ImplArg $3) }
455-
| 'option' Exp 'of' '{' ListOpt '}' { Opts $2 $5 }
455+
| 'option' Exp 'of' '{' ListOpt '}' { Opts (Nothing, $2) $5 }
456456
| 'case' Exp 'of' '{' ListCase '}' { let annot = case $2 of
457457
Typed _ t -> TTyped t
458458
_ -> TRaw
@@ -611,7 +611,7 @@ ListPattTupleComp
611611

612612
Opt :: { Option }
613613
Opt
614-
: '(' Exp ')' '=>' Exp { ($2,$5) }
614+
: '(' Exp ')' '=>' Exp { ((Nothing,$2),$5) }
615615

616616
ListOpt :: { [Option] }
617617
ListOpt

0 commit comments

Comments
 (0)