Skip to content

Commit cbe27d0

Browse files
committed
reinstate run for now
1 parent d293cfa commit cbe27d0

File tree

5 files changed

+102
-49
lines changed

5 files changed

+102
-49
lines changed

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

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import Control.Effect.Error
1717
import Control.Effect.Lens
1818
import Control.Effect.Lift
1919
import Control.Lens as Lens hiding (Const, distrib, from, parts, use, uses, view, (%=), (+=), (.=), (<+=), (<>=))
20-
import Control.Monad (filterM, forM, forM_, guard, unless, when)
20+
import Control.Monad (filterM, forM, forM_, guard, msum, unless, when)
2121
import Data.Bifunctor (second)
2222
import Data.Bool (bool)
2323
import Data.Char (chr, ord)
@@ -35,7 +35,7 @@ import Data.List.NonEmpty qualified as NE
3535
import Data.Map qualified as M
3636
import Data.Map.NonEmpty qualified as NEM
3737
import Data.Map.Strict qualified as MS
38-
import Data.Maybe (fromMaybe, isJust, isNothing, listToMaybe, mapMaybe)
38+
import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing, listToMaybe, mapMaybe)
3939
import Data.MonoidMap qualified as MM
4040
import Data.Ord (Down (Down))
4141
import Data.Sequence qualified as Seq
@@ -46,6 +46,7 @@ import Data.Text qualified as T
4646
import Data.Tuple (swap)
4747
import Linear (V2 (..), perp, zero)
4848
import Swarm.Effect as Effect (Time, getNow)
49+
import Swarm.Failure (SystemFailure, AssetData(Script))
4950
import Swarm.Game.Achievement.Definitions
5051
import Swarm.Game.CESK
5152
import Swarm.Game.Cosmetic.Attribute (readAttribute)
@@ -89,14 +90,17 @@ import Swarm.Game.Value
8990
import Swarm.Language.Capability
9091
import Swarm.Language.Key (parseKeyComboFull)
9192
import Swarm.Language.Parser.Value (readValue)
93+
import Swarm.Language.Pipeline (processTerm)
9294
import Swarm.Language.Requirements qualified as R
9395
import Swarm.Language.Syntax
9496
import Swarm.Language.Syntax.Direction
9597
import Swarm.Language.Text.Markdown qualified as Markdown
9698
import Swarm.Language.Value
9799
import Swarm.Log
98100
import Swarm.Pretty (prettyText)
101+
import Swarm.ResourceLoading (getDataFileNameSafe)
99102
import Swarm.Util hiding (both)
103+
import Swarm.Util.Effect (throwToMaybe)
100104
import Swarm.Util.Lens (inherit)
101105
import Text.Megaparsec (runParser)
102106
import Witch (From (from), into)
@@ -1212,6 +1216,28 @@ execConst runChildProg c vs s k = do
12121216
time <- use $ temporal . ticks
12131217
return $ Waiting (addTicks (numItems + 1) time) (mkReturn ())
12141218
_ -> badConst
1219+
-- run can take both types of text inputs
1220+
-- with and without file extension as in
1221+
-- "./path/to/file.sw" and "./path/to/file"
1222+
Run -> case vs of
1223+
[VText fileName] -> do
1224+
let filePath = into @String fileName
1225+
sData <- throwToMaybe @SystemFailure $ getDataFileNameSafe Script filePath
1226+
sDataSW <- throwToMaybe @SystemFailure $ getDataFileNameSafe Script (filePath <> ".sw")
1227+
mf <- sendIO $ mapM readFileMay $ [filePath, filePath <> ".sw"] <> catMaybes [sData, sDataSW]
1228+
1229+
f <- msum mf `isJustOrFail` ["File not found:", fileName]
1230+
1231+
res <- sendIO $ processTerm (into @Text f)
1232+
mt <- res `isRightOr` \err -> cmdExn Run ["Error in", fileName, "\n", prettyText err]
1233+
1234+
case mt of
1235+
Nothing -> return $ mkReturn ()
1236+
Just (_, t) -> do
1237+
void $ traceLog CmdStatus Info "run: OK."
1238+
cesk <- use machine
1239+
return $ continue M.empty t cesk
1240+
_ -> badConst
12151241
Not -> case vs of
12161242
[VBool b] -> return $ Out (VBool (not b)) s k
12171243
_ -> badConst

