summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lambda-calcul/haskell/app/Main.hs6
-rw-r--r--lambda-calcul/haskell/minilang.cabal25
-rw-r--r--lambda-calcul/haskell/src/Minilang/IO.hs32
-rw-r--r--lambda-calcul/haskell/src/Minilang/Lambda/Eval.hs2
-rw-r--r--lambda-calcul/haskell/test/Minilang/IOSpec.hs37
5 files changed, 77 insertions, 25 deletions
diff --git a/lambda-calcul/haskell/app/Main.hs b/lambda-calcul/haskell/app/Main.hs
new file mode 100644
index 0000000..5b48c01
--- /dev/null
+++ b/lambda-calcul/haskell/app/Main.hs
@@ -0,0 +1,6 @@
+import Minilang.IO
+import System.IO (stdin, stdout)
+
+main :: IO ()
+main =
+ runEval stdin stdout
diff --git a/lambda-calcul/haskell/minilang.cabal b/lambda-calcul/haskell/minilang.cabal
index 817672e..7c9c266 100644
--- a/lambda-calcul/haskell/minilang.cabal
+++ b/lambda-calcul/haskell/minilang.cabal
@@ -25,6 +25,7 @@ source-repository head
library
exposed-modules:
+ Minilang.IO
Minilang.Lambda.Unify
Minilang.Lambda.Eval
Minilang.Lambda.Infer
@@ -60,6 +61,7 @@ test-suite minilang-test
type: exitcode-stdio-1.0
main-is: Spec.hs
other-modules:
+ Minilang.IOSpec
Minilang.Lambda.InferSpec
Minilang.Lambda.EvalSpec
hs-source-dirs:
@@ -91,5 +93,28 @@ test-suite minilang-test
, minilang
, mtl
, text
+ , unix
, unordered-containers
default-language: Haskell2010
+
+executable lambda
+ main-is: Main.hs
+ other-modules:
+ Paths_minilang
+ hs-source-dirs:
+ app
+ default-extensions:
+ DeriveGeneric
+ OverloadedStrings
+ FlexibleInstances
+ MultiParamTypeClasses
+ FlexibleContexts
+ RecordWildCards
+ NamedFieldPuns
+ GeneralizedNewtypeDeriving
+ ghc-options: -Wall -fno-warn-orphans -threaded -rtsopts -with-rtsopts=-N
+ build-depends:
+ base
+ , containers
+ , minilang
+ default-language: Haskell2010
diff --git a/lambda-calcul/haskell/src/Minilang/IO.hs b/lambda-calcul/haskell/src/Minilang/IO.hs
index bfcb125..c468316 100644
--- a/lambda-calcul/haskell/src/Minilang/IO.hs
+++ b/lambda-calcul/haskell/src/Minilang/IO.hs
@@ -1,40 +1,24 @@
-{-# LANGUAGE DuplicateRecordFields #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE TypeSynonymInstances #-}
-{-# OPTIONS_GHC "-fno-warn-orphans" #-}
-
module Minilang.IO where
import qualified Data.ByteString as BS
+import qualified Data.Text as Text
import Data.Text.Encoding
( decodeUtf8With,
encodeUtf8,
)
import Data.Text.Encoding.Error (lenientDecode)
-import Minilang.Lambda.Eval hiding (rho)
-import Minilang.Parser
-import Minilang.Type
-import Prettyprinter
-import Prettyprinter.Render.Text
+import Minilang.Lambda.Eval (eval)
import System.IO (Handle)
--- | Read an `AST` from @hin@ handle, evaluate it and dump the result
+-- | Read a "program" from @hin@ handle, evaluate it and dump the result
-- on @hout@.
runEval :: Handle -> Handle -> IO ()
runEval hin hout = do
- programText <- decodeUtf8With lenientDecode <$> BS.hGetContents hin
- let ast = parseProgram False programText
- ρ = EmptyEnv
- γ = EmptyContext
- (ρ', _) <- loadProgram ast ρ γ
- let val = eval ast ρ'
+ programText <- Text.unpack . decodeUtf8With lenientDecode <$> BS.hGetContents hin
+ let ast = read programText
+ env = mempty
+ result = eval ast env
BS.hPut
hout
- ( encodeUtf8
- ( renderStrict $ layoutPretty defaultLayoutOptions $ pretty val
- )
- <> "\n"
- )
+ (encodeUtf8 (Text.pack (show result) <> "\n"))
diff --git a/lambda-calcul/haskell/src/Minilang/Lambda/Eval.hs b/lambda-calcul/haskell/src/Minilang/Lambda/Eval.hs
index 68b01be..0829186 100644
--- a/lambda-calcul/haskell/src/Minilang/Lambda/Eval.hs
+++ b/lambda-calcul/haskell/src/Minilang/Lambda/Eval.hs
@@ -6,7 +6,7 @@ data Term
= Var Text
| Lam Text Term
| App Term Term
- deriving (Show, Eq)
+ deriving (Show, Read, Eq)
type Env = [(Text, Term)]
diff --git a/lambda-calcul/haskell/test/Minilang/IOSpec.hs b/lambda-calcul/haskell/test/Minilang/IOSpec.hs
new file mode 100644
index 0000000..038877d
--- /dev/null
+++ b/lambda-calcul/haskell/test/Minilang/IOSpec.hs
@@ -0,0 +1,37 @@
+module Minilang.IOSpec where
+
+import Control.Exception (bracket)
+import Minilang.IO (runEval)
+import System.Directory (getTemporaryDirectory, removeFile)
+import System.FilePath ((<.>), (</>))
+import System.IO (IOMode (..), hClose, readFile, withFile, writeFile)
+import System.Posix (mkstemp)
+import Test.Hspec (Spec, around, describe, it, parallel, shouldBe)
+import Prelude hiding (lines, readFile, writeFile)
+
+spec :: Spec
+spec = parallel $
+ describe "MiniLang I/O Evaluator" $ do
+ around withTempFile $
+ it "evaluates a simple MiniLang 'program' and dumps result" $ \fileName -> do
+ let outputFileName = fileName <> ".out"
+ program =
+ [ "(App (Lam \"x\" (Var \"x\")) (Var \"y\"))"
+ ]
+
+ writeFile fileName (unlines program)
+
+ _ <- withFile fileName ReadMode $ \hin ->
+ withFile outputFileName AppendMode $ \hout ->
+ runEval hin hout
+
+ out <- readFile outputFileName
+
+ out `shouldBe` "Var \"y\"\n"
+
+withTempFile :: (String -> IO ()) -> IO ()
+withTempFile =
+ bracket mkTempFile rmTempFile
+ where
+ mkTempFile = getTemporaryDirectory >>= \dir -> mkstemp (dir </> "test-repl") >>= \(fp, h) -> hClose h >> pure fp
+ rmTempFile fn = removeFile fn >> removeFile (fn <.> "out")