aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/aoc22_1.milch29
-rw-r--r--examples/aoc22_1.txt14
-rw-r--r--src/Builtins.hs48
-rw-r--r--src/Utils.hs19
-rw-r--r--stdlib/common.milch40
5 files changed, 150 insertions, 0 deletions
diff --git a/examples/aoc22_1.milch b/examples/aoc22_1.milch
new file mode 100644
index 0000000..4170661
--- /dev/null
+++ b/examples/aoc22_1.milch
@@ -0,0 +1,29 @@
+(import! "stdlib/common.milch")
+
+;; utils
+
+; convert ["a" "b" "c"] into "abc"
+(let! str-from-vec (\[vec]
+ (foldr concat "" vec)))
+
+;; solution
+
+(let! sample-path "examples/aoc22_1.txt")
+(let! sample-input (read-file! sample-path))
+
+(print-fmt! "Read {0} characters from \"{1}\"\n" [
+ (len sample-input)
+ sample-path])
+
+(let! sample-vec (to-vec sample-input))
+
+(let! result1 (pipe sample-vec [
+ (split-by "\n")
+ (map str-from-vec)
+ (split-by "")
+ (map (map parse-int))
+ (map (foldr + 0))
+ max
+]))
+
+(print-fmt! "Result 1: {0}\n" [result1])
diff --git a/examples/aoc22_1.txt b/examples/aoc22_1.txt
new file mode 100644
index 0000000..2094f91
--- /dev/null
+++ b/examples/aoc22_1.txt
@@ -0,0 +1,14 @@
+1000
+2000
+3000
+
+4000
+
+5000
+6000
+
+7000
+8000
+9000
+
+10000
diff --git a/src/Builtins.hs b/src/Builtins.hs
index ec14c2f..b731e66 100644
--- a/src/Builtins.hs
+++ b/src/Builtins.hs
@@ -29,8 +29,13 @@ builtinEnv = M.fromList [
-- string operations
builtinSubstr,
builtinStrToVec,
+ builtinLen,
-- vector & string operations
builtinConcat,
+ -- filesystem operations
+ builtinReadFile,
+ builtinWriteFile,
+ builtinAppendFile,
-- special
builtinPrint,
("unit", makeNonsenseAST ASTUnit),
@@ -246,6 +251,13 @@ builtinConcat = (name, makeNonsenseAST $ ASTFunction True fn1) where
fn2 ast2 = throwL (astPos ast2) $ argError2 name ast1 ast2
fn1 ast1 = throwL (astPos ast1) $ argError1 name ast1
+builtinLen :: (String, AST)
+builtinLen = (name, makeNonsenseAST $ ASTFunction True fn1) where
+ name = "len"
+ fn1 AST { astNode = ASTString str } =
+ return $ makeNonsenseAST $ ASTInteger $ length str
+ fn1 ast1 = throwL (astPos ast1) $ argError1 name ast1
+
builtinFatal :: (String, AST)
builtinFatal = (name, makeNonsenseAST $ ASTFunction False fn1) where
name = "fatal!"
@@ -260,3 +272,39 @@ builtinKind = (name, makeNonsenseAST $ ASTFunction True fn1) where
fn1 AST { astNode = ASTRecord identifier _} =
return $ makeNonsenseAST $ ASTString identifier
fn1 ast1 = throwL (astPos ast1) $ argError1 name ast1
+
+builtinReadFile :: (String, AST)
+builtinReadFile = (name, makeNonsenseAST $ ASTFunction False fn1) where
+ name = "read-file!"
+ fn1 ast1@AST { astNode = ASTString filePath } = do
+ contentsM <- liftIO $ safeReadFile filePath
+ case contentsM of
+ Just contents -> return $ makeNonsenseAST $ ASTString contents
+ Nothing -> throwL (astPos ast1) $ "failed to read file: " ++ filePath
+ fn1 ast1 = throwL (astPos ast1) $ argError1 name ast1
+
+builtinWriteFile :: (String, AST)
+builtinWriteFile = (name, makeNonsenseAST $ ASTFunction False fn1) where
+ name = "write-file!"
+ fn1 ast1@AST { astNode = ASTString filePath } =
+ return $ makeNonsenseAST $ ASTFunction True $ fn2 where
+ fn2 AST { astNode = ASTString content } = do
+ resultM <- liftIO $ safeWriteFile filePath content
+ case resultM of
+ Just () -> return $ makeNonsenseAST $ ASTUnit
+ Nothing -> throwL (astPos ast1) $ "failed to write file: " ++ filePath
+ fn2 ast2 = throwL (astPos ast2) $ argError2 name ast1 ast2
+ fn1 ast1 = throwL (astPos ast1) $ argError1 name ast1
+
+builtinAppendFile :: (String, AST)
+builtinAppendFile = (name, makeNonsenseAST $ ASTFunction False fn1) where
+ name = "append-file!"
+ fn1 ast1@AST { astNode = ASTString filePath } =
+ return $ makeNonsenseAST $ ASTFunction True $ fn2 where
+ fn2 AST { astNode = ASTString content } = do
+ resultM <- liftIO $ safeAppendFile filePath content
+ case resultM of
+ Just () -> return $ makeNonsenseAST $ ASTUnit
+ Nothing -> throwL (astPos ast1) $ "failed to append to file: " ++ filePath
+ fn2 ast2 = throwL (astPos ast2) $ argError2 name ast1 ast2
+ fn1 ast1 = throwL (astPos ast1) $ argError1 name ast1
diff --git a/src/Utils.hs b/src/Utils.hs
index bcac58e..2f9e3c0 100644
--- a/src/Utils.hs
+++ b/src/Utils.hs
@@ -2,6 +2,7 @@
module Utils where
import Control.Monad.Except
+import Control.Exception (IOException, catch)
import Control.Monad.State
import qualified Data.Map as M
import qualified Data.List as L
@@ -301,3 +302,21 @@ separateNsIdPart identifier =
nsPartText = T.concat $ L.init parts
idPartText = L.last parts
in (T.unpack nsPartText, T.unpack idPartText)
+
+safeReadFile :: FilePath -> IO (Maybe String)
+safeReadFile p = (Just <$> readFile p) `catch` handler
+ where
+ handler :: IOException -> IO (Maybe String)
+ handler _ = pure Nothing
+
+safeWriteFile :: FilePath -> String -> IO (Maybe ())
+safeWriteFile p content = (Just <$> writeFile p content) `catch` handler
+ where
+ handler :: IOException -> IO (Maybe ())
+ handler _ = pure Nothing
+
+safeAppendFile :: FilePath -> String -> IO (Maybe ())
+safeAppendFile p content = (Just <$> appendFile p content) `catch` handler
+ where
+ handler :: IOException -> IO (Maybe ())
+ handler _ = pure Nothing
diff --git a/stdlib/common.milch b/stdlib/common.milch
index b04cf37..b69452e 100644
--- a/stdlib/common.milch
+++ b/stdlib/common.milch
@@ -59,3 +59,43 @@
(let! flow (\[fs] (foldr compose id (reverse fs))))
(let! pipe (\[x fs] ((flow fs) x)))
+
+(let! leq? (\[a b]
+ (or?
+ (eq? a b)
+ (lt? a b))))
+
+(let! rt? (compose not leq?))
+(let! req? (compose not lt?))
+
+(let! max2 (\[a b]
+ (match (lt? a b)
+ true b
+ false a)))
+
+(let! max (\[vals]
+ (let! lazy v (head vals))
+ (let! vs (tail vals))
+
+ (match vs
+ [] v
+ otherwise (max2 v (max vs)))))
+
+(let! split-by' (\[delim acc vals]
+ (let! lazy v (head vals))
+ (let! vs (tail vals))
+
+ (match vs
+ [] (match v
+ delim [(reverse acc)]
+ otherwise [(prepend v (reverse acc))])
+ otherwise (match v
+ delim (prepend (reverse acc) (split-by' delim [] vs))
+ otherwise (split-by' delim (prepend v acc) vs)))))
+
+; split vector by delimiter
+(let! split-by (\[delim vals]
+ (split-by' delim [] vals)))
+
+(let! print-fmt! (\![fstr args]
+ (print! (fmt fstr args))))