src/swarm-lang/Swarm/Language/Capability.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ constCaps = \case
126126
Undefined -> Nothing
127127
Use -> Nothing -- Recipes alone shall dictate whether things can be "used"
128128
View -> Nothing -- TODO: #17 should require equipping an antenna
129+
-- TODO: #495
130+
-- the require command will be inlined once the Issue is fixed
131+
-- so the capabilities of the run commands will be checked instead
132+
Run -> Nothing
129133
-- Some God-like abilities.
130134
As -> Just CGod
131135
Create -> Just CGod

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ data Comment = Comment
5656
, commentSituation :: CommentSituation
5757
, commentText :: Text
5858
}
59-
deriving (Eq, Show, Generic, Data, ToJSON, Hashable)
59+
deriving (Eq, Show, Generic, Data, ToJSON, FromJSON, Hashable)
6060

6161
instance PrettyPrec Comment where
6262
prettyPrec _ (Comment _ LineComment _ txt) = "//" <> pretty txt
@@ -78,6 +78,10 @@ instance ToJSON Comments where
7878
Empty -> True
7979
_ -> False
8080

81+
instance FromJSON Comments where
82+
parseJSON = A.genericParseJSON A.defaultOptions
83+
omittedField = Just Empty
84+
8185
instance Semigroup Comments where
8286
Comments b1 a1 <> Comments b2 a2 = Comments (b1 <> b2) (a1 <> a2)
8387

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@ data Const
204204
Setname
205205
| -- | Get a uniformly random integer.
206206
Random
207+
| -- Modules
208+
209+
-- | Run a program loaded from a file.
210+
Run
207211
| -- Language built-ins
208212

209213
-- | If-expressions.
@@ -778,6 +782,7 @@ constInfo c = case c of
778782
Random ->
779783
command 1 Intangible . doc (Set.singleton $ Query PRNG) "Get a uniformly random integer." $
780784
["The random integer will be chosen from the range 0 to n-1, exclusive of the argument."]
785+
Run -> command 1 long $ shortDoc (Set.singleton $ Mutation $ RobotChange BehaviorChange) "Run a program loaded from a file."
781786
Pure -> command 1 Intangible $ shortDoc Set.empty "Create a pure `Cmd a`{=type} computation that yields the given value."
782787
Try -> command 2 Intangible $ shortDoc Set.empty "Execute a command, catching errors."
783788
Undefined -> function 0 $ shortDoc Set.empty "A value of any type, that is evaluated as error."

src/swarm-lang/Swarm/Language/Typecheck.hs

