Skip to content

Commit c8f2b7b

Browse files
authored
Change SRcd to contain a list of tuples instead of a Map (#2584)
It makes sense for, say, a record type to consist of a `Map` from field names to types. However, we were also storing record literal AST nodes using a `Map`, but after a question from @oliverpauffley I realized this is probably not the right thing to do. For one thing, the AST should store the fields in the same order as they were written (otherwise pretty-printing would always sort record fields alphabetically). For another, the field names should be stored as `LocVar`s, not just `Var`s, so we know where they were in the source.
1 parent 699b79c commit c8f2b7b

File tree

14 files changed

+63
-53
lines changed

14 files changed

+63
-53
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Test that record literals are pretty-printed with fields in the
2+
// same order they were written
3+
([x = 3, y = 5], [y = 3, x = 5])

src/swarm-engine/Swarm/Game/Step.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import Control.Effect.Lens
4242
import Control.Effect.Lift
4343
import Control.Lens as Lens hiding (Const, distrib, from, parts, use, uses, view, (%=), (+=), (.=), (<+=), (<>=))
4444
import Control.Monad (foldM, forM_, unless, when)
45+
import Data.Bifunctor (first)
4546
import Data.Foldable.Extra (notNull)
4647
import Data.Functor (void)
4748
import Data.IntMap qualified as IM
@@ -659,7 +660,7 @@ stepCESK cesk = case cesk of
659660
Out _ s (FApp _ : _) -> badMachineState s "FApp of non-function"
660661
-- Start evaluating a record. If it's empty, we're done. Otherwise, focus
661662
-- on the first field and record the rest in a FRcd frame.
662-
In (TRcd m) e s k -> return $ case M.assocs m of
663+
In (TRcd m) e s k -> return $ case map (first lvVar) m of
663664
[] -> Out (VRcd M.empty) s k
664665
((x, t) : fs) -> In (fromMaybe (TVar x) t) e s (FRcd e [] x fs : k)
665666
-- When we finish evaluating the last field, return a record value.

src/swarm-lang/Swarm/Language/LSP/Hover.hs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ import Data.Foldable (asum)
2424
import Data.Graph
2525
import Data.List.NonEmpty (NonEmpty (..))
2626
import Data.List.NonEmpty qualified as NE
27-
import Data.Map qualified as M
28-
import Data.Maybe (catMaybes, fromMaybe, isNothing)
27+
import Data.Maybe (fromMaybe, isNothing, mapMaybe)
2928
import Data.Text (Text)
3029
import Data.Text qualified as T
3130
import Data.Text.Lines qualified as R
@@ -124,7 +123,7 @@ pathToPosition s0 pos = s0 :| fromMaybe [] (innerPath s0)
124123
STydef typ typBody _ti s1 -> d s1 <|> Just [locVarToSyntax' (tdVarName <$> typ) $ fromPoly typBody]
125124
SPair s1 s2 -> d s1 <|> d s2
126125
SDelay s -> d s
127-
SRcd m -> asum . map d . catMaybes . M.elems $ m
126+
SRcd m -> asum . map d . mapMaybe snd $ m
128127
SProj s1 _ -> d s1
129128
SAnnotate s _ -> d s
130129
SRequirements _ s -> d s

src/swarm-lang/Swarm/Language/LSP/VarUsage.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ getUsage bindings (CSyntax _pos t _comments) = case t of
110110
Just v -> checkOccurrences bindings v Bind [s1, s2]
111111
Nothing -> getUsage bindings s1 <> getUsage bindings s2
112112
SDelay s -> getUsage bindings s
113-
SRcd m -> M.foldMapWithKey (\x -> maybe (getUsage bindings (STerm (TVar x))) (getUsage bindings)) m
113+
SRcd m -> foldMap (\(LV _ x, mt) -> maybe (getUsage bindings (STerm (TVar x))) (getUsage bindings) mt) m
114114
SProj s _ -> getUsage bindings s
115115
SAnnotate s _ -> getUsage bindings s
116116
SSuspend s -> getUsage bindings s

src/swarm-lang/Swarm/Language/Parser/Record.hs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@ module Swarm.Language.Parser.Record (
88
parseRecord,
99
) where
1010

11-
import Data.Map (Map)
12-
import Data.Map qualified as M
1311
import Swarm.Language.Parser.Core (Parser)
14-
import Swarm.Language.Parser.Lex (symbol, tmVar)
15-
import Swarm.Language.Var (Var)
12+
import Swarm.Language.Parser.Lex (locTmVar, symbol)
13+
import Swarm.Language.Syntax.Loc (LocVar, lvVar)
1614
import Swarm.Util (failT, findDup, squote)
1715
import Text.Megaparsec (sepBy)
1816

@@ -22,10 +20,10 @@ import Text.Megaparsec (sepBy)
2220
--
2321
-- The @Parser a@ argument is the parser to use for the RHS of each
2422
-- binding in the record.
25-
parseRecord :: Parser a -> Parser (Map Var a)
23+
parseRecord :: Parser a -> Parser [(LocVar, a)]
2624
parseRecord p = (parseBinding `sepBy` symbol ",") >>= fromListUnique
2725
where
28-
parseBinding = (,) <$> tmVar <*> p
29-
fromListUnique kvs = case findDup (map fst kvs) of
30-
Nothing -> return $ M.fromList kvs
26+
parseBinding = (,) <$> locTmVar <*> p
27+
fromListUnique kvs = case findDup (map (lvVar . fst) kvs) of
28+
Nothing -> pure kvs
3129
Just x -> failT ["duplicate field name", squote x, "in record literal"]

src/swarm-lang/Swarm/Language/Parser/Type.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ module Swarm.Language.Parser.Type (
1515

1616
import Control.Monad.Combinators (many)
1717
import Control.Monad.Combinators.Expr (Operator (..), makeExprParser)
18+
import Data.Bifunctor (first)
1819
import Data.Fix (Fix (..), foldFix)
1920
import Data.List.Extra (enumerate)
21+
import Data.Map.Strict qualified as M
2022
import Data.Maybe (fromMaybe)
2123
import Swarm.Language.Parser.Core (Parser)
2224
import Swarm.Language.Parser.Lex (
@@ -30,6 +32,7 @@ import Swarm.Language.Parser.Lex (
3032
tyVar,
3133
)
3234
import Swarm.Language.Parser.Record (parseRecord)
35+
import Swarm.Language.Syntax.Loc (lvVar)
3336
import Swarm.Language.Types
3437
import Text.Megaparsec (choice, optional, some, (<|>))
3538

@@ -70,7 +73,7 @@ parseTypeAtom =
7073
TyVar <$> tyVar
7174
<|> TyConApp <$> parseTyCon <*> pure []
7275
<|> TyDelay <$> braces parseType
73-
<|> TyRcd <$> brackets (parseRecord (symbol ":" *> parseType))
76+
<|> TyRcd <$> brackets (M.fromList . (map . first) lvVar <$> parseRecord (symbol ":" *> parseType))
7477
<|> tyRec <$> (reserved "rec" *> tyVar) <*> (symbol "." *> parseType)
7578
<|> parens parseType
7679

src/swarm-lang/Swarm/Language/Parser/Value.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
module Swarm.Language.Parser.Value (readValue) where
1010

1111
import Control.Lens ((^.))
12+
import Data.Bifunctor (first)
1213
import Data.Either.Extra (eitherToMaybe)
14+
import Data.Map.Strict qualified as M
1315
import Data.Text (Text)
1416
import Data.Text qualified as T
1517
import Swarm.Language.Context qualified as Ctx
@@ -60,7 +62,7 @@ toValue = \case
6062
VKey <$> eitherToMaybe (MP.runParser parseKeyComboFull "" k)
6163
_ -> Nothing
6264
TPair t1 t2 -> VPair <$> toValue t1 <*> toValue t2
63-
TRcd m -> VRcd <$> traverse (>>= toValue) m
65+
TRcd m -> VRcd . M.fromList <$> traverse (traverse (>>= toValue) . first lvVar) m
6466
TParens t -> toValue t
6567
-- List the other cases explicitly, instead of a catch-all, so that
6668
-- we will get a warning if we ever add new constructors in the

src/swarm-lang/Swarm/Language/Requirements/Analysis.hs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import Control.Effect.Reader (Reader, ask, local)
2020
import Control.Monad (when)
2121
import Data.Fix (Fix (..))
2222
import Data.Foldable (forM_)
23-
import Data.Map qualified as M
2423
import Swarm.Language.Capability (Capability (..), constCaps)
2524
import Swarm.Language.Context qualified as Ctx
2625
import Swarm.Language.Requirements.Type
@@ -156,9 +155,9 @@ requirements tdCtx ctx =
156155
-- Everything else is straightforward.
157156
TPair t1 t2 -> add (singletonCap CProd) *> go t1 *> go t2
158157
TDelay t -> go t
159-
TRcd m -> add (singletonCap CRecord) *> forM_ (M.assocs m) (go . expandEq)
158+
TRcd m -> add (singletonCap CRecord) *> forM_ m (go . expandEq)
160159
where
161-
expandEq (x, Nothing) = TVar x
160+
expandEq (LV _ x, Nothing) = TVar x
162161
expandEq (_, Just t) = t
163162
TProj t _ -> add (singletonCap CRecord) *> go t
164163
-- A type ascription doesn't change requirements

src/swarm-lang/Swarm/Language/Syntax/AST.hs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import Data.Aeson.Types hiding (Key)
1717
import Data.Data (Data)
1818
import Data.Data.Lens (uniplate)
1919
import Data.Hashable (Hashable)
20-
import Data.Map.Strict (Map)
2120
import Data.Text (Text)
2221
import GHC.Generics (Generic)
2322
import Swarm.Language.Requirements.Type (Requirements)
@@ -137,7 +136,7 @@ data Term' ty
137136
| -- | Record literals @[x1 = e1, x2 = e2, x3, ...]@ Names @x@
138137
-- without an accompanying definition are sugar for writing
139138
-- @x=x@.
140-
SRcd (Map Var (Maybe (Syntax' ty)))
139+
SRcd [(LocVar, Maybe (Syntax' ty))]
141140
| -- | Record projection @e.x@
142141
SProj (Syntax' ty) Var
143142
| -- | Annotate a term with a type

src/swarm-lang/Swarm/Language/Syntax/Pattern.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ module Swarm.Language.Syntax.Pattern (
3838
) where
3939

4040
import Control.Lens (makeLenses, pattern Empty)
41-
import Data.Map.Strict (Map)
41+
import Data.Bifunctor (second)
4242
import Data.Text (Text)
4343
import Swarm.Language.Requirements.Type (Requirements)
4444
import Swarm.Language.Syntax.AST
@@ -130,10 +130,10 @@ pattern TDelay :: Term -> Term
130130
pattern TDelay t = SDelay (STerm t)
131131

132132
-- | Match a TRcd without annotations.
133-
pattern TRcd :: Map Var (Maybe Term) -> Term
134-
pattern TRcd m <- SRcd ((fmap . fmap) _sTerm -> m)
133+
pattern TRcd :: [(LocVar, Maybe Term)] -> Term
134+
pattern TRcd m <- SRcd ((map . second . fmap) _sTerm -> m)
135135
where
136-
TRcd m = SRcd ((fmap . fmap) STerm m)
136+
TRcd m = SRcd ((map . second . fmap) STerm m)
137137

138138
pattern TProj :: Term -> Var -> Term
139139
pattern TProj t x = SProj (STerm t) x

0 commit comments

Comments
 (0)