commit 6167580bc4407dc40fe1e5d81512d44f894b221e Author: Yann Esposito (Yogsototh) Date: Sat Feb 18 17:57:37 2017 +0100 first commit for lish diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f25d1fe --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/tutorial.md +/.stack-work/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..3066175 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,35 @@ +# Use new container infrastructure to enable caching +sudo: false + +# Choose a lightweight base image; we provide our own build tools. +language: c + +# GHC depends on GMP. You can add other dependencies here as well. +addons: + apt: + packages: + - libgmp-dev + +# The different configurations we want to test. You could also do things like +# change flags or use --stack-yaml to point to a different file. +env: +- ARGS="" +#- ARGS="--resolver lts-2" +- ARGS="--resolver lts" +- ARGS="--resolver nightly" + +before_install: +# Download and unpack the stack executable +- mkdir -p ~/.local/bin +- export PATH=$HOME/.local/bin:$PATH +- travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack' + +# This line does all of the work: installs GHC if necessary, builds the +# library, executables, and test suites, and runs the test suites. +# `--no-terminal works` around some quirks in Travis's terminal implementation. +script: stack $ARGS --no-terminal --install-ghc test + +# Caching so the next build will be fast too. +cache: + directories: + - $HOME/.stack diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9bba350 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +Change log +========== + +lish uses [Semantic Versioning][1]. +The change log is available [on GitHub][2]. + +[1]: http://semver.org/spec/v2.0.0.html +[2]: https://github.com/yogsototh/lish/releases + +## v0.1.0.0 + +* Initially created. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..becd8f8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2017, Yann Esposito + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2c7bb10 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +lish +========== + +New Haskell project using stack template `tasty-travis`. + +Please read file `tutorial.md` for first steps in using the template. diff --git a/Setup.hs b/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/lish.cabal b/lish.cabal new file mode 100644 index 0000000..eb463df --- /dev/null +++ b/lish.cabal @@ -0,0 +1,79 @@ +name: lish +version: 0.1.0.0 +-- synopsis: +description: LISP Shell written in Haskell + +license: ISC +license-file: LICENSE +author: Yann Esposito +maintainer: yann.esposito@gmail.com +copyright: © 2017 Yann Esposito +homepage: https://github.com/yogsototh/lish +bug-reports: https://github.com/yogsototh/lish/issues + +category: Test +build-type: Simple +stability: alpha (experimental) +cabal-version: >=1.10 + +extra-source-files: + README.md + stack.yaml + +source-repository head + type: git + location: https://github.com/yogsototh/lish + +library + default-language: Haskell2010 + ghc-options: -Wall -Werror -O2 + hs-source-dirs: src + exposed-modules: Lib + , Lish.Core + build-depends: base >= 4.8 && < 5 + , haskeline + , parsec >= 3 && < 4 + , protolude + , process + +executable lish-exe + default-language: Haskell2010 + ghc-options: -Wall -Werror -O2 -threaded -rtsopts -with-rtsopts=-N + hs-source-dirs: src-exe + main-is: Main.hs + build-depends: base >= 4.8 && < 5 + , lish + +test-suite lish-test + type: exitcode-stdio-1.0 + default-language: Haskell2010 + ghc-options: -Wall -Werror -O2 -threaded -rtsopts -with-rtsopts=-N + hs-source-dirs: src-test + main-is: Main.hs + build-depends: base >= 4.8 && < 5 + , tasty >= 0.11 + , tasty-hunit >= 0.9 + , tasty-smallcheck >= 0.8 + , lish + +test-suite lish-doctest + type: exitcode-stdio-1.0 + default-language: Haskell2010 + ghc-options: -Wall -Werror -O2 -threaded -rtsopts -with-rtsopts=-N + hs-source-dirs: src-doctest + main-is: Main.hs + build-depends: base >= 4.8 && < 5 + , doctest >=0.10 + , Glob >= 0.7 + , QuickCheck >= 2.5 + , lish + +benchmark lish-benchmark + type: exitcode-stdio-1.0 + default-language: Haskell2010 + ghc-options: -Wall -Werror -O2 -threaded -rtsopts -with-rtsopts=-N + hs-source-dirs: src-benchmark + main-is: Main.hs + build-depends: base >= 4.8 && < 5 + , criterion >= 1.1 + , lish diff --git a/src-benchmark/Main.hs b/src-benchmark/Main.hs new file mode 100644 index 0000000..e69835d --- /dev/null +++ b/src-benchmark/Main.hs @@ -0,0 +1,7 @@ +import Criterion +import Criterion.Main + +import Lib (inc) + +main :: IO () +main = defaultMain [bench "inc 41" (whnf inc (41 :: Int))] diff --git a/src-doctest/Main.hs b/src-doctest/Main.hs new file mode 100644 index 0000000..4e85e16 --- /dev/null +++ b/src-doctest/Main.hs @@ -0,0 +1,5 @@ +import System.FilePath.Glob +import Test.DocTest + +main :: IO () +main = glob "src/**/*.hs" >>= doctest diff --git a/src-exe/Main.hs b/src-exe/Main.hs new file mode 100644 index 0000000..63b9ffd --- /dev/null +++ b/src-exe/Main.hs @@ -0,0 +1,4 @@ +import Lish.Core (runLish) + +main :: IO () +main = runLish diff --git a/src-test/Main.hs b/src-test/Main.hs new file mode 100644 index 0000000..aef50a4 --- /dev/null +++ b/src-test/Main.hs @@ -0,0 +1,38 @@ +import Test.Tasty +import Test.Tasty.HUnit +import Test.Tasty.SmallCheck + +import Lib (inc) + +main :: IO () +main = defaultMain $ testGroup "all-tests" tests + +tests :: [TestTree] +tests = + [ testGroup "SmallCheck" scTests + , testGroup "Unit tests" huTests + ] + +scTests :: [TestTree] +scTests = + [ testProperty "inc == succ" prop_succ + , testProperty "inc . negate == negate . pred" prop_pred + ] + +huTests :: [TestTree] +huTests = + [ testCase "Increment below TheAnswer" case_inc_below + , testCase "Decrement above TheAnswer" case_dec_above + ] + +prop_succ :: Int -> Bool +prop_succ n = inc n == succ n + +prop_pred :: Int -> Bool +prop_pred n = inc (negate n) == negate (pred n) + +case_inc_below :: Assertion +case_inc_below = inc 41 @?= (42 :: Int) + +case_dec_above :: Assertion +case_dec_above = negate (inc (negate 43)) @?= (42 :: Int) diff --git a/src/Lib.hs b/src/Lib.hs new file mode 100644 index 0000000..91fdc67 --- /dev/null +++ b/src/Lib.hs @@ -0,0 +1,24 @@ +-- | Example of a library file. It is also used for testing the test suites. +module Lib + ( + -- * Exported functions + inc + ) where + +-- | Increment one 'Num' value. +-- +-- >>> let answer = 42 :: Int +-- >>> let prev = answer - 1 +-- >>> inc prev +-- 42 +-- >>> succ . Prelude.last . Prelude.take prev . iterate inc $ 1 +-- 42 +-- +-- Properties: +-- +-- prop> succ x == inc x +-- prop> inc (negate x) == negate (pred x) +-- +inc :: Num a => a -- ^ value to increment + -> a -- ^ result +inc x = x + 1 diff --git a/src/Lish/Core.hs b/src/Lish/Core.hs new file mode 100644 index 0000000..4843e69 --- /dev/null +++ b/src/Lish/Core.hs @@ -0,0 +1,66 @@ +{-# LANGUAGE OverloadedStrings #-} +-- | Lish core +module Lish.Core + ( + runLish + ) where + +import Control.Monad.IO.Class +import Data.List (intercalate) +import GHC.IO.Handle (hGetContents) +import System.Console.Haskeline +import System.Process +import Text.Parsec + +-- | Start an interactive lish shell +runLish :: IO () +runLish = runInputT defaultSettings mainLoop + +mainLoop :: InputT IO () +mainLoop = do + maybeLine <- getInputLine ":€ > " + case maybeLine of + -- EOF / control-d + Nothing -> outputStrLn "bye bye!" + Just "exit" -> outputStrLn "bye bye!" + Just "logout" -> outputStrLn "bye bye!" + Just line -> do + eval (parseCmd line) + mainLoop + +data Cmd = Cmd String [String] deriving (Eq, Show) + +type Command = [String] -> IO () + +internalCommands :: [(String,Command)] +internalCommands = [("pr",\args -> putStrLn (intercalate " " args))] + +-- PARSE +parseCmd :: String -> Either ParseError Cmd +parseCmd = parse sExprParser "S-Expr" + +identifier :: Parsec String () String +identifier = many1 (noneOf " \t") + +sExprParser :: Parsec String () Cmd +sExprParser = do + (cmdname:args) <- many1 (identifier <* spaces) + return $ Cmd cmdname args + +-- EVAL +internalFunction :: String -> Maybe Command +internalFunction cmdname = lookup cmdname internalCommands + +execute :: String -> [String] -> IO () +execute cmd args = do + res <- createProcess (proc cmd args) { std_out = CreatePipe } + case res of + (_, Just hout, _, _) -> hGetContents hout >>= mapM_ putStrLn . (map ("o-o " ++)) . lines + _ -> putStrLn "no output" + +eval :: Either ParseError Cmd -> InputT IO () +eval parsed = case parsed of + Right (Cmd cmdname args) -> case internalFunction cmdname of + Just f -> liftIO (f args) + Nothing -> liftIO (execute cmdname args) + Left err -> outputStrLn (show err) diff --git a/stack.yaml b/stack.yaml new file mode 100644 index 0000000..8c81be8 --- /dev/null +++ b/stack.yaml @@ -0,0 +1,67 @@ +# This file was automatically generated by 'stack init' +# +# Some commonly used options have been documented as comments in this file. +# For advanced use and comprehensive documentation of the format, please see: +# http://docs.haskellstack.org/en/stable/yaml_configuration/ + +# Resolver to choose a 'specific' stackage snapshot or a compiler version. +# A snapshot resolver dictates the compiler version and the set of packages +# to be used for project dependencies. For example: +# +# resolver: lts-3.5 +# resolver: nightly-2015-09-21 +# resolver: ghc-7.10.2 +# resolver: ghcjs-0.1.0_ghc-7.10.2 +# resolver: +# name: custom-snapshot +# location: "./custom-snapshot.yaml" +resolver: lts-8.0 + +# User packages to be built. +# Various formats can be used as shown in the example below. +# +# packages: +# - some-directory +# - https://example.com/foo/bar/baz-0.0.2.tar.gz +# - location: +# git: https://github.com/commercialhaskell/stack.git +# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a +# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a +# extra-dep: true +# subdirs: +# - auto-update +# - wai +# +# A package marked 'extra-dep: true' will only be built if demanded by a +# non-dependency (i.e. a user package), and its test suites and benchmarks +# will not be run. This is useful for tweaking upstream packages. +packages: +- '.' +# Dependency packages to be pulled from upstream that are not in the resolver +# (e.g., acme-missiles-0.3) +extra-deps: +- haskeline-0.7.3.1 + +# Override default flag values for local packages and extra-deps +flags: {} + +# Extra package databases containing global packages +extra-package-dbs: [] + +# Control whether we use the GHC we find on the path +# system-ghc: true +# +# Require a specific version of stack, using version ranges +# require-stack-version: -any # Default +# require-stack-version: ">=1.3" +# +# Override the architecture used by stack, especially useful on Windows +# arch: i386 +# arch: x86_64 +# +# Extra directories used by stack for building +# extra-include-dirs: [/path/to/dir] +# extra-lib-dirs: [/path/to/dir] +# +# Allow a newer minor version of GHC than the snapshot specifies +# compiler-check: newer-minor