Lines changed: 60 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ module Swarm.Language.Typecheck (
2929
LocatedTCFrame (..),
3030
TCStack,
3131
withFrame,
32+
popFrame,
3233

3334
-- * Typechecking monad
3435
fresh,
@@ -133,6 +134,13 @@ type TCStack = [LocatedTCFrame]
133134
withFrame :: Has (Reader TCStack) sig m => SrcLoc -> TCFrame -> m a -> m a
134135
withFrame l f = local (LocatedTCFrame l f :)
135136

137+
-- | Locally pop a frame from the typechecking stack.
138+
popFrame :: Has (Reader TCStack) sig m => m a -> m a
139+
popFrame = local @TCStack pop
140+
where
141+
pop (_ : fs) = fs
142+
pop [] = []
143+
136144
------------------------------------------------------------
137145
-- Type source
138146

@@ -1214,6 +1222,7 @@ inferConst c = run . runReader @TVCtx Ctx.empty . quantify $ case c of
12141222
Whoami -> [tyQ| Cmd Text |]
12151223
Setname -> [tyQ| Text -> Cmd Unit |]
12161224
Random -> [tyQ| Int -> Cmd Int |]
1225+
Run -> [tyQ| Text -> Cmd Unit |]
12171226
If -> [tyQ| Bool -> {a} -> {a} -> a |]
12181227
Inl -> [tyQ| a -> a + b |]
12191228
Inr -> [tyQ| b -> a + b |]
@@ -1369,52 +1378,57 @@ check s@(CSyntax l t cs) expected = addLocToTypeErr l $ case t of
13691378
let Syntax _ tt1 _ _ = t1
13701379
reqs = requirements tdCtx reqCtx tt1
13711380

1372-
-- If we are checking a 'def', ensure t2 has a command type. This ensures that
1373-
-- something like 'def ... end; x + 3' is not allowed, since this
1374-
-- would result in the whole thing being wrapped in pure, like
1375-
-- 'pure (def ... end; x + 3)', which means the def would be local and
1376-
-- not persist to the next REPL input, which could be surprising.
1377-
--
1378-
-- On the other hand, 'let x = y in x + 3' is perfectly fine.
1379-
when (ls == LSDef) $ void $ decomposeCmdTy t2 (Expected, expected)
1380-
1381-
-- Now check the type of the body, under a context extended with
1382-
-- the type and requirements of the bound variable.
1383-
t2' <-
1384-
withBinding (lvVar x) upty $
1385-
withBinding (lvVar x) reqs $
1386-
check t2 expected
1387-
1388-
-- Make sure none of the generated skolem variables have escaped.
1389-
ask @UCtx >>= traverse_ (noSkolems l skolems)
1390-
1391-
-- Annotate a 'def' with requirements, but not 'let'. The reason
1392-
-- is so that let introduces truly "local" bindings which never
1393-
-- persist, but def introduces "global" bindings. Variables bound
1394-
-- in the environment can only be used to typecheck future REPL
1395-
-- terms if the environment holds not only a value but also a type
1396-
-- + requirements for them. For example:
1397-
--
1398-
-- > def x : Int = 3 end; pure (x + 2)
1399-
-- 5
1400-
-- > x
1401-
-- 3
1402-
-- > let y : Int = 3 in y + 2
1403-
-- 5
1404-
-- > y
1405-
-- 1:1: Unbound variable y
1406-
-- > let y = 3 in def x = 5 end; pure (x + y)
1407-
-- 8
1408-
-- > y
1409-
-- 1:1: Unbound variable y
1410-
-- > x
1411-
-- 5
1412-
let mreqs = case ls of
1413-
LSDef -> Just reqs
1414-
LSLet -> Nothing
1415-
1416-
-- Return the annotated let.
1417-
return $ Syntax l (SLet ls r x mxTy mqxTy mreqs t1' t2') cs expected
1381+
-- Locally pop the typechecking frame that said we were checking
1382+
-- the definition of a let while typechecking the body. Even
1383+
-- though the body is a syntactic subterm of the let, we don't
1384+
-- want to see a bunch of nested typechecking frames.
1385+
popFrame $ do
1386+
-- If we are checking a 'def', ensure t2 has a command type. This ensures that
1387+
-- something like 'def ... end; x + 3' is not allowed, since this
1388+
-- would result in the whole thing being wrapped in pure, like
1389+
-- 'pure (def ... end; x + 3)', which means the def would be local and
1390+
-- not persist to the next REPL input, which could be surprising.
1391+
--
1392+
-- On the other hand, 'let x = y in x + 3' is perfectly fine.
1393+
when (ls == LSDef) $ void $ decomposeCmdTy t2 (Expected, expected)
1394+
1395+
-- Now check the type of the body, under a context extended with
1396+
-- the type and requirements of the bound variable.
1397+
t2' <-
1398+
withBinding (lvVar x) upty $
1399+
withBinding (lvVar x) reqs $
1400+
check t2 expected
1401+
1402+
-- Make sure none of the generated skolem variables have escaped.
1403+
ask @UCtx >>= traverse_ (noSkolems l skolems)
1404+
1405+
-- Annotate a 'def' with requirements, but not 'let'. The reason
1406+
-- is so that let introduces truly "local" bindings which never
1407+
-- persist, but def introduces "global" bindings. Variables bound
1408+
-- in the environment can only be used to typecheck future REPL
1409+
-- terms if the environment holds not only a value but also a type
1410+
-- + requirements for them. For example:
1411+
--
1412+
-- > def x : Int = 3 end; pure (x + 2)
1413+
-- 5
1414+
-- > x
1415+
-- 3
1416+
-- > let y : Int = 3 in y + 2
1417+
-- 5
1418+
-- > y
1419+
-- 1:1: Unbound variable y
1420+
-- > let y = 3 in def x = 5 end; pure (x + y)
1421+
-- 8
1422+
-- > y
1423+
-- 1:1: Unbound variable y
1424+
-- > x
1425+
-- 5
1426+
let mreqs = case ls of
1427+
LSDef -> Just reqs
1428+
LSLet -> Nothing
1429+
1430+
-- Return the annotated let.
1431+
return $ Syntax l (SLet ls r x mxTy mqxTy mreqs t1' t2') cs expected
14181432

14191433
-- Kind-check a type definition and then check the body under an
14201434
-- extended context.

0 commit comments

Comments
 (0)