on master help sign in
Merge remote-tracking branch 'upstream/master' into deprecated-parser-features
commitc20e139882f9586c1dc3d5697a69f5ba2f5c93fc authorJason Felice <jason.m.felice@gmail.com> dateMon 18 Dec 2017, 10:11 (9 years ago) parent4f1955324f580d
47 files changed+1236−161
CHANGELOG.md+3 libs/contrib/Control/ST.idr+6−11 libs/contrib/Control/ST/File.idr+247 libs/contrib/Data/Fuel.idr+18 libs/contrib/Data/List/Group.idr+24 libs/contrib/Text/Lexer.idr+59−15 libs/contrib/contrib.ipkg+2 libs/prelude/IO.idr+3−2 libs/prelude/Prelude/Interfaces.idr+2 libs/prelude/Prelude/List.idr+12−12 src/IRTS/CodegenC.hs+26−23 src/IRTS/Compiler.hs+14−7 src/IRTS/JavaScript/PrimOp.hs−2 src/IRTS/Lang.hs+97−34 src/IRTS/LangOpts.hs+265−50 src/Idris/Core/CaseTree.hs+52−1 stack-nightly.yaml+17 stack.yaml+6−1 test/README.md+1 test/TestData.hs+8 test/st001/expected+8 test/st001/run+6 test/st001/test001.idr+66 test/st001/testFile+2 test/st002/expected+8 test/st002/run+6 test/st002/test002.idr+66 test/st002/testFile+2 test/st003/expected+8 test/st003/run+6 test/st003/test003.idr+25 test/st003/testFile+2 test/st004/expected+6 test/st004/run+6 test/st004/test004.idr+24 test/st005/expected+6 test/st005/run+7 test/st005/test005.idr+33 test/st006/expected+5 test/st006/run+6 test/st006/test006.idr+37 test/st007/expected+6 test/st007/run+6 test/st007/test007.idr+24 test/views001/views001.idr+1−1 test/views001/views001a.idr+1−1 test/views002/views002.idr+1−1
CHANGELOG.md+3
@@ -55,6 +55,7 @@
5555 * Lowered the precedence of `>>=` to be below that of `<|>`.
5656+ Added some useful string manipulation functions to `Data.String.Extra`.
5757+ Added `Control.Delayed`, a module for conditionally making a type `Inf` or `Lazy`.
58++ Added `Data.Fuel`, which implements the `Fuel` data type and the partial `forever` function.
5859+ Added `Data.Bool.Extra`, a module with properties of boolean operations.
5960+ Moved core of `Text.Lexer` to `Text.Lexer.Core`. Added several new combinators
6061 and lexers to `Text.Lexer`.
@@ -70,6 +71,8 @@
7071+ Removed several deprecated items from the libraries shipped with Idris.
7172+ Moved `abs` from the `Neg` interface into its own `Abs` interface. `Nat`
7273 implements `Abs` with `abs = id`.
74++ Added `Control.ST.File`, an ST based implementation of the same behaviour
75+ implemented by `Effect.File` in the effects package.
7376
7477## Tool Updates
7578
libs/contrib/Control/ST.idr+6−11
@@ -1,7 +1,9 @@
11module Control.ST
22
3−import Language.Reflection.Utils
43import Control.IOExcept
4+import Language.Reflection.Utils
5+
6+import public Data.Fuel
57
68%default total
79
@@ -394,13 +396,6 @@ runST env (Call prog res_prf) k
394396runST env (Read lbl prf) k = k (lookupEnv prf env) env
395397runST env (Write lbl prf val) k = k () (updateEnv prf env val)
396398
397−export
398−data Fuel = Empty | More (Lazy Fuel)
399−
400−export partial
401−forever : Fuel
402−forever = More forever
403−
404399runSTLoop : Fuel -> Env invars -> STransLoop m a invars outfn ->
405400 (k : (x : a) -> Env (outfn x) -> m b) ->
406401 (onDry : m b) -> m b
@@ -589,10 +584,10 @@ run prog = runST [] prog (\res, env' => pure res)
589584
590585export
591586runLoop : Applicative m => Fuel -> STLoop m a [] ->
592− (onEmpty : m a) ->
587+ (onDry : m a) ->
593588 m a
594−runLoop fuel prog onEmpty
595− = runSTLoop fuel [] prog (\res, env' => pure res) onEmpty
589+runLoop fuel prog onDry
590+ = runSTLoop fuel [] prog (\res, env' => pure res) onDry
596591
597592||| runWith allows running an STrans program with an initial environment,
598593||| which must be consumed.
libs/contrib/Control/ST/File.idrnew file+247
@@ -0,0 +1,247 @@
1+module Control.ST.File
2+
3+import Control.ST
4+import Control.IOExcept
5+
6+%default total
7+
8+||| A record of the file modes that can read from a file.
9+public export
10+data ValidModeRead : Mode -> Type where
11+ VMRRead : ValidModeRead Read
12+ VMRReadW : ValidModeRead ReadWrite
13+ VMRReadWT : ValidModeRead ReadWriteTruncate
14+ VMRReadA : ValidModeRead ReadAppend
15+
16+||| A record of the file modes that can write from a file.
17+public export
18+data ValidModeWrite : Mode -> Type where
19+ VMWWrite : ValidModeWrite WriteTruncate
20+ VMWAppend : ValidModeWrite Append
21+ VMWReadW : ValidModeWrite ReadWrite
22+ VMWReadWT : ValidModeWrite ReadWriteTruncate
23+
24+||| The file handle which will be used as a State Transition
25+||| resource in the `IO` and `IOExcept` implementations of `File`.
26+|||
27+||| @mode The `Mode` that the handle was generated under.
28+|||
29+public export
30+data FileHandle : (mode : Mode) -> Type where
31+ FH : File -> FileHandle mode
32+
33+||| Description of state transition operations on a file.
34+|||
35+||| +------------+-------------+----------------+----------------+----------------+
36+||| | Operation | State in | Mode in | State out | Mode out |
37+||| +------------+-------------+----------------+----------------+----------------+
38+||| | open | - | - | file handle | input paramater|
39+||| | close | file handle | any | - | - |
40+||| | eof | file handle | ValidModeRead | file handle | ValidModeRead |
41+||| | flush | file handle | any | file handle | unchanged |
42+||| | readLine | file handle | ValidModeRead | file handle | ValidModeRead |
43+||| | readChar | file handle | ValidModeRead | file handle | ValidModeRead |
44+||| | readFile | - | - | - | - |
45+||| | writeString| file handle | ValidModeWrite | file handle | ValidModeWrite |
46+||| | writeLine | file handle | ValidModeWrite | file handle | ValidModeWrite |
47+||| | writeFile | - | - | - | - |
48+||| +------------+-------------+----------------+----------------+----------------+
49+|||
50+public export
51+interface File (m : Type -> Type) where
52+ FileHandleI : Mode -> Type
53+
54+ ||| Open a file.
55+ |||
56+ ||| @fname the filename.
57+ ||| @mode the mode; either Read, WriteTruncate, Append, ReadWrite,
58+ ||| ReadWriteTruncate, or ReadAppend
59+ |||
60+ open : (fname : String)
61+ -> (mode : Mode)
62+ -> ST m (Either FileError Var) [ addIfRight (FileHandleI mode) ]
63+
64+ ||| Close a file.
65+ close : (fileHandle : Var)
66+ -> ST m () [ remove fileHandle (FileHandleI mode) ]
67+
68+ ||| Have we reached the end of the file.
69+ eof : (fileHandle : Var)
70+ -> {auto prf : ValidModeRead mode}
71+ -> ST m Bool [ fileHandle ::: (FileHandleI mode) ]
72+
73+ ||| Flush
74+ flush : (fileHandle : Var)
75+ -> ST m () [ fileHandle ::: (FileHandleI mode) ]
76+
77+ ||| Read a complete line.
78+ readLine : (fileHandle : Var)
79+ -> {auto prf : ValidModeRead mode}
80+ -> ST m (Either FileError String) [ fileHandle ::: (FileHandleI mode) ]
81+
82+ ||| Read a `Char`.
83+ readChar : (fileHandle : Var)
84+ -> {auto prf : ValidModeRead mode}
85+ -> ST m (Either FileError Char) [ fileHandle ::: (FileHandleI mode) ]
86+
87+ ||| Read the contents of a file into a string.
88+ |||
89+ ||| This checks the size of
90+ ||| the file before beginning to read, and only reads that many bytes,
91+ ||| to ensure that it remains a total function if the file is appended
92+ ||| to while being read.
93+ |||
94+ ||| Returns an error if fname is not a normal file.
95+ |||
96+ readFile : (fileName : String)
97+ -> ST m (Either FileError String) []
98+
99+ ||| Write a complete line to the file.
100+ |||
101+ ||| @string The string to be written to file.
102+ |||
103+ writeString : (fileHandle : Var)
104+ -> (string : String)
105+ -> {auto prf : ValidModeWrite mode}
106+ -> ST m (Either FileError ()) [ fileHandle ::: (FileHandleI mode) ]
107+
108+ ||| Write a complete line to the file.
109+ |||
110+ ||| @string The text to be written to file.
111+ |||
112+ writeLine : (fileHandle : Var)
113+ -> (string : String)
114+ -> {auto prf : ValidModeWrite mode}
115+ -> ST m (Either FileError ()) [ fileHandle ::: (FileHandleI mode) ]
116+
117+ ||| Create a file and write contents to the file.
118+ |||
119+ ||| @fname The fileName of the file.
120+ ||| @string The text to be written to file.
121+ |||
122+ writeFile : (fname : String)
123+ -> (string : String)
124+ -> ST m (Either FileError ()) []
125+
126+public export
127+File IO where
128+ FileHandleI mode = State (FileHandle mode)
129+
130+ open fname mode = do
131+ (Right file) <- lift ( openFile fname mode )
132+ | (Left error ) => pure (Left error)
133+ let fh = FH file
134+ var <- new fh
135+ pure (Right var)
136+
137+ close fh = do
138+ (FH file) <- read fh
139+ lift (closeFile file)
140+ delete fh
141+ pure ()
142+
143+ eof fh = do
144+ (FH file) <- read fh
145+ isEof <- lift (fEOF file)
146+ pure (isEof)
147+
148+ flush fh = do
149+ (FH file) <- read fh
150+ lift (fEOF file)
151+ pure ()
152+
153+ readLine fh = do
154+ (FH file) <- read fh
155+ (Right string) <- lift (fGetLine file)
156+ | (Left error ) => pure (Left error)
157+ pure (Right string)
158+
159+ readChar fh = do
160+ (FH file) <- read fh
161+ (Right chr) <- lift (fgetc file)
162+ | (Left error ) => pure (Left error)
163+ pure (Right chr)
164+
165+ readFile fname = do
166+ (Right content) <- lift ( readFile fname )
167+ | (Left error ) => pure (Left error)
168+ pure (Right content)
169+
170+ writeString fh str = do
171+ (FH file) <- read fh
172+ Right x <- lift (fPutStr file str)
173+ | (Left error ) => pure (Left error)
174+ pure (Right x)
175+
176+ writeLine fh str = do
177+ (FH file) <- read fh
178+ Right x <- lift (fPutStrLn file str)
179+ | (Left error ) => pure (Left error)
180+ pure (Right x)
181+
182+ writeFile fname str = do
183+ Right x <- lift (writeFile fname str)
184+ | (Left error ) => pure (Left error)
185+ pure (Right x)
186+
187+public export
188+File (IOExcept a) where
189+ FileHandleI mode = State (FileHandle mode)
190+
191+ open fname mode = do
192+ (Right file) <- lift (ioe_lift (openFile fname mode))
193+ | (Left error ) => pure (Left error)
194+ let fh = FH file
195+ var <- new fh
196+ pure (Right var)
197+
198+ close fh = do
199+ (FH file) <- read fh
200+ lift (ioe_lift (closeFile file))
201+ delete fh
202+ pure ()
203+
204+ eof fh = do
205+ (FH file) <- read fh
206+ isEof <- lift (ioe_lift (fEOF file))
207+ pure (isEof)
208+
209+ flush fh = do
210+ (FH file) <- read fh
211+ lift (ioe_lift (fEOF file))
212+ pure ()
213+
214+ readLine fh = do
215+ (FH file) <- read fh
216+ (Right string) <- lift (ioe_lift (fGetLine file))
217+ | (Left error ) => pure (Left error)
218+ pure (Right string)
219+
220+ readChar fh = do
221+ (FH file) <- read fh
222+ (Right chr) <- lift (ioe_lift (fgetc file))
223+ | (Left error ) => pure (Left error)
224+ pure (Right chr)
225+
226+ readFile fname = do
227+ (Right content) <- lift (ioe_lift (readFile fname))
228+ | (Left error ) => pure (Left error)
229+ pure (Right content)
230+
231+ writeString fh str = do
232+ (FH file) <- read fh
233+ Right x <- lift (ioe_lift (fPutStr file str))
234+ | (Left error ) => pure (Left error)
235+ pure (Right x)
236+
237+ writeLine fh str = do
238+ (FH file) <- read fh
239+ Right x <- lift (ioe_lift (fPutStrLn file str))
240+ | (Left error ) => pure (Left error)
241+ pure (Right x)
242+
243+ writeFile fname str = do
244+ Right x <- lift (ioe_lift (writeFile fname str))
245+ | (Left error ) => pure (Left error)
246+ pure (Right x)
247+--- EOF -------------------------------------------------------------------------
libs/contrib/Data/Fuel.idrnew file+18
@@ -0,0 +1,18 @@
1+module Data.Fuel
2+
3+%access public export
4+%default total
5+
6+||| Fuel for running total operations potentially indefinitely.
7+data Fuel = Dry | More (Lazy Fuel)
8+
9+||| Provide `n` units of fuel.
10+limit : Nat -> Fuel
11+limit Z = Dry
12+limit (S n) = More (limit n)
13+
14+||| Provide fuel indefinitely.
15+||| This function is fundamentally partial.
16+partial
17+forever : Fuel
18+forever = More forever
libs/contrib/Data/List/Group.idrnew file+24
@@ -0,0 +1,24 @@
1+module Data.List.Group
2+
3+||| The groupBy function returns a list of lists such that the concatenation
4+||| of the list is equal to the argument, and each sublist contains only
5+||| elements that are equal according to the user-supplied predicate.
6+|||
7+||| ```idris example
8+||| groupBy (==) [1, 1, 2, 3, 3]
9+||| ```
10+|||
11+groupBy : (a -> a -> Bool) -> List a -> List (List a)
12+groupBy _ [] = []
13+groupBy p list@(x :: xs) =
14+ let (ys, zs) = span (p x) xs in
15+ (x :: ys) :: groupBy p (assert_smaller list zs)
16+
17+||| The group function is a special case of groupBy.
18+|||
19+||| ```idris example
20+||| group [1, 1, 2, 3, 3]
21+||| ```
22+|||
23+group : Eq a => List a -> List (List a)
24+group = groupBy (==)
libs/contrib/Text/Lexer.idr+59−15
@@ -12,16 +12,19 @@ import public Text.Token
1212toTokenMap : List (Lexer, k) -> TokenMap (Token k)
1313toTokenMap = map $ \(l, kind) => (l, Tok kind)
1414
15−||| Recognise any character
15+||| Recognise any character.
16+||| /./
1617any : Lexer
1718any = pred (const True)
1819
1920||| Recognise a lexer or recognise no input. This is not guaranteed
20−||| to consume input
21−opt : Lexer -> Recognise False
21+||| to consume input.
22+||| /`l`?/
23+opt : (l : Lexer) -> Recognise False
2224opt l = l <|> empty
2325
2426||| Recognise any character if the sub-lexer `l` fails.
27+||| /(?!`l`)./
2528non : (l : Lexer) -> Lexer
2629non l = reject l <+> any
2730
@@ -45,63 +48,75 @@ concat : (xs : List (Recognise c)) -> Recognise (c && isCons xs)
4548concat = concatMap id
4649
4750||| Recognise a specific character.
48−is : Char -> Lexer
51+||| /[`x`]/
52+is : (x : Char) -> Lexer
4953is x = pred (==x)
5054
5155||| Recognise anything but the given character.
52−isNot : Char -> Lexer
56+||| /[\^`x`]/
57+isNot : (x : Char) -> Lexer
5358isNot x = pred (/=x)
5459
5560||| Recognise a specific character (case-insensitive).
56−like : Char -> Lexer
61+||| /[`x`]/i
62+like : (x : Char) -> Lexer
5763like x = pred (\y => toUpper x == toUpper y)
5864
5965||| Recognise anything but the given character (case-insensitive).
60−notLike : Char -> Lexer
66+||| /[\^`x`]/i
67+notLike : (x : Char) -> Lexer
6168notLike x = pred (\y => toUpper x /= toUpper y)
6269
6370||| Recognise a specific string.
6471||| Fails if the string is empty.
65−exact : String -> Lexer
72+||| /`str`/
73+exact : (str : String) -> Lexer
6674exact str = case unpack str of
6775 [] => fail
6876 (x :: xs) => concatMap is (x :: xs)
6977
7078||| Recognise a specific string (case-insensitive).
7179||| Fails if the string is empty.
72−approx : String -> Lexer
80+||| /`str`/i
81+approx : (str : String) -> Lexer
7382approx str = case unpack str of
7483 [] => fail
7584 (x :: xs) => concatMap like (x :: xs)
7685
77−||| Recognise any of the characters in the given string
78−oneOf : String -> Lexer
79−oneOf cs = pred (\x => x `elem` unpack cs)
86+||| Recognise any of the characters in the given string.
87+||| /[`chars`]/
88+oneOf : (chars : String) -> Lexer
89+oneOf chars = pred (\x => x `elem` unpack chars)
8090
81−||| Recognise a character range [`a`-`b`]. Also works in reverse!
91+||| Recognise a character range. Also works in reverse!
92+||| /[`start`-`end`]/
8293range : (start : Char) -> (end : Char) -> Lexer
8394range start end = pred (\x => (x >= min start end)
8495 && (x <= max start end))
8596
8697mutual
8798 ||| Recognise a sequence of at least one sub-lexers
99+ ||| /`l`+/
88100 some : Lexer -> Lexer
89101 some l = l <+> many l
90102
91103 ||| Recognise a sequence of at zero or more sub-lexers. This is not
92104 ||| guaranteed to consume input
105+ ||| /`l`\*/
93106 many : Lexer -> Recognise False
94107 many l = opt (some l)
95108
96109||| Repeat the sub-lexer `l` zero or more times until the lexer
97110||| `stopBefore` is encountered. `stopBefore` will not be consumed.
98111||| Not guaranteed to consume input.
112+||| /((?!`stopBefore`)`l`)\*/
99113manyUntil : (stopBefore : Recognise c) -> (l : Lexer) -> Recognise False
100114manyUntil stopBefore l = many (reject stopBefore <+> l)
101115
102116||| Repeat the sub-lexer `l` zero or more times until the lexer
103117||| `stopAfter` is encountered, and consume it. Guaranteed to
104118||| consume if `stopAfter` consumes.
119+||| /`l`\*?`stopAfter`/
105120manyThen : (stopAfter : Recognise c) -> (l : Lexer) -> Recognise c
106121manyThen stopAfter l = manyUntil stopAfter l <+> stopAfter
107122
@@ -116,6 +131,7 @@ manyTill l end = end <|> opt (l <+> manyTill l end)
116131
117132||| Recognise a sub-lexer repeated as specified by `q`. Fails if `q` has
118133||| `min` and `max` in the wrong order. Consumes input unless `min q` is zero.
134+||| /`l`{`q`}/
119135count : (q : Quantity) -> (l : Lexer) -> Recognise (isSucc (min q))
120136count (Qty Z Nothing) l = many l
121137count (Qty Z (Just Z)) _ = empty
@@ -125,122 +141,150 @@ count (Qty (S min) (Just Z)) _ = fail
125141count (Qty (S min) (Just (S max))) l = l <+> count (between min max) l
126142
127143||| Recognise a single digit 0-9
144+||| /[0-9]/
128145digit : Lexer
129146digit = pred isDigit
130147
131−||| Recognise one or more digits
148+||| Recognise one or more digits
149+||| /[0-9]+/
132150digits : Lexer
133151digits = some digit
134152
135153||| Recognise a single hexidecimal digit
154+||| /[0-9A-Fa-f]/
136155hexDigit : Lexer
137156hexDigit = pred isHexDigit
138157
139158||| Recognise one or more hexidecimal digits
159+||| /[0-9A-Fa-f]+/
140160hexDigits : Lexer
141161hexDigits = some hexDigit
142162
143163||| Recognise a single alpha character
164+||| /[A-Za-z]/
144165alpha : Lexer
145166alpha = pred isAlpha
146167
147168||| Recognise one or more alpha characters
169+||| /[A-Za-z]+/
148170alphas : Lexer
149171alphas = some alpha
150172
151173||| Recognise a lowercase alpha character
174+||| /[a-z]/
152175lower : Lexer
153176lower = pred isLower
154177
155178||| Recognise one or more lowercase alpha characters
179+||| /[a-z]+/
156180lowers : Lexer
157181lowers = some lower
158182
159183||| Recognise an uppercase alpha character
184+||| /[A-Z]/
160185upper : Lexer
161186upper = pred isUpper
162187
163188||| Recognise one or more uppercase alpha characters
189+||| /[A-Z]+/
164190uppers : Lexer
165191uppers = some upper
166192
167193||| Recognise an alphanumeric character
194+||| /[A-Za-z0-9]/
168195alphaNum : Lexer
169196alphaNum = pred isAlphaNum
170197
171198||| Recognise one or more alphanumeric characters
199+||| /[A-Za-z0-9]+/
172200alphaNums : Lexer
173201alphaNums = some alphaNum
174202
175203||| Recognise a single whitespace character
204+||| /\\s/
176205space : Lexer
177206space = pred isSpace
178207
179208||| Recognise one or more whitespace characters
209+||| /\\s+/
180210spaces : Lexer
181211spaces = some space
182212
183213||| Recognise a single newline sequence. Understands CRLF, CR, and LF
214+||| /\\r\\n|[\\r\\n]/
184215newline : Lexer
185216newline = let crlf = "\r\n" in
186217 exact crlf <|> oneOf crlf
187218
188219||| Recognise one or more newline sequences. Understands CRLF, CR, and LF
220+||| /(\\r\\n|[\\r\\n])+)/
189221newlines : Lexer
190222newlines = some newline
191223
192224||| Recognise a single non-whitespace, non-alphanumeric character
225+||| /[\^\\sA-Za-z0-9]/
193226symbol : Lexer
194227symbol = pred (\x => not (isSpace x || isAlphaNum x))
195228
196229||| Recognise one or more non-whitespace, non-alphanumeric characters
230+||| /[\^\\sA-Za-z0-9]+/
197231symbols : Lexer
198232symbols = some symbol
199233
200234||| Recognise a single control character
235+||| /[\\x00-\\x1f\\x7f-\\x9f]/
201236control : Lexer
202237control = pred isControl
203238
204239||| Recognise one or more control characters
240+||| /[\\x00-\\x1f\\x7f-\\x9f]+/
205241controls : Lexer
206242controls = some control
207243
208244||| Recognise zero or more occurrences of a sub-lexer between
209245||| delimiting lexers
246+||| /`start`(`l`)\*?`end`/
210247surround : (start : Lexer) -> (end : Lexer) -> (l : Lexer) -> Lexer
211248surround start end l = start <+> manyThen end l
212249
213250||| Recognise zero or more occurrences of a sub-lexer surrounded
214251||| by the same quote lexer on both sides (useful for strings)
252+||| /`q`(`l`)\*?`q`/
215253quote : (q : Lexer) -> (l : Lexer) -> Lexer
216254quote q l = surround q q l
217255
218256||| Recognise an escape character (often '\\') followed by a sub-lexer
257+||| /[`esc`]`l`/
219258escape : (esc : Char) -> Lexer -> Lexer
220259escape esc l = is esc <+> l
221260
222261||| Recognise a string literal, including escaped characters.
223262||| (Note: doesn't yet handle escape sequences such as \123)
263+||| /"(\\\\.|.)\*?"/
224264stringLit : Lexer
225265stringLit = quote (is '"') (escape '\\' any <|> any)
226266
227267||| Recognise a character literal, including escaped characters.
228268||| (Note: doesn't yet handle escape sequences such as \123)
269+||| /'(\\\\.|[\^'])'/
229270charLit : Lexer
230271charLit = let q = '\'' in
231272 is q <+> (escape '\\' any <|> isNot q) <+> is q
232273
233274||| Recognise an integer literal (possibly with a '-' prefix)
275+||| /-?[0-9]+/
234276intLit : Lexer
235277intLit = opt (is '-') <+> digits
236278
237279||| Recognise a hexidecimal literal, prefixed by "0x" or "0X"
280+||| /0[Xx][0-9A-Fa-f]+/
238281hexLit : Lexer
239282hexLit = approx "0x" <+> hexDigits
240283
241284||| Recognise `start`, then recognise all input until a newline is encountered,
242285||| and consume the newline. Will succeed if end-of-input is encountered before
243286||| a newline.
287+||| /`start`[\^\\r\\n]+(\\r\\n|[\\r\\n])?/
244288lineComment : (start : Lexer) -> Lexer
245289lineComment start = start <+> manyUntil newline any <+> opt newline
246290
@@ -248,7 +292,7 @@ lineComment start = start <+> manyUntil newline any <+> opt newline
248292||| Supports balanced nesting.
249293|||
250294||| For block comments that don't support nesting (such as C-style comments),
251−||| use `surround`.
295+||| use `surround`
252296blockComment : (start : Lexer) -> (end : Lexer) -> Lexer
253297blockComment start end = start <+> middle <+> end
254298 where
libs/contrib/contrib.ipkg+2
@@ -20,6 +20,7 @@ modules = CFFI
2020 , Control.ST.Exception
2121 , Control.ST.ImplicitCall
2222 , Control.ST.Random
23+ , Control.ST.File
2324
2425 , Data.Bool.Extra
2526 , Data.BoundedList
@@ -28,6 +29,7 @@ modules = CFFI
2829 , Data.Combinators.Applicative
2930 , Data.Combinators.Arrow
3031 , Data.Fin.Extra
32+ , Data.Fuel
3133 , Data.Fun
3234 , Data.Hash
3335 , Data.Heap
libs/prelude/IO.idr+3−2
@@ -101,9 +101,10 @@ unsafePerformPrimIO : PrimIO a -> a
101101prim_io_pure : a -> PrimIO a
102102prim_io_pure x = Prim__IO x
103103
104+-- Don't %inline; the compiler treats it specially
104105io_bind : IO' l a -> (a -> IO' l b) -> IO' l b
105−io_bind (MkIO fn) k
106− = MkIO (\w => prim_io_bind (fn w)
106+io_bind (MkIO fn)
107+ = \k => MkIO (\w => prim_io_bind (fn w)
107108 (\ b => case k b of
108109 MkIO fkb => fkb w))
109110
libs/prelude/Prelude/Interfaces.idr+2
@@ -12,6 +12,8 @@ infixl 7 <<, >> -- unused
1212infixl 8 +, -
1313infixl 9 *, /
1414
15+infixl 9 `div`, `mod`
16+
1517-- ------------------------------------------------------------- [ Boolean Ops ]
1618intToBool : Int -> Bool
1719intToBool 0 = False
libs/prelude/Prelude/List.idr+12−12
@@ -447,7 +447,7 @@ transpose ((x::xs) :: xss) = assert_total $ (x :: (mapMaybe head' xss)) :: (tran
447447--------------------------------------------------------------------------------
448448
449449||| Check if something is a member of a list using a custom comparison.
450−elemBy : (a -> a -> Bool) -> a -> List a -> Bool
450+elemBy : %static (a -> a -> Bool) -> a -> List a -> Bool
451451elemBy p e [] = False
452452elemBy p e (x::xs) =
453453 if p e x then
@@ -460,7 +460,7 @@ elem : Eq a => a -> List a -> Bool
460460elem = elemBy (==)
461461
462462||| Find associated information in a list using a custom comparison.
463−lookupBy : (a -> a -> Bool) -> a -> List (a, b) -> Maybe b
463+lookupBy : %static (a -> a -> Bool) -> a -> List (a, b) -> Maybe b
464464lookupBy p e [] = Nothing
465465lookupBy p e (x::xs) =
466466 let (l, r) = x in
@@ -475,7 +475,7 @@ lookup = lookupBy (==)
475475
476476||| Check if any elements of the first list are found in the second, using
477477||| a custom comparison.
478−hasAnyBy : (a -> a -> Bool) -> List a -> List a -> Bool
478+hasAnyBy : %static (a -> a -> Bool) -> List a -> List a -> Bool
479479hasAnyBy p elems [] = False
480480hasAnyBy p elems (x::xs) =
481481 if elemBy p x elems then
@@ -527,7 +527,7 @@ findIndices = findIndices' Z
527527 findIndices' (S cnt) p xs
528528
529529||| Find the index of the first occurrence of an element in a list, using a custom equality test.
530−elemIndexBy : (a -> a -> Bool) -> a -> List a -> Maybe Nat
530+elemIndexBy : %static (a -> a -> Bool) -> a -> List a -> Maybe Nat
531531elemIndexBy p e = findIndex $ p e
532532
533533||| Find the index of the first occurrence of an element in a list,
@@ -536,7 +536,7 @@ elemIndex : Eq a => a -> List a -> Maybe Nat
536536elemIndex = elemIndexBy (==)
537537
538538||| Find all indices for an element in a list, using a custom equality test.
539−elemIndicesBy : (a -> a -> Bool) -> a -> List a -> List Nat
539+elemIndicesBy : %static (a -> a -> Bool) -> a -> List a -> List Nat
540540elemIndicesBy p e = findIndices $ p e
541541
542542||| Find all indices for an element in a list, using the default equality test for the type of list elements.
@@ -572,7 +572,7 @@ filterSmaller {p} (x :: xs) with (p x)
572572
573573||| The nubBy function behaves just like nub, except it uses a user-supplied
574574||| equality predicate instead of the overloaded == function.
575−nubBy : (a -> a -> Bool) -> List a -> List a
575+nubBy : %static (a -> a -> Bool) -> List a -> List a
576576nubBy = nubBy' []
577577 where
578578 nubBy' : List a -> (a -> a -> Bool) -> List a -> List a
@@ -595,7 +595,7 @@ nub : Eq a => List a -> List a
595595nub = nubBy (==)
596596
597597||| The deleteBy function behaves like delete, but takes a user-supplied equality predicate.
598−deleteBy : (a -> a -> Bool) -> a -> List a -> List a
598+deleteBy : %static (a -> a -> Bool) -> a -> List a -> List a
599599deleteBy _ _ [] = []
600600deleteBy eq x (y::ys) = if x `eq` y then ys else y :: deleteBy eq x ys
601601
@@ -622,7 +622,7 @@ delete = deleteBy (==)
622622(\\) = foldl (flip delete)
623623
624624||| The unionBy function returns the union of two lists by user-supplied equality predicate.
625−unionBy : (a -> a -> Bool) -> List a -> List a -> List a
625+unionBy : %static (a -> a -> Bool) -> List a -> List a -> List a
626626unionBy eq xs ys = xs ++ foldl (flip (deleteBy eq)) (nubBy eq ys) xs
627627
628628||| Compute the union of two lists according to their `Eq` implementation.
@@ -747,7 +747,7 @@ replaceOn a b l = map (\c => if c == a then b else c) l
747747||| @ eq the equality comparison
748748||| @ left the potential prefix
749749||| @ right the list that may have `left` as its prefix
750−isPrefixOfBy : (eq : a -> a -> Bool) -> (left, right : List a) -> Bool
750+isPrefixOfBy : %static (eq : a -> a -> Bool) -> (left, right : List a) -> Bool
751751isPrefixOfBy p [] right = True
752752isPrefixOfBy p left [] = False
753753isPrefixOfBy p (x::xs) (y::ys) =
@@ -760,7 +760,7 @@ isPrefixOfBy p (x::xs) (y::ys) =
760760isPrefixOf : Eq a => List a -> List a -> Bool
761761isPrefixOf = isPrefixOfBy (==)
762762
763−isSuffixOfBy : (a -> a -> Bool) -> List a -> List a -> Bool
763+isSuffixOfBy : %static (a -> a -> Bool) -> List a -> List a -> Bool
764764isSuffixOfBy p left right = isPrefixOfBy p (reverse left) (reverse right)
765765
766766||| The isSuffixOf function takes two lists and returns True iff the first list is a suffix of the second.
@@ -795,7 +795,7 @@ sorted (x::xs) =
795795||| Merge two sorted lists using an arbitrary comparison
796796||| predicate. Note that the lists must have been sorted using this
797797||| predicate already.
798−mergeBy : (a -> a -> Ordering) -> List a -> List a -> List a
798+mergeBy : %static (a -> a -> Ordering) -> List a -> List a -> List a
799799mergeBy order [] right = right
800800mergeBy order left [] = left
801801mergeBy order (x::xs) (y::ys) =
@@ -811,7 +811,7 @@ merge = mergeBy compare
811811|||
812812||| @ cmp how to compare elements
813813||| @ xs the list to sort
814−sortBy : (cmp : a -> a -> Ordering) -> (xs : List a) -> List a
814+sortBy : %static (cmp : a -> a -> Ordering) -> (xs : List a) -> List a
815815sortBy cmp [] = []
816816sortBy cmp [x] = [x]
817817sortBy cmp xs = let (x, y) = split xs in
src/IRTS/CodegenC.hs+26−23
@@ -220,8 +220,14 @@ bcc i (PROJECT l loc a) = indent i ++ "PROJECT(vm, " ++ creg l ++ ", " ++ show l
220220 ", " ++ show a ++ ");\n"
221221bcc i (PROJECTINTO r t idx)
222222 = indent i ++ creg r ++ " = GETARG(" ++ creg t ++ ", " ++ show idx ++ ");\n"
223+bcc i (CASE True r [(_, alt)] Nothing)
224+ = indent i ++ showCode i alt
225+ where
226+ showCode :: Int -> [BC] -> String
227+ showCode i bc = "{\n" ++ concatMap (bcc (i + 1)) bc ++
228+ indent i ++ "}\n"
223229bcc i (CASE True r code def)
224− | length code < 4 = showCase i def code
230+ | length code < 6 && length code > 1 = showCase i def code
225231 where
226232 showCode :: Int -> [BC] -> String
227233 showCode i bc = "{\n" ++ concatMap (bcc (i + 1)) bc ++
@@ -697,29 +703,26 @@ ifaceC (ExportFun n cn ret args)
697703
698704 argNames = zipWith (++) (repeat "arg") (map show [0..])
699705
700−mkBody n as t = indent 1 ++ "INITFRAME;\n" ++
701− indent 1 ++ "RESERVE(" ++ show (max (length as) 3) ++ ");\n" ++
702− push 0 as ++ call n ++ retval t
703− where push i [] = ""
704− push i ((n, t) : ts) = indent 1 ++ c_irts (toFType t)
705− ("TOP(" ++ show i ++ ") = ") n
706− ++ ";\n" ++ push (i + 1) ts
707−
708− call _ = indent 1 ++ "STOREOLD;\n" ++
709− indent 1 ++ "BASETOP(0);\n" ++
710− indent 1 ++ "ADDTOP(" ++ show (length as) ++ ");\n" ++
711− indent 1 ++ "CALL(" ++ cname n ++ ");\n"
712−
713− retval (FIO t)
714− = indent 1 ++ "TOP(0) = NULL;\n" ++
715− indent 1 ++ "TOP(1) = NULL;\n" ++
716− indent 1 ++ "TOP(2) = RVAL;\n" ++
717− indent 1 ++ "STOREOLD;\n" ++
706+mkBody n as_in t
707+ = indent 1 ++ "INITFRAME;\n" ++
708+ indent 1 ++ "RESERVE(" ++ show (max (length as) 3) ++ ");\n" ++
709+ push 0 as ++ call n ++ retval t
710+ where
711+ as = case t of
712+ FIO t -> as_in ++ [("NULL", FUnknown)] -- add world token
713+ _ -> as_in
714+ push i [] = ""
715+ push i ((n, t) : ts) = indent 1 ++ c_irts (toFType t)
716+ ("TOP(" ++ show i ++ ") = ") n
717+ ++ ";\n" ++ push (i + 1) ts
718+
719+ call _ = indent 1 ++ "STOREOLD;\n" ++
718720 indent 1 ++ "BASETOP(0);\n" ++
719− indent 1 ++ "ADDTOP(3);\n" ++
720− indent 1 ++ "CALL(" ++ cname (sUN "call__IO") ++ ");\n" ++
721− retval t
722− retval t = indent 1 ++ "return " ++ irts_c (toFType t) "RVAL" ++ ";\n"
721+ indent 1 ++ "ADDTOP(" ++ show (length as) ++ ");\n" ++
722+ indent 1 ++ "CALL(" ++ cname n ++ ");\n"
723+
724+ retval (FIO t) = retval t
725+ retval t = indent 1 ++ "return " ++ irts_c (toFType t) "RVAL" ++ ";\n"
723726
724727ctype (FCon c)
725728 | c == sUN "C_Str" = "char*"
src/IRTS/Compiler.hs+14−7
@@ -81,7 +81,14 @@ compile codegen f mtm = do
8181 let defsUniq = map (allocUnique (addAlist defsInlined emptyContext))
8282 defsInlined
8383
84− let (nexttag, tagged) = addTags 65536 (liftAll defsUniq)
84+ logCodeGen 1 "Inlining"
85+
86+ dumpCases <- getDumpCases
87+ case dumpCases of
88+ Nothing -> return ()
89+ Just f -> runIO $ writeFile f (showCaseTrees defsUniq)
90+
91+ let (nexttag, tagged) = addTags 65536 (liftAll defsInlined)
8592 let ctxtIn = addAlist tagged emptyContext
8693
8794 logCodeGen 1 "Defunctionalising"
@@ -96,11 +103,7 @@ compile codegen f mtm = do
96103
97104 let checked = simplifyDefs defuns (toAlist defuns)
98105 outty <- outputTy
99− dumpCases <- getDumpCases
100106 dumpDefun <- getDumpDefun
101− case dumpCases of
102− Nothing -> return ()
103− Just f -> runIO $ writeFile f (showCaseTrees defs)
104107 case dumpDefun of
105108 Nothing -> return ()
106109 Just f -> runIO $ writeFile f (dumpDefuns defuns)
@@ -168,9 +171,13 @@ getDeclarations used
168171showCaseTrees :: [(Name, LDecl)] -> String
169172showCaseTrees = showSep "\n\n" . map showCT . sortBy (comparing defnRank)
170173 where
171− showCT (n, LFun _ f args lexp)
172− = show n ++ " " ++ showSep " " (map show args) ++ " =\n\t"
174+ showCT (n, LFun opts f args lexp)
175+ = showOpts ++
176+ show n ++ " " ++ showSep " " (map show args) ++ " =\n\t"
173177 ++ show lexp
178+ where
179+ showOpts | Inline `elem` opts = "%inline "
180+ | otherwise = ""
174181 showCT (n, LConstructor c t a) = "data " ++ show n ++ " " ++ show a
175182
176183 defnRank :: (Name, LDecl) -> String
src/IRTS/JavaScript/PrimOp.hs−2
@@ -26,8 +26,6 @@ data JsPrimTy = PTBool | PTAny deriving (Eq, Ord)
2626type PrimF = [JsExpr] -> JsExpr
2727type PrimDec = (Bool, JsPrimTy, PrimF) -- the bool indicates if bigint library is used or not
2828
29−deriving instance Ord PrimFn
30−
3129primDB :: Map.Map PrimFn PrimDec
3230primDB =
3331 Map.fromList [
src/IRTS/Lang.hs+97−34
@@ -16,6 +16,7 @@ import Idris.Core.TT
1616import Control.Monad.State hiding (lift)
1717import Data.Data (Data)
1818import Data.List
19+import qualified Data.Map.Strict as Map
1920import Data.Typeable (Typeable)
2021import GHC.Generics (Generic)
2122
@@ -44,26 +45,26 @@ data LExp = LV Name
4445 | LOp PrimFn [LExp]
4546 | LNothing
4647 | LError String
47− deriving Eq
48+ deriving (Eq, Ord)
4849
4950data FDesc = FCon Name
5051 | FStr String
5152 | FUnknown
5253 | FIO FDesc
5354 | FApp Name [FDesc]
54− deriving (Show, Eq)
55+ deriving (Show, Eq, Ord)
5556
5657data Export = ExportData FDesc -- Exported data descriptor (usually string)
5758 | ExportFun Name -- Idris name
5859 FDesc -- Exported function descriptor
5960 FDesc -- Return type descriptor
6061 [FDesc] -- Argument types
61− deriving (Show, Eq)
62+ deriving (Show, Eq, Ord)
6263
6364data ExportIFace = Export Name -- FFI descriptor
6465 String -- interface file
6566 [Export]
66− deriving (Show, Eq)
67+ deriving (Show, Eq, Ord)
6768
6869-- Primitive operators. Backends are not *required* to implement all
6970-- of these, but should report an error if they are unable
@@ -96,12 +97,12 @@ data PrimFn = LPlus ArithTy | LMinus ArithTy | LTimes ArithTy
9697 | LCrash
9798
9899 | LNoOp
99− deriving (Show, Eq, Generic)
100+ deriving (Show, Eq, Ord, Generic)
100101
101102-- Supported target languages for foreign calls
102103
103104data FCallType = FStatic | FObject | FConstructor
104− deriving (Show, Eq)
105+ deriving (Show, Eq, Ord)
105106
106107data FType = FArith ArithTy
107108 | FFunction
@@ -112,24 +113,24 @@ data FType = FArith ArithTy
112113 | FManagedPtr
113114 | FCData
114115 | FAny
115− deriving (Show, Eq)
116+ deriving (Show, Eq, Ord)
116117
117118-- FIXME: Why not use this for all the IRs now?
118119data LAlt' e = LConCase Int Name [Name] e
119120 | LConstCase Const e
120121 | LDefaultCase e
121− deriving (Show, Eq, Functor, Data, Typeable)
122+ deriving (Show, Eq, Ord, Functor, Data, Typeable)
122123
123124type LAlt = LAlt' LExp
124125
125126data LDecl = LFun [LOpt] Name [Name] LExp -- options, name, arg names, def
126127 | LConstructor Name Int Int -- constructor name, tag, arity
127− deriving (Show, Eq)
128+ deriving (Show, Eq, Ord)
128129
129130type LDefs = Ctxt LDecl
130131
131132data LOpt = Inline | NoInline
132− deriving (Show, Eq)
133+ deriving (Show, Eq, Ord)
133134
134135addTags :: Int -> [(Name, LDecl)] -> (Int, [(Name, LDecl)])
135136addTags i ds = tag i ds []
@@ -140,37 +141,71 @@ addTags i ds = tag i ds []
140141 tag i (x : as) acc = tag i as (x : acc)
141142 tag i [] acc = (i, reverse acc)
142143
143−data LiftState = LS Name Int [(Name, LDecl)]
144+data LiftState = LS (Maybe Name) Int [(Name, LDecl)]
145+ (Map.Map ([Name], LExp) Name) -- map from args/expressions
146+ -- to names, so we don't create the same function
147+ -- multiple times
148+
149+setBaseName :: Name -> State LiftState ()
150+setBaseName n
151+ = do LS _ i ds done <- get
152+ put (LS (Just n) i ds done)
144153
145154lname (NS n x) i = NS (lname n i) x
146155lname (UN n) i = MN i n
147156lname x i = sMN i (showCG x ++ "_lam")
148157
149−liftAll :: [(Name, LDecl)] -> [(Name, LDecl)]
150−liftAll xs = concatMap (\ (x, d) -> lambdaLift x d) xs
151−
152−lambdaLift :: Name -> LDecl -> [(Name, LDecl)]
153−lambdaLift n (LFun opts _ args e)
154− = let (e', (LS _ _ decls)) = runState (lift args e) (LS n 0 []) in
155− (n, LFun opts n args e') : decls
156−lambdaLift n x = [(n, x)]
157−
158158getNextName :: State LiftState Name
159−getNextName = do LS n i ds <- get
160− put (LS n (i + 1) ds)
161− return (lname n i)
159+getNextName
160+ = do LS mn i ds done <- get
161+ let newn = case mn of
162+ Nothing -> lname (sUN "_") i
163+ Just n -> lname n i
164+ put (LS mn (i + 1) ds done)
165+ return newn
166+
167+renameArgs :: [Name] -> LExp -> ([Name], LExp)
168+renameArgs args e
169+ = let newargNames = map (\i -> sMN i "lift") [0..]
170+ newargs = zip args newargNames in
171+ (map snd newargs, rename newargs e)
162172
163173addFn :: Name -> LDecl -> State LiftState ()
164−addFn fn d = do LS n i ds <- get
165− put (LS n i ((fn, d) : ds))
174+addFn fn d
175+ = do LS n i ds done <- get
176+ put (LS n i ((fn, d) : ds) done)
177+
178+makeFn :: [Name] -> LExp -> State LiftState Name
179+makeFn args exp
180+ = do fn <- getNextName
181+ let (args', exp') = renameArgs args exp
182+ LS n i ds done <- get
183+ case Map.lookup (args', exp') done of
184+ Just fn -> return fn
185+ Nothing ->
186+ do addFn fn (LFun [Inline] fn args' exp')
187+ LS n i ds done <- get
188+ put (LS n i ds (Map.insert (args', exp') fn done))
189+ return fn
190+
191+liftAll :: [(Name, LDecl)] -> [(Name, LDecl)]
192+liftAll xs =
193+ let (LS _ _ decls _) = execState (mapM_ liftDef xs) (LS Nothing 0 [] Map.empty) in
194+ decls
195+
196+liftDef :: (Name, LDecl) -> State LiftState ()
197+liftDef (n, LFun opts _ args e) =
198+ do setBaseName n
199+ e' <- lift args e
200+ addFn n (LFun opts n args e')
201+liftDef (n, x) = addFn n x
166202
167203lift :: [Name] -> LExp -> State LiftState LExp
168204lift env (LV v) = return (LV v) -- Lifting happens before these can exist...
169205lift env (LApp tc (LV n) args) = do args' <- mapM (lift env) args
170206 return (LApp tc (LV n) args')
171207lift env (LApp tc f args) = do f' <- lift env f
172− fn <- getNextName
173− addFn fn (LFun [Inline] fn env f')
208+ fn <- makeFn env f'
174209 args' <- mapM (lift env) args
175210 return (LApp tc (LV fn) (map LV env ++ args'))
176211lift env (LLazyApp n args) = do args' <- mapM (lift env) args
@@ -180,18 +215,17 @@ lift env (LLazyExp (LConst c)) = return (LConst c)
180215-- = lift env (LLazyApp f args)
181216lift env (LLazyExp e) = do e' <- lift env e
182217 let usedArgs = nub $ usedIn env e'
183− fn <- getNextName
184− addFn fn (LFun [NoInline] fn usedArgs e')
218+ fn <- makeFn usedArgs e'
185219 return (LLazyApp fn (map LV usedArgs))
186220lift env (LForce e) = do e' <- lift env e
187221 return (LForce e')
188222lift env (LLet n v e) = do v' <- lift env v
189223 e' <- lift (env ++ [n]) e
190224 return (LLet n v' e')
225+lift env (LLam args (LLam args' e)) = lift env (LLam (args ++ args') e)
191226lift env (LLam args e) = do e' <- lift (env ++ args) e
192227 let usedArgs = nub $ usedIn env e'
193− fn <- getNextName
194− addFn fn (LFun [Inline] fn (usedArgs ++ args) e')
228+ fn <- makeFn (usedArgs ++ args) e'
195229 return (LApp False (LV fn) (map LV usedArgs))
196230lift env (LProj t i) = do t' <- lift env t
197231 return (LProj t' i)
@@ -329,6 +363,35 @@ lsubst n new (LCase t e alts) = let e' = lsubst n new e
329363 LCase t e' alts'
330364lsubst n new tm = tm
331365
366+rename :: [(Name, Name)] -> LExp -> LExp
367+rename ns tm@(LV x)
368+ = case lookup x ns of
369+ Just n -> LV n
370+ _ -> tm
371+rename ns (LApp t e args)
372+ = let e' = rename ns e
373+ args' = map (rename ns) args in
374+ LApp t e' args'
375+rename ns (LLazyApp fn args)
376+ = let args' = map (rename ns) args in
377+ LLazyApp fn args'
378+rename ns (LLazyExp e) = LLazyExp (rename ns e)
379+rename ns (LForce e) = LForce (rename ns e)
380+rename ns (LLet v val sc) = LLet v (rename ns val) (rename ns sc)
381+rename ns (LLam args sc) = LLam args (rename ns sc)
382+rename ns (LProj e i) = LProj (rename ns e) i
383+rename ns (LCon lv t cn args) = let args' = map (rename ns) args in
384+ LCon lv t cn args'
385+rename ns (LOp op args) = let args' = map (rename ns) args in
386+ LOp op args'
387+rename ns (LForeign fd rd args)
388+ = let args' = map (\(d, a) -> (d, rename ns a)) args in
389+ LForeign fd rd args'
390+rename ns (LCase t e alts) = let e' = rename ns e
391+ alts' = map (fmap (rename ns)) alts in
392+ LCase t e' alts'
393+rename ns tm = tm
394+
332395instance Show LExp where
333396 show e = show' [] "" e where
334397 show' env ind (LV n) = show n
@@ -346,8 +409,8 @@ instance Show LExp where
346409 ++ " in " ++ show' (env ++ [show n]) ind e
347410
348411 show' env ind (LLam args e)
349− = "\\ " ++ showSep "," (map show args)
350− ++ " => " ++ show' (env ++ (map show args)) ind e
412+ = "(\\ " ++ showSep "," (map show args)
413+ ++ " => " ++ show' (env ++ (map show args)) ind e ++ ") "
351414
352415 show' env ind (LProj t i) = show t ++ "!" ++ show i
353416
@@ -357,7 +420,7 @@ instance Show LExp where
357420 atloc (Just l) = "@" ++ show (LV l) ++ ":"
358421
359422 show' env ind (LCase up e alts)
360− = "case" ++ update ++ show' env ind e ++ " of \n" ++ fmt alts
423+ = "case" ++ update ++ "(" ++ show' env ind e ++ ") of \n" ++ fmt alts
361424 where
362425 update = case up of
363426 Shared -> " "
src/IRTS/LangOpts.hs+265−50
@@ -7,12 +7,16 @@ Maintainer : The Idris Community.
77-}
88{-# LANGUAGE DeriveFunctor, PatternGuards #-}
99
10−module IRTS.LangOpts where
10+module IRTS.LangOpts(inlineAll) where
1111
12+import Idris.Core.CaseTree
1213import Idris.Core.TT
1314import IRTS.Lang
1415
1516import Control.Monad.State hiding (lift)
17+import Data.List
18+
19+import Debug.Trace
1620
1721inlineAll :: [(Name, LDecl)] -> [(Name, LDecl)]
1822inlineAll lds = let defs = addAlist lds emptyContext in
@@ -31,53 +35,264 @@ nextN = do i <- get
3135doInline :: LDefs -> LDecl -> LDecl
3236doInline defs d@(LConstructor _ _ _) = d
3337doInline defs (LFun opts topn args exp)
34− = let res = evalState (inlineWith [topn] (map (\n -> (n, LV n)) args) exp) 0 in
35− LFun opts topn args res
38+ = let inl = evalState (eval [] initEnv [topn] defs exp)
39+ (length args)
40+ -- do some case floating, which might arise as a result
41+ -- then, eta contract
42+ res = eta $ caseFloats 10 inl in
43+ case res of
44+ LLam args' body -> LFun opts topn (map snd initNames ++ args') body
45+ _ -> LFun opts topn (map snd initNames) res
46+ where
47+ caseFloats 0 tm = tm
48+ caseFloats n tm
49+ = let res = caseFloat tm in
50+ if res == tm
51+ then res
52+ else caseFloats (n-1) res
53+
54+ initNames = zipWith (\n i -> (n, newn n i)) args [0..]
55+ initEnv = map (\(n, n') -> (n, LV n')) initNames
56+ newn (UN n) i = MN i n
57+ newn _ i = sMN i "arg"
58+
59+unload :: [LExp] -> LExp -> LExp
60+unload [] e = e
61+unload stk (LApp tc e args) = LApp tc e (args ++ stk)
62+unload stk e = LApp False e stk
63+
64+takeStk :: [(Name, LExp)] -> [Name] -> [LExp] ->
65+ ([(Name, LExp)], [Name], [LExp])
66+takeStk env (a : args) (v : stk) = takeStk ((a, v) : env) args stk
67+takeStk env args stk = (env, args, stk)
68+
69+eval :: [LExp] -> [(Name, LExp)] -> [Name] -> LDefs -> LExp -> State Int LExp
70+eval stk env rec defs (LLazyApp n es)
71+ = unload stk <$> LLazyApp n <$> (mapM (eval [] env rec defs) es)
72+eval stk env rec defs (LForce e)
73+ = do e' <- eval [] env rec defs e
74+ case e' of
75+ LLazyExp forced -> return $ unload stk forced
76+ LLazyApp n es -> return $ unload stk (LApp False (LV n) es)
77+ _ -> return (unload stk (LForce e'))
78+eval stk env rec defs (LLazyExp e)
79+ = unload stk <$> LLazyExp <$> eval [] env rec defs e
80+-- Special case for io_bind, because it needs to keep executing the first
81+-- action, and is worth inlining to avoid the thunk
82+eval [] env rec defs (LApp t (LV n) [_, _, _, act, (LLam [arg] k)])
83+ | n == sUN "io_bind"
84+ = do w <- nextN
85+ let env' = (w, LV w) : env
86+ act' <- eval [] env' rec defs (LApp False act [LV w])
87+ argn <- nextN
88+ k' <- eval [] ((arg, LV argn) : env') rec defs (LApp False k [LV w])
89+ return $ LLam [w] (LLet argn act' k')
90+eval (world : stk) env rec defs (LApp t (LV n) [_, _, _, act, (LLam [arg] k)])
91+ | n == sUN "io_bind"
92+ = do act' <- eval [] env rec defs (LApp False act [world])
93+ argn <- nextN
94+ k' <- eval stk ((arg, LV argn) : env) rec defs (LApp False k [world])
95+ return $ LLet argn act' k'
96+
97+eval stk env rec defs (LApp t f es)
98+ = do es' <- mapM (eval [] env rec defs) es
99+ eval (es' ++ stk) env rec defs f
100+eval stk env rec defs (LLet n val sc)
101+ = do n' <- nextN
102+ LLet n' <$> eval [] env rec defs val
103+ <*> eval stk ((n, LV n') : env) rec defs sc
104+eval stk env rec defs (LProj exp i)
105+ = unload stk <$> (LProj <$> eval [] env rec defs exp <*> return i)
106+eval stk env rec defs (LCon loc i n es)
107+ = unload stk <$> (LCon loc i n <$> mapM (eval [] env rec defs) es)
108+eval stk env rec defs (LCase ty e alts)
109+ = do alts' <- mapM (evalAlt stk env rec defs) alts
110+ e' <- eval [] env rec defs e
111+ -- If they're all lambdas, bind the lambda at the top
112+ let prefix = getLams (map getRHS alts')
113+ case prefix of
114+ [] -> return $ conOpt $ LCase ty e' (replaceInAlts e' alts')
115+ args -> do alts_red <- mapM (dropArgs args) alts'
116+ return $ LLam args
117+ (conOpt (LCase ty e' (replaceInAlts e' alts_red)))
118+eval stk env rec defs (LOp f es)
119+ = unload stk <$> LOp f <$> mapM (eval [] env rec defs) es
120+eval stk env rec defs (LForeign t s args)
121+ = unload stk <$>
122+ LForeign t s <$> mapM (\(t, e) -> do e' <- eval [] env rec defs e
123+ return (t, e')) args
124+-- save the interesting cases for the end:
125+-- lambdas, and names to reduce
126+eval stk env rec defs (LLam args sc)
127+ | (env', args', stk') <- takeStk env args stk
128+ = case args' of
129+ [] -> eval stk' env' rec defs sc
130+ as -> do ns' <- mapM (\n -> do n' <- nextN
131+ return (n, n')) args'
132+ unload stk' <$> LLam (map snd ns') <$>
133+ eval [] (map (\ (n, n') -> (n, LV n')) ns' ++ env')
134+ rec defs sc
135+eval stk env rec defs var@(LV n)
136+ = case lookup n env of
137+ Just t
138+ | t /= LV n && n `notElem` rec ->
139+ eval stk env (n : rec) defs t
140+ | otherwise -> return (unload stk t)
141+ Nothing
142+ | n `notElem` rec,
143+ Just (LFun opts _ args body) <- lookupCtxtExact n defs,
144+ Inline `elem` opts ->
145+ apply stk env (n : rec) defs var args body
146+ | Just (LConstructor n t a) <- lookupCtxtExact n defs ->
147+ return (LCon Nothing t n stk)
148+ | otherwise -> return (unload stk var)
149+eval stk env rec defs t = return (unload stk t)
150+
151+evalAlt stk env rec defs (LConCase i n es rhs)
152+ = do ns' <- mapM (\n -> do n' <- nextN
153+ return (n, n')) es
154+ LConCase i n (map snd ns') <$>
155+ eval stk (map (\ (n, n') -> (n, LV n')) ns' ++ env) rec defs rhs
156+evalAlt stk env rec defs (LConstCase c e)
157+ = LConstCase c <$> eval stk env rec defs e
158+evalAlt stk env rec defs (LDefaultCase e)
159+ = LDefaultCase <$> eval stk env rec defs e
160+
161+apply :: [LExp] -> [(Name, LExp)] -> [Name] -> LDefs -> LExp ->
162+ [Name] -> LExp -> State Int LExp
163+apply stk env rec defs var args body
164+ = eval stk env rec defs (LLam args body)
165+
166+dropArgs :: [Name] -> LAlt -> State Int LAlt
167+dropArgs as (LConCase i n es (LLam args rhs))
168+ = do let old = take (length as) args
169+ rhs' <- eval [] (zipWith (\ o n -> (o, LV n)) old as) [] emptyContext rhs
170+ return (LConCase i n es rhs')
171+dropArgs as (LConstCase c (LLam args rhs))
172+ = do let old = take (length as) args
173+ rhs' <- eval [] (zipWith (\ o n -> (o, LV n)) old as) [] emptyContext rhs
174+ return (LConstCase c rhs')
175+dropArgs as (LDefaultCase (LLam args rhs))
176+ = do let old = take (length as) args
177+ rhs' <- eval [] (zipWith (\ o n -> (o, LV n)) old as) [] emptyContext rhs
178+ return (LDefaultCase rhs')
179+
180+caseFloat :: LExp -> LExp
181+caseFloat (LApp tc e es) = LApp tc (caseFloat e) (map caseFloat es)
182+caseFloat (LLazyExp e) = LLazyExp (caseFloat e)
183+caseFloat (LForce e) = LForce (caseFloat e)
184+caseFloat (LCon up i n es) = LCon up i n (map caseFloat es)
185+caseFloat (LOp f es) = LOp f (map caseFloat es)
186+caseFloat (LLam ns sc) = LLam ns (caseFloat sc)
187+caseFloat (LLet v val sc) = LLet v (caseFloat val) (caseFloat sc)
188+caseFloat (LCase _ (LCase ct exp alts) alts')
189+ | all conRHS alts || length alts == 1
190+ = conOpt $ replaceInCase (LCase ct (caseFloat exp) (map (updateWith alts') alts))
191+ where
192+ conRHS (LConCase _ _ _ (LCon _ _ _ _)) = True
193+ conRHS (LConstCase _ (LCon _ _ _ _)) = True
194+ conRHS (LDefaultCase (LCon _ _ _ _)) = True
195+ conRHS _ = False
196+
197+ updateWith alts (LConCase i n es rhs) =
198+ LConCase i n es (caseFloat (conOpt (LCase Shared (caseFloat rhs) alts)))
199+ updateWith alts (LConstCase c rhs) =
200+ LConstCase c (caseFloat (conOpt (LCase Shared (caseFloat rhs) alts)))
201+ updateWith alts (LDefaultCase rhs) =
202+ LDefaultCase (caseFloat (conOpt (LCase Shared (caseFloat rhs) alts)))
203+
204+caseFloat (LCase ct exp alts')
205+ = conOpt $ replaceInCase (LCase ct (caseFloat exp) (map cfAlt alts'))
206+ where
207+ cfAlt (LConCase i n es rhs) = LConCase i n es (caseFloat rhs)
208+ cfAlt (LConstCase c rhs) = LConstCase c (caseFloat rhs)
209+ cfAlt (LDefaultCase rhs) = LDefaultCase (caseFloat rhs)
210+caseFloat exp = exp
211+
212+-- Case of constructor
213+conOpt :: LExp -> LExp
214+conOpt (LCase ct (LCon _ t n args) alts)
215+ = pickAlt n args alts
216+ where
217+ pickAlt n args (LConCase i n' es rhs : as) | n == n'
218+ = substAll (zip es args) rhs
219+ pickAlt _ _ (LDefaultCase rhs : as) = rhs
220+ pickAlt n args (_ : as) = pickAlt n args as
221+ pickAlt n args [] = error "Can't happen pickAlt - impossible case found"
222+
223+ substAll [] rhs = rhs
224+ substAll ((n, tm) : ss) rhs = lsubst n tm (substAll ss rhs)
225+conOpt tm = tm
226+
227+replaceInCase :: LExp -> LExp
228+replaceInCase (LCase ty e alts)
229+ = LCase ty e (replaceInAlts e alts)
230+replaceInCase exp = exp
231+
232+replaceInAlts :: LExp -> [LAlt] -> [LAlt]
233+replaceInAlts exp alts = dropDups $ concatMap (replaceInAlt exp) alts
234+
235+-- Drop overlapping case (arising from case merging of overlapping
236+-- patterns)
237+dropDups (alt@(LConCase _ i n ns) : alts)
238+ = alt : dropDups (filter (notTag i) alts)
36239 where
37− inlineWith :: [Name] -> [(Name, LExp)] -> LExp -> State Int LExp
38− inlineWith done env var@(LV n)
39− = case lookup n env of
40− Just t -> return t
41− Nothing -> return var
42− inlineWith done env (LLazyApp n es) = LLazyApp n <$> (mapM (inlineWith done env) es)
43− inlineWith done env (LForce e) = LForce <$> inlineWith done env e
44− inlineWith done env (LLazyExp e) = LLazyExp <$> inlineWith done env e
45− -- Extend the environment for Let and Lam so that bound names aren't
46− -- expanded with any top level argument definitions they shadow
47− inlineWith done env (LLet n val sc)
48− = do n' <- nextN
49− LLet n' <$> inlineWith done env val <*>
50− inlineWith done ((n, LV n') : env) sc
51− inlineWith done env (LLam args sc)
52− = do ns' <- mapM (\n -> do n' <- nextN
53− return (n, n')) args
54− LLam (map snd ns') <$>
55− inlineWith done (map (\ (n,n') -> (n, LV n')) ns' ++ env) sc
56− inlineWith done env (LProj exp i) = LProj <$> inlineWith done env exp <*> return i
57− inlineWith done env (LCon loc i n es)
58− = LCon loc i n <$> mapM (inlineWith done env) es
59− inlineWith done env (LCase ty e alts)
60− = LCase ty <$> inlineWith done env e <*> mapM (inlineWithAlt done env) alts
61− inlineWith done env (LOp f es) = LOp f <$> mapM (inlineWith done env) es
62− -- the interesting case!
63− inlineWith done env (LApp t (LV n) es)
64− | n `notElem` done,
65− [LFun opts _ args body] <- lookupCtxt n defs,
66− Inline `elem` opts,
67− length es == length args
68− = do es' <- mapM (inlineWith done env) es
69− inlineWith (n : done) (zip args es' ++ env) body
70− inlineWith done env (LApp t f es)
71− = LApp t <$> inlineWith done env f <*> mapM (inlineWith done env) es
72− inlineWith done env (LForeign t s args)
73− = LForeign t s <$> mapM (\(t, e) -> do e' <- inlineWith done env e
74− return (t, e')) args
75− inlineWith done env t = return t
76−
77− inlineWithAlt done env (LConCase i n es rhs)
78− = do ns' <- mapM (\n -> do n' <- nextN
79− return (n, n')) es
80− LConCase i n (map snd ns') <$>
81− inlineWith done (map (\ (n,n') -> (n, LV n')) ns' ++ env) rhs
82− inlineWithAlt done env (LConstCase c e) = LConstCase c <$> inlineWith done env e
83− inlineWithAlt done env (LDefaultCase e) = LDefaultCase <$> inlineWith done env e
240+ notTag i (LConCase _ j n ns) = i /= j
241+ notTag _ _ = True
242+dropDups (c : alts) = c : dropDups alts
243+dropDups [] = []
244+
245+
246+replaceInAlt :: LExp -> LAlt -> [LAlt]
247+-- In an alternative, if the case appears on the right hand side, replace
248+-- it with the given expression, to preserve sharing
249+replaceInAlt exp@(LV _) (LConCase i con args rhs)
250+ = [LConCase i con args $
251+ replaceExp (LCon Nothing i con (map LV args)) exp rhs]
252+-- if a default case inspects the same variable as the case it's in,
253+-- remove the inspection and replace with the alternatives
254+-- (i.e. merge the inner case block)
255+replaceInAlt exp@(LV var) (LDefaultCase (LCase ty (LV var') alts))
256+ | var == var' = alts
257+replaceInAlt exp a = [a]
258+
259+replaceExp :: LExp -> LExp -> LExp -> LExp
260+replaceExp (LCon _ t n args) new (LCon _ t' n' args')
261+ | n == n' && args == args' = new
262+replaceExp (LCon _ t n args) new (LApp _ (LV n') args')
263+ | n == n' && args == args' = new
264+replaceExp old new tm = tm
265+
266+-- dropArgs as (LConstCase c rhs) = LConstCase c (dropRHS as rhs)
267+-- dropArgs as (LDefaultCase rhs) = LDefaultCase (dropRHS as rhs)
268+
269+getRHS (LConCase i n es rhs) = rhs
270+getRHS (LConstCase _ rhs) = rhs
271+getRHS (LDefaultCase rhs) = rhs
272+
273+getLams [] = []
274+getLams (LLam args tm : cs) = getLamPrefix args cs
275+getLams _ = []
276+
277+getLamPrefix as [] = as
278+getLamPrefix as (LLam args tm : cs)
279+ | length args < length as = getLamPrefix args cs
280+ | otherwise = getLamPrefix as cs
281+getLamPrefix as (_ : cs) = []
282+
283+-- eta contract ('\x -> f x' can just be compiled as 'f' when f is local)
284+eta :: LExp -> LExp
285+eta (LApp tc a es) = LApp tc (eta a) (map eta es)
286+eta (LLazyApp n es) = LLazyApp n (map eta es)
287+eta (LLazyExp e) = LLazyExp (eta e)
288+eta (LForce e) = LForce (eta e)
289+eta (LLet n val sc) = LLet n (eta val) (eta sc)
290+eta (LLam args (LApp tc f args'))
291+ | args' == map LV args = eta f
292+eta (LLam args e) = LLam args (eta e)
293+eta (LProj e i) = LProj (eta e) i
294+eta (LCon a t n es) = LCon a t n (map eta es)
295+eta (LCase ct e alts) = LCase ct (eta e) (map (fmap eta) alts)
296+eta (LOp f es) = LOp f (map eta es)
297+eta tm = tm
298+
src/Idris/Core/CaseTree.hs+52−1
@@ -279,7 +279,8 @@ simpleCase tc defcase reflect phase fc inacc argtys cs erInfo
279279 (tree, st) = runCaseBuilder erInfo
280280 (match ns' ps' defcase)
281281 ([], numargs, [])
282− t = CaseDef ns (prune proj (depatt ns' tree)) (fstT st) in
282+ sc = removeUnreachable (prune proj (depatt ns' tree))
283+ t = CaseDef ns sc (fstT st) in
283284 if proj then return (stripLambdas t)
284285 else return t
285286 Error err -> Error (At fc err)
@@ -765,6 +766,56 @@ prune proj (Case up n alts) = case alts' of
765766
766767prune _ t = t
767768
769+-- Remove any branches we can't reach because of variables we've already
770+-- tested
771+removeUnreachable :: SC -> SC
772+removeUnreachable sc = ru [] sc
773+ where
774+ -- keep a mapping from variable names, to the constructor tag we've
775+ -- already checked it as in this branch
776+ ru :: [(Name, Int)] -> SC -> SC
777+ ru checked (Case t n alts)
778+ = let alts' = map (ruAlt checked n) (dropImpossible (lookup n checked) alts) in
779+ Case t n alts'
780+ ru checked t = t
781+
782+ dropImpossible Nothing alts = alts
783+ dropImpossible (Just t) [] = []
784+ dropImpossible (Just t) (ConCase con tag args sc : rest)
785+ | t == tag = [ConCase con tag args sc] -- must be this case
786+ | otherwise = dropImpossible (Just t) rest -- can't be this case
787+ dropImpossible (Just t) (c : rest)
788+ = c : dropImpossible (Just t) rest
789+
790+ ruAlt :: [(Name, Int)] -> Name -> CaseAlt -> CaseAlt
791+ ruAlt checked var (ConCase con tag args sc)
792+ = let checked' = dropChecked args (updateChecked var tag checked)
793+ sc' = ru checked' sc in
794+ ConCase con tag args sc'
795+ ruAlt checked var (FnCase n args sc)
796+ = let checked' = dropChecked [var] checked
797+ sc' = ru checked' sc in
798+ FnCase n args sc'
799+ ruAlt checked var (ConstCase c sc)
800+ = let checked' = dropChecked [var] checked
801+ sc' = ru checked' sc in
802+ ConstCase c sc'
803+ ruAlt checked var (SucCase n sc)
804+ = let checked' = dropChecked [var] checked
805+ sc' = ru checked' sc in
806+ SucCase n sc'
807+ ruAlt checked var (DefaultCase sc)
808+ = let checked' = dropChecked [var] checked
809+ sc' = ru checked' sc in
810+ DefaultCase sc'
811+
812+ updateChecked :: Name -> Int -> [(Name, Int)] -> [(Name, Int)]
813+ updateChecked n i checked
814+ = (n, i) : filter (\x -> fst x /= n) checked
815+
816+ dropChecked :: [Name] -> [(Name, Int)] -> [(Name, Int)]
817+ dropChecked ns checked = filter (\x -> fst x `notElem` ns) checked
818+
768819stripLambdas :: CaseDef -> CaseDef
769820stripLambdas (CaseDef ns (STerm (Bind x (Lam _ _) sc)) tm)
770821 = stripLambdas (CaseDef (ns ++ [x]) (STerm (instantiate (P Bound x Erased) sc)) tm)
stack-nightly.yamlnew file+17
@@ -0,0 +1,17 @@
1+#recheck extra-deps next on resolver or cabal file change
2+resolver: nightly-2017-11-25
3+
4+packages:
5+ - location: .
6+
7+flags:
8+ idris:
9+ FFI: true
10+ GMP: true
11+
12+ghc-options:
13+ idris: -fwarn-unused-imports -fwarn-unused-binds
14+
15+nix:
16+ enable: false
17+ shell-file: stack-shell.nix
stack.yaml+6−1
@@ -1,9 +1,14 @@
11#recheck extra-deps next on resolver or cabal file change
2−resolver: nightly-2017-11-25
2+resolver: lts-9.17
33
44packages:
55 - location: .
66
7+extra-deps:
8+ - binary-0.8.5.1
9+ - cheapskate-0.1.1
10+ - megaparsec-6.2.0
11+
712flags:
813 idris:
914 FFI: true
test/README.md+1
@@ -91,6 +91,7 @@ Tests are categorised with the following test families (and their identifiers):
9191+ *reg*: Regression tests, covering previous bug fixes
9292+ *regression*: Regression tests, covering previous bug fixes
9393+ *sourceLocation*: Interaction with files from Idris
94++ *st*: ST, state transition systems
9495+ *sugar*: Syntactic sugar, syntax extensions
9596+ *syntax*: Syntax extensions
9697+ *tactics*: Testing for tactics
test/TestData.hs+8
@@ -276,6 +276,14 @@ testFamiliesData = [
276276 ( 3 , ANY )]),
277277 ("sourceLocation", "Source location",
278278 [ ( 1 , ANY )]),
279+ ("st", "ST",
280+ [ ( 1, C_CG),
281+ ( 2, C_CG),
282+ ( 3, C_CG),
283+ ( 4, C_CG),
284+ ( 5, C_CG),
285+ ( 6, C_CG),
286+ ( 7, C_CG)]),
279287 ("sugar", "Syntactic sugar",
280288 [ ( 1, ANY ),
281289 ( 2, ANY ),
test/st001/expectednew file+8
@@ -0,0 +1,8 @@
1+# test001:
2+--test IO:
3+["HELLO!!\n", "WORLD!!"]
4+2
5+--test IOExcept:
6+["HELLO!!\n", "WORLD!!"]
7+2
8+()
test/st001/runnew file+6
@@ -0,0 +1,6 @@
1+#!/usr/bin/env bash
2+${IDRIS:-idris} $@ -p contrib test001.idr -o test001
3+echo "# test001:"
4+./test001
5+rm -f test001 *.ibc
6+
test/st001/test001.idrnew file+66
@@ -0,0 +1,66 @@
1+module Main
2+
3+import Control.IOExcept
4+import Control.ST
5+import Control.ST.File
6+import Control.ST.ImplicitCall
7+
8+increment : (x : Var) -> STrans m () [ x ::: State Int ]
9+ (const [x ::: State Int])
10+increment x = do num <- read x
11+ write x (num + 1)
12+
13+readFileCount : (ConsoleIO m, File m) =>
14+ (fileHandle : Var)
15+ -> (count : Var)
16+ -> {auto prf : ValidModeRead mode}
17+ -> ST m (Either FileError (List String))
18+ [ count ::: (State Int),
19+ fileHandle ::: FileHandleI {m} mode ]
20+readFileCount fh cnt =
21+ readAcc fh cnt []
22+ where
23+ readAcc : (ConsoleIO m, File m) =>
24+ (fileHandle : Var)
25+ -> (count : Var)
26+ -> List String
27+ -> {auto prf : ValidModeRead mode}
28+ -> ST m (Either FileError (List String))
29+ [ count ::: (State Int),
30+ fileHandle ::: FileHandleI {m} mode ]
31+ readAcc fileHandle cnt acc = with ST do
32+ e <- (eof fileHandle)
33+ if (not e)
34+ then do Right str <- (readLine fileHandle)
35+ | Left ferr => pure (Left ferr)
36+ (increment cnt)
37+ readAcc fileHandle cnt (str :: acc)
38+ else do let rev = reverse acc
39+ pure (Right rev)
40+
41+testFile : (ConsoleIO m, File m) => ST m () []
42+testFile = with ST do
43+ Right fileHandle <- open "testFile" Read
44+ | Left ferr => do putStrLn (show ferr)
45+ pure ()
46+ count <- new 0
47+ Right fContents <- readFileCount fileHandle count
48+ | Left ferr => do putStrLn (show ferr)
49+ delete count
50+ close fileHandle
51+ pure ()
52+ putStrLn (show fContents)
53+ putStrLn (show !(read count))
54+ delete count
55+ close fileHandle
56+ pure ()
57+
58+main : IO ()
59+main = do putStrLn "--test IO:"
60+ run testFile
61+ putStrLn "--test IOExcept:"
62+ ioe_run (run testFile)
63+ (\err => putStrLn err)
64+ (\ok => printLn ok)
65+
66+-- EOF -------------------------------------------------------------------------
test/st001/testFilenew file+2
@@ -0,0 +1,2 @@
1+HELLO!!
2+WORLD!!
test/st002/expectednew file+8
@@ -0,0 +1,8 @@
1+# test002:
2+--test IO:
3+['H', 'E', 'L', 'L', 'O', '!', '!', '\n', 'W', 'O', 'R', 'L', 'D', '!', '!', '\NUL']
4+16
5+--test IOExcept:
6+['H', 'E', 'L', 'L', 'O', '!', '!', '\n', 'W', 'O', 'R', 'L', 'D', '!', '!', '\NUL']
7+16
8+()
test/st002/runnew file+6
@@ -0,0 +1,6 @@
1+#!/usr/bin/env bash
2+${IDRIS:-idris} $@ -p contrib test002.idr -o test002
3+echo "# test002:"
4+./test002
5+rm -f test002 *.ibc
6+
test/st002/test002.idrnew file+66
@@ -0,0 +1,66 @@
1+module Main
2+
3+import Control.IOExcept
4+import Control.ST
5+import Control.ST.File
6+import Control.ST.ImplicitCall
7+
8+increment : (x : Var) -> STrans m () [ x ::: State Int ]
9+ (const [x ::: State Int])
10+increment x = do num <- read x
11+ write x (num + 1)
12+
13+readFileCount : (ConsoleIO m, File m) =>
14+ (fileHandle : Var)
15+ -> (count : Var)
16+ -> {auto prf : ValidModeRead mode}
17+ -> ST m (Either FileError (List Char))
18+ [ count ::: (State Int),
19+ fileHandle ::: FileHandleI {m} mode ]
20+readFileCount fh cnt =
21+ readAcc fh cnt []
22+ where
23+ readAcc : (ConsoleIO m, File m) =>
24+ (fileHandle : Var)
25+ -> (count : Var)
26+ -> List Char
27+ -> {auto prf : ValidModeRead mode}
28+ -> ST m (Either FileError (List Char))
29+ [ count ::: (State Int),
30+ fileHandle ::: FileHandleI {m} mode ]
31+ readAcc fileHandle cnt acc = with ST do
32+ e <- (eof fileHandle)
33+ if (not e)
34+ then do Right chr <- (readChar fileHandle)
35+ | Left ferr => pure (Left ferr)
36+ (increment cnt)
37+ readAcc fileHandle cnt (chr :: acc)
38+ else do let rev = reverse acc
39+ pure (Right rev)
40+
41+testFile : (ConsoleIO m, File m) => ST m () []
42+testFile = with ST do
43+ Right fileHandle <- open "testFile" Read
44+ | Left ferr => do putStrLn (show ferr)
45+ pure ()
46+ count <- new 0
47+ Right fContents <- readFileCount fileHandle count
48+ | Left ferr => do putStrLn (show ferr)
49+ delete count
50+ close fileHandle
51+ pure ()
52+ putStrLn (show fContents)
53+ putStrLn (show !(read count))
54+ delete count
55+ close fileHandle
56+ pure ()
57+
58+main : IO ()
59+main = do putStrLn "--test IO:"
60+ run testFile
61+ putStrLn "--test IOExcept:"
62+ ioe_run (run testFile)
63+ (\err => putStrLn err)
64+ (\ok => printLn ok)
65+
66+-- EOF -------------------------------------------------------------------------
test/st002/testFilenew file+2
@@ -0,0 +1,2 @@
1+HELLO!!
2+WORLD!!
test/st003/expectednew file+8
@@ -0,0 +1,8 @@
1+# test003:
2+--test IO:
3+HELLO!!
4+WORLD!!
5+--test IOExcept:
6+HELLO!!
7+WORLD!!
8+()
test/st003/runnew file+6
@@ -0,0 +1,6 @@
1+#!/usr/bin/env bash
2+${IDRIS:-idris} $@ -p contrib test003.idr -o test003
3+echo "# test003:"
4+./test003
5+rm -f test003 *.ibc
6+
test/st003/test003.idrnew file+25
@@ -0,0 +1,25 @@
1+module Main
2+
3+import Control.IOExcept
4+import Control.ST
5+import Control.ST.File
6+import Control.ST.ImplicitCall
7+
8+testFile : (ConsoleIO m, File m) => ST m () []
9+testFile = with ST do
10+ Right str <- readFile "testFile"
11+ | Left ferr => do putStrLn (show ferr)
12+ pure ()
13+ putStrLn str
14+ pure ()
15+
16+
17+main : IO ()
18+main = do putStrLn "--test IO:"
19+ run testFile
20+ putStrLn "--test IOExcept:"
21+ ioe_run (run testFile)
22+ (\err => putStrLn err)
23+ (\ok => printLn ok)
24+
25+-- EOF -------------------------------------------------------------------------
test/st003/testFilenew file+2
@@ -0,0 +1,2 @@
1+HELLO!!
2+WORLD!!
test/st004/expectednew file+6
@@ -0,0 +1,6 @@
1+# test004:
2+--test IO:
3+File Not Found
4+--test IOExcept:
5+File Not Found
6+()
test/st004/runnew file+6
@@ -0,0 +1,6 @@
1+#!/usr/bin/env bash
2+${IDRIS:-idris} $@ -p contrib test004.idr -o test004
3+echo "# test004:"
4+./test004
5+rm -f test004 *.ibc
6+
test/st004/test004.idrnew file+24
@@ -0,0 +1,24 @@
1+module Main
2+
3+import Control.IOExcept
4+import Control.ST
5+import Control.ST.File
6+import Control.ST.ImplicitCall
7+
8+testFile : (ConsoleIO m, File m) => ST m () []
9+testFile = with ST do
10+ Right str <- readFile "noneexistingtestFile"
11+ | Left ferr => do putStrLn (show ferr)
12+ pure ()
13+ putStr str
14+ pure ()
15+
16+main : IO ()
17+main = do putStrLn "--test IO:"
18+ run testFile
19+ putStrLn "--test IOExcept:"
20+ ioe_run (run testFile)
21+ (\err => putStrLn err)
22+ (\ok => printLn ok)
23+
24+-- EOF -------------------------------------------------------------------------
test/st005/expectednew file+6
@@ -0,0 +1,6 @@
1+# test005:
2+--test IO:
3+--test IOExcept:
4+()
5+HELLO!!
6+WORLD!!
test/st005/runnew file+7
@@ -0,0 +1,7 @@
1+#!/usr/bin/env bash
2+${IDRIS:-idris} $@ -p contrib test005.idr -o test005
3+echo "# test005:"
4+./test005
5+cat writeTestFile
6+rm -f test005 writeTestFile *.ibc
7+
test/st005/test005.idrnew file+33
@@ -0,0 +1,33 @@
1+module Main
2+
3+import Control.IOExcept
4+import Control.ST
5+import Control.ST.File
6+import Control.ST.ImplicitCall
7+
8+testFile : (ConsoleIO m, File m) => ST m () []
9+testFile = with ST do
10+ Right fileHandle <- open "writeTestFile" WriteTruncate
11+ | Left ferr => do putStrLn (show ferr)
12+ pure ()
13+ Right _ <- writeLine fileHandle "HELLO!!"
14+ | Left ferr => do putStrLn (show ferr)
15+ close fileHandle
16+ pure ()
17+ Right _ <- writeLine fileHandle "WORLD!!"
18+ | Left ferr => do putStrLn (show ferr)
19+ close fileHandle
20+ pure ()
21+ close fileHandle
22+ pure ()
23+
24+
25+main : IO ()
26+main = do putStrLn "--test IO:"
27+ run testFile
28+ putStrLn "--test IOExcept:"
29+ ioe_run (run testFile)
30+ (\err => putStrLn err)
31+ (\ok => printLn ok)
32+
33+-- EOF -------------------------------------------------------------------------
test/st006/expectednew file+5
@@ -0,0 +1,5 @@
1+# test006:
2+--test IO:
3+--test IOExcept:
4+()
5+HELLO!!WORLD!!
test/st006/runnew file+6
@@ -0,0 +1,6 @@
1+#!/usr/bin/env bash
2+${IDRIS:-idris} $@ -p contrib test006.idr -o test006
3+echo "# test006:"
4+./test006
5+cat writeStringTestFile
6+rm -f test006 writeStringTestFile *.ibc
test/st006/test006.idrnew file+37
@@ -0,0 +1,37 @@
1+module Main
2+
3+import Control.IOExcept
4+import Control.ST
5+import Control.ST.File
6+import Control.ST.ImplicitCall
7+
8+testFile : (ConsoleIO m, File m) => ST m () []
9+testFile = with ST do
10+ Right fileHandle <- open "writeStringTestFile" WriteTruncate
11+ | Left ferr => do putStrLn (show ferr)
12+ pure ()
13+ Right _ <- writeString fileHandle "HELLO!!"
14+ | Left ferr => do putStrLn (show ferr)
15+ close fileHandle
16+ pure ()
17+ Right _ <- writeString fileHandle "WORLD!!"
18+ | Left ferr => do putStrLn (show ferr)
19+ close fileHandle
20+ pure ()
21+ Right _ <- writeString fileHandle "\n"
22+ | Left ferr => do putStrLn (show ferr)
23+ close fileHandle
24+ pure ()
25+ close fileHandle
26+ pure ()
27+
28+
29+main : IO ()
30+main = do putStrLn "--test IO:"
31+ run testFile
32+ putStrLn "--test IOExcept:"
33+ ioe_run (run testFile)
34+ (\err => putStrLn err)
35+ (\ok => printLn ok)
36+
37+-- EOF -------------------------------------------------------------------------
test/st007/expectednew file+6
@@ -0,0 +1,6 @@
1+# test007:
2+--test IO:
3+--test IOExcept:
4+()
5+HELLO!!
6+WORLD!!
test/st007/runnew file+6
@@ -0,0 +1,6 @@
1+#!/usr/bin/env bash
2+${IDRIS:-idris} $@ -p contrib test007.idr -o test007
3+echo "# test007:"
4+./test007
5+cat writeFileTestFile
6+rm -f test007 writeFileTestFile *.ibc
test/st007/test007.idrnew file+24
@@ -0,0 +1,24 @@
1+module Main
2+
3+import Control.IOExcept
4+import Control.ST
5+import Control.ST.File
6+import Control.ST.ImplicitCall
7+
8+testFile : (ConsoleIO m, File m) => ST m () []
9+testFile = with ST do
10+ Right _ <- writeFile "writeFileTestFile" "HELLO!!\nWORLD!!\n"
11+ | Left ferr => do putStrLn (show ferr)
12+ pure ()
13+ pure ()
14+
15+
16+main : IO ()
17+main = do putStrLn "--test IO:"
18+ run testFile
19+ putStrLn "--test IOExcept:"
20+ ioe_run (run testFile)
21+ (\err => putStrLn err)
22+ (\ok => printLn ok)
23+
24+-- EOF -------------------------------------------------------------------------
test/views001/views001.idr+1−1
@@ -26,7 +26,7 @@ mergeSort xs with (splitRec xs)
2626testList : Int -> Int -> List Int -> List Int
2727testList 0 seed acc = acc
2828-- Need to explicitly mod since different back ends overflow differently
29−testList x seed acc = let seed' = seed * 12345 + 768 `mod` 65536 in
29+testList x seed acc = let seed' = (seed * 12345 + 768) `mod` 65536 in
3030 testList (x - 1) seed'
3131 ((seed' `mod` 100) :: acc)
3232
test/views001/views001a.idr+1−1
@@ -13,7 +13,7 @@ mergeSort xs with (splitRec xs)
1313testList : Int -> Int -> List Int -> List Int
1414testList 0 seed acc = acc
1515-- Need to explicitly mod since different back ends overflow differently
16−testList x seed acc = let seed' = seed * 12345 + 768 `mod` 65536 in
16+testList x seed acc = let seed' = (seed * 12345 + 768) `mod` 65536 in
1717 testList (x - 1) seed'
1818 ((seed' `mod` 100) :: acc)
1919
test/views002/views002.idr+1−1
@@ -11,7 +11,7 @@ qsort inp with (filtered (<) inp)
1111testList : Int -> Int -> List Int -> List Int
1212testList 0 seed acc = acc
1313-- Need to explicitly mod since different back ends overflow differently
14−testList x seed acc = let seed' = seed * 12345 + 768 `mod` 65536 in
14+testList x seed acc = let seed' = (seed * 12345 + 768) `mod` 65536 in
1515 testList (x - 1) seed'
1616 ((seed' `mod` 100) :: acc)
1717