@@ -32,15 +32,18 @@ import Network.HTTP.Simple (getResponseBody, httpBS, parseRequest)
3232import Swarm.Failure (Asset (.. ), AssetData (.. ), Entry (.. ), LoadingFailure (.. ), SystemFailure (.. ))
3333import Swarm.Language.Parser (readTerm' )
3434import Swarm.Language.Parser.Core (defaultParserConfig , importLoc )
35- import Swarm.Language.Syntax ( ImportPhaseFor , Phase ( .. ), SwarmType , Syntax )
35+ import Swarm.Language.Syntax
3636import Swarm.Language.Syntax.Import hiding (ImportPhase (.. ))
3737import Swarm.Language.Syntax.Import qualified as Import
38- import Swarm.Language.Syntax.Util (Erasable (.. ), traverseSyntax )
38+ import Swarm.Language.Syntax.Util (Erasable (.. ))
3939import Swarm.Language.Types (TCtx , UCtx )
40+ import Swarm.Pretty (prettyText )
4041import Swarm.Util (readFileMayT , showT )
4142import Swarm.Util.Graph (findCycle )
4243import Witch (into )
4344
45+ type ResLoc = ImportLoc Import. Resolved
46+
4447-- | The context for a module, containing names and types of things
4548-- defined in the module (once typechecking has run).
4649type family ModuleCtx (phase :: Phase ) where
@@ -120,8 +123,6 @@ resolve' = traverseSyntax pure (throwError . DisallowedImport)
120123eraseSourceMap :: SourceMap Elaborated -> SourceMap Resolved
121124eraseSourceMap = M. map erase
122125
123- type ResLoc = ImportLoc Import. Resolved
124-
125126-- | Convert a 'SourceMap' into a suitable form for 'findCycle'.
126127toImportGraph :: SourceMap Resolved -> [(ResLoc , ResLoc , [ResLoc ])]
127128toImportGraph = map processNode . M. assocs
@@ -172,8 +173,8 @@ resolveImport parent loc = do
172173 add $ S. singleton canonicalLoc
173174
174175 srcMap <- get @ (SourceMap Resolved )
175- case M. lookup canonicalLoc srcMap of
176- Just _ -> pure () -- Already loaded - do nothing
176+ resMod <- case M. lookup canonicalLoc srcMap of
177+ Just m -> pure m -- Already loaded - do nothing
177178 Nothing -> do
178179 -- Record this import loc in the source map using a temporary, empty module,
179180 -- to prevent it from attempting to load itself recursively
@@ -188,14 +189,35 @@ resolveImport parent loc = do
188189 let (imps, mt') = sequence mres
189190
190191 -- Finally, record the loaded module in the SourceMap.
191- modify @ (SourceMap Resolved ) (M. insert canonicalLoc $ Module mt' () imps)
192+ let m = Module mt' () imps
193+ modify @ (SourceMap Resolved ) (M. insert canonicalLoc m)
194+
195+ pure m
192196
193- -- XXX make sure imports contain ONLY defs + more imports?
194- -- Otherwise we can't cache their values---we would have to
195- -- re-execute them every time they are imported.
197+ -- Make sure imports are pure, i.e. contain ONLY defs + imports.
198+ validateImport canonicalLoc resMod
196199
197200 pure canonicalLoc
198201
202+ -- | Validate the source code of the import to ensure that it contains
203+ -- *only* imports and definitions. This is so we do not have to worry
204+ -- about side-effects happening every time a module is imported. In
205+ -- other words, imports must be pure so we can get away with only
206+ -- evaluating them once.
207+ validateImport :: forall sig m . (Has (Throw SystemFailure ) sig m ) => ResLoc -> Module Resolved -> m ()
208+ validateImport loc = maybe (pure () ) validate . moduleTerm
209+ where
210+ validate :: Syntax Resolved -> m ()
211+ validate = validateTerm . _sTerm
212+
213+ validateTerm :: Term Resolved -> m ()
214+ validateTerm = \ case
215+ SLet LSDef _ _ _ _ _ _ t -> validate t
216+ SImportIn _ t -> validate t
217+ STydef _ _ _ t -> validate t
218+ TConst Noop -> pure ()
219+ t -> throwError $ ImpureImport loc (prettyText t)
220+
199221-- | Try to read and parse a term from a specific import location,
200222-- either over the network or on disk.
201223readLoc ::
0 commit comments