on master help sign in
Added simple library packaging system

Now used for the prelude (see lib/base.ipkg)

commit1e523240084951f9729912ad8560081b59e85f3b authorEdwin Brady <eb@cs.st-andrews.ac.uk> dateTue 25 Sep 2012, 17:34 (14 years ago) parent2832517
15 files changed+341−49
CHANGELOG+6 Makefile+1−1 idris.cabal+3−1 lib/Makefile+3−15 lib/base.ipkg+15 lib/prelude/complex.idr+1−1 rts/libtest.c+1 src/IRTS/CodegenC.hs+1−1 src/Idris/AbsSyntax.hs+8−3 src/Idris/AbsSyntaxTree.hs+6−1 src/Idris/REPL.hs+49 src/Main.hs+10−25 src/Pkg/PParser.hs+102 src/Pkg/Package.hs+128 src/Util/System.hs+7−1
CHANGELOG+6
@@ -1,7 +1,13 @@
11New in 0.9.4:
22-------------
33
4+User visible changes:
5+
6+* Simple packaging system
7+
8+Internal changes:
49
10+* Improve overloading resolution (especially where this is a type error)
511
612New in 0.9.3:
713-------------
Makefile+1−1
@@ -15,7 +15,7 @@ test : .PHONY
1515 make -C test
1616
1717relib: .PHONY
18− make -C lib clean
18+ make -C lib IDRIS=../dist/build/idris/idris clean
1919 make -C lib IDRIS=../dist/build/idris/idris
2020
2121linecount : .PHONY
idris.cabal+3−1
@@ -1,5 +1,5 @@
11Name: idris
2−Version: 0.9.3.1
2+Version: 0.9.4
33License: BSD3
44License-file: LICENSE
55Author: Edwin Brady
@@ -42,6 +42,7 @@ Build-type: Custom
4242
4343Data-files: rts/libidris_rts.a rts/idris_rts.h rts/idris_gc.h
4444 rts/idris_stdfgn.h rts/idris_main.c rts/idris_gmp.h
45+ rts/libtest.c
4546Extra-source-files: lib/Makefile lib/*.idr lib/prelude/*.idr lib/network/*.idr
4647 lib/control/monad/*.idr lib/language/*.idr
4748 tutorial/examples/*.idr
@@ -69,6 +70,7 @@ Executable idris
6970 Idris.DataOpts, Idris.Transforms, Idris.DSL,
7071
7172 Util.Pretty, Util.System,
73+ Pkg.Package, Pkg.PParser,
7274
7375 IRTS.Lang, IRTS.LParser, IRTS.Bytecode, IRTS.Simplified,
7476 IRTS.CodegenC, IRTS.Defunctionalise, IRTS.Compiler,
lib/Makefile+3−15
@@ -1,26 +1,14 @@
11
22check: .PHONY
3− $(IDRIS) --noprelude --verbose --check checkall.idr
3+ $(IDRIS) --build base.ipkg
44
55recheck: clean check
66
77install: check
8− mkdir -p $(TARGET)/prelude
9− mkdir -p $(TARGET)/network
10− mkdir -p $(TARGET)/language
11− mkdir -p $(TARGET)/control/monad
12− install *.ibc $(TARGET)
13− install prelude/*.ibc $(TARGET)/prelude
14− install network/*.ibc $(TARGET)/network
15− install language/*.ibc $(TARGET)/language
16− install control/monad/*.ibc $(TARGET)/control/monad
8+ $(IDRIS) --install base.ipkg
179
1810clean: .PHONY
19− rm -f *.ibc
20− rm -f prelude/*.ibc
21− rm -f network/*.ibc
22− rm -f language/*.ibc
23− rm -f control/monad/*.ibc
11+ $(IDRIS) --clean base.ipkg
2412
2513linecount: .PHONY
2614 wc -l *.idr network/*.idr language/*.idr prelude/*.idr control/monad/*.idr
lib/base.ipkgnew file+15
@@ -0,0 +1,15 @@
1+package base
2+
3+opts = "--noprelude"
4+modules = builtins, prelude, io, system,
5+
6+ prelude.algebra, prelude.cast, prelude.nat, prelude.fin,
7+ prelude.list, prelude.maybe, prelude.monad, prelude.applicative,
8+ prelude.either, prelude.vect, prelude.strings, prelude.char,
9+ prelude.heap, prelude.complex,
10+
11+ network.cgi,
12+
13+ language.reflection,
14+
15+ control.monad.identity, control.monad.state
lib/prelude/complex.idr+1−1
@@ -6,7 +6,7 @@
66module prelude.complex
77
88import builtins
9−
9+import prelude
1010
1111------------------------------ Rectangular form
1212
rts/libtest.cnew file+1
@@ -0,0 +1 @@
1+int main() {}
src/IRTS/CodegenC.hs+1−1
@@ -38,7 +38,7 @@ codegenC defs out exec incs objs libs dbg
3838 hFlush tmph
3939 hClose tmph
4040 let useclang = False
41− let comp = if useclang then "clang" else "gcc"
41+ comp <- getCC
4242 let gcc = comp ++ " -I. " ++ objs ++ " -x c " ++
4343 (if exec then "" else " - c ") ++
4444 gccDbg dbg ++
src/Idris/AbsSyntax.hs+8−3
@@ -257,6 +257,12 @@ setIBCSubDir fp = do i <- get
257257valIBCSubDir :: IState -> Idris FilePath
258258valIBCSubDir i = return (opt_ibcsubdir (idris_options i))
259259
260+addImportDir :: FilePath -> Idris ()
261+addImportDir fp = do i <- get
262+ let opts = idris_options i
263+ let opt' = opts { opt_importdirs = fp : opt_importdirs opts }
264+ put (i { idris_options = opt' })
265+
260266setImportDirs :: [FilePath] -> Idris ()
261267setImportDirs fps = do i <- get
262268 let opts = idris_options i
@@ -264,9 +270,8 @@ setImportDirs fps = do i <- get
264270 put (i { idris_options = opt' })
265271
266272allImportDirs :: IState -> Idris [FilePath]
267−allImportDirs i = do datadir <- liftIO $ getDataDir
268− let optdirs = opt_importdirs (idris_options i)
269− return ("." : (optdirs ++ [datadir]))
273+allImportDirs i = do let optdirs = opt_importdirs (idris_options i)
274+ return ("." : optdirs)
270275
271276impShow :: Idris Bool
272277impShow = do i <- get
src/Idris/AbsSyntaxTree.hs+6−1
@@ -165,9 +165,14 @@ data Opt = Filename String
165165 | Verbose
166166 | IBCSubDir String
167167 | ImportDir String
168+ | PkgBuild String
169+ | PkgInstall String
170+ | PkgClean String
171+ | WarnOnly
172+ | Pkg String
168173 | BCAsm String
169174 | FOVM String
170− deriving Eq
175+ deriving (Show, Eq)
171176
172177
173178-- Parsed declarations
src/Idris/REPL.hs+49
@@ -365,6 +365,35 @@ displayHelp = let vstr = showVersion version in
365365 l ++ take (c1 - length l) (repeat ' ') ++
366366 m ++ take (c2 - length m) (repeat ' ') ++ r ++ "\n"
367367
368+parseArgs :: [String] -> [Opt]
369+parseArgs [] = []
370+parseArgs ("--log":lvl:ns) = OLogging (read lvl) : (parseArgs ns)
371+parseArgs ("--noprelude":ns) = NoPrelude : (parseArgs ns)
372+parseArgs ("--check":ns) = NoREPL : (parseArgs ns)
373+parseArgs ("-o":n:ns) = NoREPL : Output n : (parseArgs ns)
374+parseArgs ("-no":n:ns) = NoREPL : NewOutput n : (parseArgs ns)
375+parseArgs ("--typecase":ns) = TypeCase : (parseArgs ns)
376+parseArgs ("--typeintype":ns) = TypeInType : (parseArgs ns)
377+parseArgs ("--nocoverage":ns) = NoCoverage : (parseArgs ns)
378+parseArgs ("--errorcontext":ns) = ErrContext : (parseArgs ns)
379+parseArgs ("--help":ns) = Usage : (parseArgs ns)
380+parseArgs ("--link":ns) = ShowLibs : (parseArgs ns)
381+parseArgs ("--libdir":ns) = ShowLibdir : (parseArgs ns)
382+parseArgs ("--include":ns) = ShowIncs : (parseArgs ns)
383+parseArgs ("--version":ns) = Ver : (parseArgs ns)
384+parseArgs ("--verbose":ns) = Verbose : (parseArgs ns)
385+parseArgs ("--ibcsubdir":n:ns) = IBCSubDir n : (parseArgs ns)
386+parseArgs ("-i":n:ns) = ImportDir n : (parseArgs ns)
387+parseArgs ("--warn":ns) = WarnOnly : (parseArgs ns)
388+parseArgs ("--package":n:ns) = Pkg n : (parseArgs ns)
389+parseArgs ("-p":n:ns) = Pkg n : (parseArgs ns)
390+parseArgs ("--build":n:ns) = PkgBuild n : (parseArgs ns)
391+parseArgs ("--install":n:ns) = PkgInstall n : (parseArgs ns)
392+parseArgs ("--clean":n:ns) = PkgClean n : (parseArgs ns)
393+parseArgs ("--bytecode":n:ns) = NoREPL : BCAsm n : (parseArgs ns)
394+parseArgs ("--fovm":n:ns) = NoREPL : FOVM n : (parseArgs ns)
395+parseArgs (n:ns) = Filename n : (parseArgs ns)
396+
368397help =
369398 [ (["Command"], "Arguments", "Purpose"),
370399 ([""], "", ""),
@@ -402,6 +431,7 @@ idrisMain opts =
402431 let importdirs = opt getImportDir opts
403432 let bcs = opt getBC opts
404433 let vm = opt getFOVM opts
434+ let pkgdirs = opt getPkgDir opts
405435 setREPL runrepl
406436 setVerbose runrepl
407437 when (Verbose `elem` opts) $ setVerbose True
@@ -418,6 +448,8 @@ idrisMain opts =
418448 [] -> setIBCSubDir ""
419449 (d:_) -> setIBCSubDir d
420450 setImportDirs importdirs
451+ addPkgDir "base"
452+ mapM_ addPkgDir pkgdirs
421453 elabPrims
422454 when (not (NoPrelude `elem` opts)) $ do x <- loadModule "prelude"
423455 return ()
@@ -442,6 +474,10 @@ idrisMain opts =
442474 makeOption ErrContext = setErrContext True
443475 makeOption _ = return ()
444476
477+ addPkgDir :: String -> Idris ()
478+ addPkgDir p = do ddir <- liftIO $ getDataDir
479+ addImportDir (ddir ++ "/" ++ p)
480+
445481getFile :: Opt -> Maybe String
446482getFile (Filename str) = Just str
447483getFile _ = Nothing
@@ -470,6 +506,19 @@ getImportDir :: Opt -> Maybe String
470506getImportDir (ImportDir str) = Just str
471507getImportDir _ = Nothing
472508
509+getPkgDir :: Opt -> Maybe String
510+getPkgDir (Pkg str) = Just str
511+getPkgDir _ = Nothing
512+
513+getPkg :: Opt -> Maybe (Bool, String)
514+getPkg (PkgBuild str) = Just (False, str)
515+getPkg (PkgInstall str) = Just (True, str)
516+getPkg _ = Nothing
517+
518+getPkgClean :: Opt -> Maybe String
519+getPkgClean (PkgClean str) = Just str
520+getPkgClean _ = Nothing
521+
473522opt :: (Opt -> Maybe a) -> [Opt] -> [a]
474523opt = mapMaybe
475524
src/Main.hs+10−25
@@ -25,13 +25,15 @@ import Idris.Primitives
2525import Idris.Imports
2626import Idris.Error
2727
28+import Pkg.Package
29+
2830import Paths_idris
2931
3032-- Main program reads command line options, parses the main program, and gets
3133-- on with the REPL.
3234
3335main = do xs <- getArgs
34− opts <- parseArgs xs
36+ let opts = parseArgs xs
3537 runInputT defaultSettings $ execStateT (runIdris opts) idrisInit
3638
3739runIdris :: [Opt] -> Idris ()
@@ -41,7 +43,13 @@ runIdris opts = do
4143 when (ShowIncs `elem` opts) $ liftIO showIncs
4244 when (ShowLibs `elem` opts) $ liftIO showLibs
4345 when (ShowLibdir `elem` opts) $ liftIO showLibdir
44− idrisMain opts -- in Idris.REPL
46+ case opt getPkgClean opts of
47+ [] -> return ()
48+ fs -> do liftIO $ mapM_ cleanPkg fs
49+ liftIO $ exitWith ExitSuccess
50+ case opt getPkg opts of
51+ [] -> idrisMain opts -- in Idris.REPL
52+ fs -> liftIO $ mapM_ (buildPkg (WarnOnly `elem` opts)) fs
4553
4654usage = do putStrLn usagemsg
4755 exitWith ExitSuccess
@@ -61,29 +69,6 @@ showIncs = do dir <- getDataDir
6169 putStrLn $ "-I" ++ dir ++ "/rts"
6270 exitWith ExitSuccess
6371
64−parseArgs :: [String] -> IO [Opt]
65−parseArgs [] = return []
66−parseArgs ("--log":lvl:ns) = liftM (OLogging (read lvl) : ) (parseArgs ns)
67−parseArgs ("--noprelude":ns) = liftM (NoPrelude : ) (parseArgs ns)
68−parseArgs ("--check":ns) = liftM (NoREPL : ) (parseArgs ns)
69−parseArgs ("-o":n:ns) = liftM (\x -> NoREPL : Output n : x) (parseArgs ns)
70−parseArgs ("-no":n:ns) = liftM (\x -> NoREPL : NewOutput n : x) (parseArgs ns)
71−parseArgs ("--typecase":ns) = liftM (TypeCase : ) (parseArgs ns)
72−parseArgs ("--typeintype":ns) = liftM (TypeInType : ) (parseArgs ns)
73−parseArgs ("--nocoverage":ns) = liftM (NoCoverage : ) (parseArgs ns)
74−parseArgs ("--errorcontext":ns) = liftM (ErrContext : ) (parseArgs ns)
75−parseArgs ("--help":ns) = liftM (Usage : ) (parseArgs ns)
76−parseArgs ("--link":ns) = liftM (ShowLibs : ) (parseArgs ns)
77−parseArgs ("--libdir":ns) = liftM (ShowLibdir : ) (parseArgs ns)
78−parseArgs ("--include":ns) = liftM (ShowIncs : ) (parseArgs ns)
79−parseArgs ("--version":ns) = liftM (Ver : ) (parseArgs ns)
80−parseArgs ("--verbose":ns) = liftM (Verbose : ) (parseArgs ns)
81−parseArgs ("--ibcsubdir":n:ns) = liftM (IBCSubDir n : ) (parseArgs ns)
82−parseArgs ("-i":n:ns) = liftM (ImportDir n : ) (parseArgs ns)
83−parseArgs ("--bytecode":n:ns) = liftM (\x -> NoREPL : BCAsm n : x) (parseArgs ns)
84−parseArgs ("--fovm":n:ns) = liftM (\x -> NoREPL : FOVM n : x) (parseArgs ns)
85−parseArgs (n:ns) = liftM (Filename n : ) (parseArgs ns)
86−
8772usagemsg = "Idris version " ++ ver ++ "\n" ++
8873 "--------------" ++ map (\x -> '-') ver ++ "\n" ++
8974 "Usage: idris [input file] [options]\n" ++
src/Pkg/PParser.hsnew file+102
@@ -0,0 +1,102 @@
1+module Pkg.PParser where
2+
3+import Core.CoreParser
4+import Core.TT
5+import Idris.REPL
6+import Idris.AbsSyntaxTree
7+
8+import Paths_idris
9+
10+import Text.ParserCombinators.Parsec
11+import Text.ParserCombinators.Parsec.Error
12+import Text.ParserCombinators.Parsec.Expr
13+import Text.ParserCombinators.Parsec.Language
14+import qualified Text.ParserCombinators.Parsec.Token as PTok
15+
16+type TokenParser a = PTok.TokenParser a
17+
18+type PParser = GenParser Char PkgDesc
19+
20+lexer :: TokenParser PkgDesc
21+lexer = PTok.makeTokenParser idrisDef
22+
23+whiteSpace= PTok.whiteSpace lexer
24+lexeme = PTok.lexeme lexer
25+symbol = PTok.symbol lexer
26+natural = PTok.natural lexer
27+parens = PTok.parens lexer
28+semi = PTok.semi lexer
29+comma = PTok.comma lexer
30+identifier= PTok.identifier lexer
31+reserved = PTok.reserved lexer
32+operator = PTok.operator lexer
33+reservedOp= PTok.reservedOp lexer
34+integer = PTok.integer lexer
35+float = PTok.float lexer
36+strlit = PTok.stringLiteral lexer
37+chlit = PTok.charLiteral lexer
38+lchar = lexeme.char
39+
40+data PkgDesc = PkgDesc { pkgname :: String,
41+ libdeps :: [String],
42+ objs :: [String],
43+ makefile :: Maybe String,
44+ idris_opts :: [Opt],
45+ sourcedir :: String,
46+ modules :: [Name],
47+ idris_main :: Name,
48+ execout :: Maybe String
49+ }
50+ deriving Show
51+
52+defaultPkg = PkgDesc "" [] [] Nothing [] "" [] (UN "") Nothing
53+
54+parseDesc :: FilePath -> IO PkgDesc
55+parseDesc fp = do p <- readFile fp
56+ case runParser pPkg defaultPkg fp p of
57+ Left err -> fail (show err)
58+ Right x -> return x
59+
60+pPkg :: PParser PkgDesc
61+pPkg = do reserved "package"; p <- identifier
62+ st <- getState
63+ setState (st { pkgname = p })
64+ many1 pClause
65+ st <- getState
66+ return st
67+
68+pClause :: PParser ()
69+pClause = do reserved "executable"; lchar '=';
70+ exec <- iName []
71+ st <- getState
72+ setState (st { execout = Just (show exec) })
73+ <|> do reserved "main"; lchar '=';
74+ main <- iName []
75+ st <- getState
76+ setState (st { idris_main = main })
77+ <|> do reserved "sourcedir"; lchar '=';
78+ src <- identifier
79+ st <- getState
80+ setState (st { sourcedir = src })
81+ <|> do reserved "opts"; lchar '=';
82+ opts <- strlit
83+ st <- getState
84+ let args = parseArgs (words opts)
85+ setState (st { idris_opts = args })
86+ <|> do reserved "modules"; lchar '=';
87+ ms <- sepBy1 (iName []) (lchar ',')
88+ st <- getState
89+ setState (st { modules = modules st ++ ms })
90+ <|> do reserved "libs"; lchar '=';
91+ ls <- sepBy1 identifier (lchar ',')
92+ st <- getState
93+ setState (st { libdeps = libdeps st ++ ls })
94+ <|> do reserved "objs"; lchar '=';
95+ ls <- sepBy1 identifier (lchar ',')
96+ st <- getState
97+ setState (st { objs = libdeps st ++ ls })
98+ <|> do reserved "makefile"; lchar '=';
99+ mk <- iName []
100+ st <- getState
101+ setState (st { makefile = Just (show mk) })
102+
src/Pkg/Package.hsnew file+128
@@ -0,0 +1,128 @@
1+module Pkg.Package where
2+
3+import System.Process
4+import System.Directory
5+import System.Exit
6+import System.IO
7+
8+import Util.System
9+
10+import Control.Monad
11+import Data.List
12+
13+import Core.TT
14+import Idris.REPL
15+import Idris.AbsSyntax
16+
17+import Pkg.PParser
18+
19+import Paths_idris
20+
21+-- To build a package:
22+-- * read the package description
23+-- * check all the library dependencies exist
24+-- * invoke the makefile if there is one
25+-- * invoke idris on each module, with idris_opts
26+-- * install everything into datadir/pname, if install flag is set
27+
28+buildPkg :: Bool -> (Bool, FilePath) -> IO ()
29+buildPkg warnonly (install, fp)
30+ = do pkgdesc <- parseDesc fp
31+ ok <- mapM (testLib warnonly (pkgname pkgdesc)) (libdeps pkgdesc)
32+ when (and ok) $
33+ do make (makefile pkgdesc)
34+ dir <- getCurrentDirectory
35+ setCurrentDirectory $ dir ++ "/" ++ sourcedir pkgdesc
36+ case (execout pkgdesc) of
37+ Nothing -> buildMods (NoREPL : Verbose : idris_opts pkgdesc)
38+ (modules pkgdesc)
39+ Just o -> do let exec = dir ++ "/" ++ o
40+ buildMod
41+ (NoREPL : Verbose : Output exec : idris_opts pkgdesc)
42+ (idris_main pkgdesc)
43+ setCurrentDirectory dir
44+ when install $ installPkg pkgdesc
45+
46+cleanPkg :: FilePath -> IO ()
47+cleanPkg fp
48+ = do pkgdesc <- parseDesc fp
49+ clean (makefile pkgdesc)
50+ dir <- getCurrentDirectory
51+ setCurrentDirectory $ dir ++ "/" ++ sourcedir pkgdesc
52+ mapM_ rmIBC (modules pkgdesc)
53+ case execout pkgdesc of
54+ Nothing -> return ()
55+ Just s -> do let exec = dir ++ "/" ++ s
56+ putStrLn $ "Removing " ++ exec
57+ system $ "rm -f " ++ exec
58+ return ()
59+
60+installPkg :: PkgDesc -> IO ()
61+installPkg pkgdesc
62+ = do dir <- getCurrentDirectory
63+ setCurrentDirectory $ dir ++ "/" ++ sourcedir pkgdesc
64+ case (execout pkgdesc) of
65+ Nothing -> mapM_ (installIBC (pkgname pkgdesc)) (modules pkgdesc)
66+ Just o -> return () -- do nothing, keep executable locally, for noe
67+
68+buildMod :: [Opt] -> Name -> IO ()
69+buildMod opts n = do let f = map slash $ show n
70+ idris (Filename f : opts)
71+ return ()
72+ where slash '.' = '/'
73+ slash x = x
74+
75+buildMods :: [Opt] -> [Name] -> IO ()
76+buildMods opts ns = do let f = map ((map slash) . show) ns
77+ idris (map Filename f ++ opts)
78+ return ()
79+ where slash '.' = '/'
80+ slash x = x
81+
82+testLib :: Bool -> String -> String -> IO Bool
83+testLib warn p f
84+ = do d <- getDataDir
85+ gcc <- getCC
86+ (tmpf, tmph) <- tempfile
87+ hClose tmph
88+ e <- system $ gcc ++ " " ++ d ++ "/rts/libtest.c -l" ++ f ++ " -o " ++ tmpf
89+ case e of
90+ ExitSuccess -> return True
91+ _ -> do if warn
92+ then do putStrLn $ "Not building " ++ p ++
93+ " due to missing library " ++ f
94+ return False
95+ else fail $ "Missing library " ++ f
96+
97+rmIBC :: Name -> IO ()
98+rmIBC m = do let f = toIBCFile m
99+ putStrLn $ "Removing " ++ f
100+ system $ "rm -f " ++ f
101+ return ()
102+
103+toIBCFile (UN n) = n ++ ".ibc"
104+toIBCFile (NS n ns) = concat (intersperse "/" (reverse ns)) ++ "/" ++ toIBCFile n
105+
106+installIBC :: String -> Name -> IO ()
107+installIBC p m = do let f = toIBCFile m
108+ d <- getDataDir
109+ let destdir = d ++ "/" ++ p ++ "/" ++ getDest m
110+ putStrLn $ "Installing " ++ f ++ " to " ++ destdir
111+ system $ "mkdir -p " ++ destdir
112+ system $ "install " ++ f ++ " " ++ destdir
113+ return ()
114+ where getDest (UN n) = ""
115+ getDest (NS n ns) = concat (intersperse "/" (reverse ns)) ++ "/" ++ getDest n
116+
117+make :: Maybe String -> IO ()
118+make Nothing = return ()
119+make (Just s) = do system $ "make -f " ++ s
120+ return ()
121+
122+clean :: Maybe String -> IO ()
123+clean Nothing = return ()
124+clean (Just s) = do system $ "make -f " ++ s ++ " clean"
125+ return ()
126+
127+
128+
src/Util/System.hs+7−1
@@ -1,5 +1,5 @@
11{-# LANGUAGE CPP #-}
2−module Util.System(tempfile,environment) where
2+module Util.System(tempfile,environment,getCC) where
33
44-- System helper functions.
55
@@ -16,6 +16,12 @@ catchIO = CE.catch
1616catchIO = catch
1717#endif
1818
19+getCC :: IO String
20+getCC = do env <- environment "IDRIS_CC"
21+ case env of
22+ Nothing -> return "gcc"
23+ Just cc -> return cc
24+
1925tempfile :: IO (FilePath, Handle)
2026tempfile = do env <- environment "TMPDIR"
2127 let dir = case env of