Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create and use lenses for ProcessedTerm and Module #1866

Merged
merged 2 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/swarm-doc/Swarm/Doc/Pedagogy.hs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ import Swarm.Game.ScenarioInfo (
scenarioPath,
)
import Swarm.Game.World.Load (loadWorlds)
import Swarm.Language.Module (Module (..))
import Swarm.Language.Pipeline (ProcessedTerm (..))
import Swarm.Language.Pipeline (ProcessedTerm, processedSyntax)
import Swarm.Language.Syntax
import Swarm.Language.Text.Markdown (docToText, findCode)
import Swarm.Language.Types (Polytype)
Expand Down Expand Up @@ -131,11 +130,11 @@ isConsidered c = isUserFunc c && c `S.notMember` ignoredCommands
-- Also, the code from `run` is not parsed transitively yet.
getCommands :: Maybe ProcessedTerm -> Map Const [SrcLoc]
getCommands Nothing = mempty
getCommands (Just (ProcessedTerm (Module stx _) _ _)) =
getCommands (Just pt) =
M.fromListWith (<>) $ mapMaybe isCommand nodelist
where
nodelist :: [Syntax' Polytype]
nodelist = universe stx
nodelist = universe (pt ^. processedSyntax)
isCommand (Syntax' sloc t _ _) = case t of
TConst c -> guard (isConsidered c) >> Just (c, [sloc])
_ -> Nothing
Expand Down
8 changes: 4 additions & 4 deletions src/swarm-engine/Swarm/Game/Scenario/Scoring/CodeSize.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
-- in terms of textual length and AST nodes.
module Swarm.Game.Scenario.Scoring.CodeSize where

import Control.Lens ((^.))
import Control.Monad (guard)
import Data.Aeson
import Data.Data (Data)
import GHC.Generics (Generic)
import Swarm.Language.Module
import Swarm.Language.Pipeline
import Swarm.Language.Pipeline (ProcessedTerm, processedSyntax)
import Swarm.Language.Syntax

data CodeSizeDeterminators = CodeSizeDeterminators
Expand Down Expand Up @@ -39,5 +39,5 @@ codeMetricsFromSyntax s@(Syntax' srcLoc _ _ _) =
codeSizeFromDeterminator :: CodeSizeDeterminators -> Maybe ScenarioCodeMetrics
codeSizeFromDeterminator (CodeSizeDeterminators maybeInitialCode usedRepl) = do
guard $ not usedRepl
ProcessedTerm (Module s _) _ _ <- maybeInitialCode
return $ codeMetricsFromSyntax s
pt <- maybeInitialCode
return $ codeMetricsFromSyntax (pt ^. processedSyntax)
6 changes: 3 additions & 3 deletions src/swarm-engine/Swarm/Game/Step/Const.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1228,13 +1228,13 @@ execConst runChildProg c vs s k = do

case mt of
Nothing -> return $ mkReturn ()
Just t@(ProcessedTerm _ _ reqCtx) -> do
Just pt -> do
-- Add the reqCtx from the ProcessedTerm to the current robot's defReqs.
-- See #827 for an explanation of (1) why this is needed, (2) why
-- it's slightly technically incorrect, and (3) why it is still way
-- better than what we had before.
robotContext . defReqs <>= reqCtx
return $ initMachine' t empty s k
robotContext . defReqs <>= (pt ^. processedReqCtx)
return $ initMachine' pt empty s k
_ -> badConst
Not -> case vs of
[VBool b] -> return $ Out (VBool (not b)) s k
Expand Down
14 changes: 7 additions & 7 deletions src/swarm-lang/Swarm/Language/LSP/Hover.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,9 @@ import Data.Text.Utf16.Rope.Mixed qualified as R
import Language.LSP.Protocol.Types qualified as J
import Language.LSP.VFS
import Swarm.Language.Context as Ctx
import Swarm.Language.Module (Module (..))
import Swarm.Language.Parser (readTerm')
import Swarm.Language.Parser.Core (defaultParserConfig)
import Swarm.Language.Pipeline (ProcessedTerm (..), processParsedTerm)
import Swarm.Language.Pipeline (processParsedTerm, processedSyntax)
import Swarm.Language.Pretty (prettyText, prettyTextLine)
import Swarm.Language.Syntax
import Swarm.Language.Typecheck (inferConst)
Expand Down Expand Up @@ -68,12 +67,13 @@ showHoverInfo _ p vf@(VirtualFile _ _ myRope) =
genHoverInfo stx =
case processParsedTerm stx of
Left _e ->
let found@(Syntax foundSloc _) = narrowToPosition stx $ fromIntegral absolutePos
finalPos = posToRange myRope foundSloc
let found = narrowToPosition stx $ fromIntegral absolutePos
finalPos = posToRange myRope (found ^. sLoc)
in (,finalPos) . treeToMarkdown 0 $ explain found
Right (ProcessedTerm modul _req _reqCtx) ->
let found@(Syntax' foundSloc _ _ _) = narrowToPosition (moduleAST modul) $ fromIntegral absolutePos
finalPos = posToRange myRope foundSloc
Right pt ->
let found =
narrowToPosition (pt ^. processedSyntax) $ fromIntegral absolutePos
finalPos = posToRange myRope (found ^. sLoc)
in (,finalPos) . treeToMarkdown 0 $ explain found

posToRange :: R.Rope -> SrcLoc -> Maybe J.Range
Expand Down
9 changes: 8 additions & 1 deletion src/swarm-lang/Swarm/Language/Module.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{-# LANGUAGE TemplateHaskell #-}

-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
Expand All @@ -6,11 +8,14 @@
module Swarm.Language.Module (
-- * Modules
Module (..),
moduleSyntax,
moduleCtx,
TModule,
UModule,
trivMod,
) where

import Control.Lens (makeLenses)
import Data.Data (Data)
import Data.Yaml (FromJSON, ToJSON)
import GHC.Generics (Generic)
Expand All @@ -27,9 +32,11 @@ import Swarm.Language.Types (Polytype, UPolytype, UType)
-- contain definitions ('Swarm.Language.Syntax.TDef'). A module
-- contains the type-annotated AST of the expression itself, as well
-- as the context giving the types of any defined variables.
data Module s t = Module {moduleAST :: Syntax' s, moduleCtx :: Ctx t}
data Module s t = Module {_moduleSyntax :: Syntax' s, _moduleCtx :: Ctx t}
deriving (Show, Eq, Functor, Data, Generic, FromJSON, ToJSON)

makeLenses ''Module

-- | A 'TModule' is the final result of the type inference process on
-- an expression: we get a polytype for the expression, and a
-- context of polytypes for the defined variables.
Expand Down
25 changes: 22 additions & 3 deletions src/swarm-lang/Swarm/Language/Pipeline.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}

-- |
-- SPDX-License-Identifier: BSD-3-Clause
Expand All @@ -9,15 +10,22 @@
-- text representing a Swarm program into something useful, this is
-- probably the module you want.
module Swarm.Language.Pipeline (
-- * ProcessedTerm
ProcessedTerm (..),
processedModule,
processedSyntax,
processedRequirements,
processedReqCtx,

-- * Pipeline functions for producing ProcessedTerm
processTerm,
processParsedTerm,
processTerm',
processParsedTerm',
processTermEither,
) where

import Control.Lens ((^.))
import Control.Lens (Lens', makeLenses, view, (^.))
import Data.Bifunctor (first)
import Data.Data (Data)
import Data.Text (Text)
Expand Down Expand Up @@ -46,9 +54,20 @@ import Witch (into)
--
-- * The requirements context for any definitions embedded in the
-- term ('ReqCtx')
data ProcessedTerm = ProcessedTerm TModule Requirements ReqCtx
data ProcessedTerm = ProcessedTerm
{ _processedModule :: TModule
, _processedRequirements :: Requirements
, _processedReqCtx :: ReqCtx
}
deriving (Data, Show, Eq, Generic)

makeLenses ''ProcessedTerm

-- | A convenient lens directly targeting the AST stored in a
-- ProcessedTerm.
processedSyntax :: Lens' ProcessedTerm (Syntax' Polytype)
processedSyntax = processedModule . moduleSyntax

processTermEither :: Text -> Either Text ProcessedTerm
processTermEither t = case processTerm t of
Left err -> Left $ T.unwords ["Could not parse term:", err]
Expand All @@ -59,7 +78,7 @@ instance FromJSON ProcessedTerm where
parseJSON = withText "Term" $ either (fail . into @String) return . processTermEither

instance ToJSON ProcessedTerm where
toJSON (ProcessedTerm t _ _) = String $ prettyText (moduleAST t)
toJSON = String . prettyText . view processedSyntax

-- | Given a 'Text' value representing a Swarm program,
--
Expand Down
8 changes: 3 additions & 5 deletions src/swarm-tournament/Swarm/Web/Tournament/Validate.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ import Swarm.Game.State.Runtime (initGameStateConfig, initScenarioInputs)
import Swarm.Game.State.Substate (initState, seed)
import Swarm.Game.Step.Validate (playUntilWin)
import Swarm.Language.Context qualified as Ctx
import Swarm.Language.Module (Module (..))
import Swarm.Language.Pipeline (ProcessedTerm (..), processTermEither)
import Swarm.Language.Pipeline
import Swarm.Util.Yaml
import Swarm.Web.Tournament.Database.Query
import Swarm.Web.Tournament.Type
Expand Down Expand Up @@ -213,12 +212,11 @@ verifySolution (SolutionTimeout timeoutSeconds) sol gs = do
(gs ^. randomness . seed)
codeMetrics
where
ProcessedTerm (Module s _) _ reqCtx = sol
codeMetrics = codeMetricsFromSyntax s
codeMetrics = codeMetricsFromSyntax (sol ^. processedSyntax)
gs' =
gs
-- See #827 for an explanation of why it's important to add to
-- the robotContext defReqs here (and also why this will,
-- hopefully, eventually, go away).
& baseRobot . robotContext . defReqs <>~ reqCtx
& baseRobot . robotContext . defReqs <>~ (sol ^. processedReqCtx)
& baseRobot . machine .~ initMachine sol Ctx.empty emptyStore
6 changes: 3 additions & 3 deletions src/swarm-tui/Swarm/TUI/Controller.hs
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ import Swarm.Game.Step (finishGameTick, gameTick)
import Swarm.Language.Capability (Capability (CGod, CMake), constCaps)
import Swarm.Language.Context
import Swarm.Language.Key (KeyCombo, mkKeyCombo)
import Swarm.Language.Module
import Swarm.Language.Module (Module (..))
import Swarm.Language.Parser.Lex (reservedWords)
import Swarm.Language.Pipeline
import Swarm.Language.Pipeline (ProcessedTerm (..), processTerm', processedSyntax)
import Swarm.Language.Pipeline.QQ (tmQ)
import Swarm.Language.Pretty
import Swarm.Language.Requirement qualified as R
Expand Down Expand Up @@ -1301,7 +1301,7 @@ validateREPLForm s =
| otherwise ->
let result = processTerm' (topCtx ^. defTypes) (topCtx ^. defReqs) uinput
theType = case result of
Right (Just (ProcessedTerm (Module tm _) _ _)) -> Just (tm ^. sType)
Right (Just pt) -> Just (pt ^. processedSyntax . sType)
_ -> Nothing
in s
& uiState . uiGameplay . uiREPL . replValid .~ isRight result
Expand Down
8 changes: 3 additions & 5 deletions src/swarm-web/Swarm/Web.hs
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,8 @@ import Swarm.Game.State
import Swarm.Game.State.Robot
import Swarm.Game.State.Substate
import Swarm.Game.Step.Path.Type
import Swarm.Language.Module
import Swarm.Language.Pipeline
import Swarm.Language.Pipeline (processTermEither, processedSyntax)
import Swarm.Language.Pretty (prettyTextLine)
import Swarm.Language.Syntax
import Swarm.TUI.Model
import Swarm.TUI.Model.Goal
import Swarm.TUI.Model.Repl (REPLHistItem, replHistory, replSeq)
Expand Down Expand Up @@ -231,8 +229,8 @@ recogFoundHandler appStateRef = do
codeRenderHandler :: Text -> Handler Text
codeRenderHandler contents = do
return $ case processTermEither contents of
Right (ProcessedTerm (Module stx@(Syntax' _srcLoc _term _ _) _) _ _) ->
into @Text . drawTree . fmap (T.unpack . prettyTextLine) . para Node $ stx
Right pt ->
into @Text . drawTree . fmap (T.unpack . prettyTextLine) . para Node $ pt ^. processedSyntax
Left x -> x

codeRunHandler :: BChan AppEvent -> Text -> Handler Text
Expand Down