hslua-repl (empty) → 0.1.0
raw patch · 6 files changed
+280/−0 lines, 6 filesdep +basedep +bytestringdep +hslua-core
Dependencies added: base, bytestring, hslua-core, hslua-repl, isocline, lua, text
Files
- CHANGELOG.md +12/−0
- LICENSE +20/−0
- README.md +19/−0
- app/luarepl.hs +28/−0
- hslua-repl.cabal +78/−0
- src/HsLua/REPL.hs +123/−0
+ CHANGELOG.md view
@@ -0,0 +1,12 @@+# Changelog++`hslua-repl` uses [PVP Versioning](https://pvp.haskell.org).++## hslua-repl-0.1.0++Release pending.++- A new package begins its way into the undiscovered land. May+ it live long and prosper.++ [PVP Versioning]: https://pvp.haskell.org
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright © 2023 Albert Krewinkel++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ README.md view
@@ -0,0 +1,19 @@+hslua-repl+==========++An embeddable, isocline-based Lua REPL.++Example+-------++``` haskell+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}+import HsLua.Core as Lua (Exception, openlibs, run)+import HsLua.REPL (defaultREPLConfig, startREPL)++-- | Run a default Lua interpreter.+main :: IO ()+main = run @Lua.Exception $ do+ startREPL defaultREPLConfig+```
+ app/luarepl.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}+{- |+Module : Main+Copyright : © 2022-2023 Albert Krewinkel+License : MIT+Maintainer : Albert Krewinkel <tarleb@hslua.org>++A simple Lua REPL.+-}+module Main (main) where+import Control.Monad (void)+import HsLua.Core as Lua (Exception, openlibs, run)+import HsLua.REPL (Config (..), defaultConfig, repl, setup)+import qualified Data.Text as T++-- | Run a default Lua interpreter.+main :: IO ()+main = run @Lua.Exception $ do+ let config = Config+ { replPrompt = "luarepl"+ , replInfo = replInfo defaultConfig `T.append`+ "\nREPL: © 2023 Albert Krewinkel"+ , replHistory = Just ".luarepl-history"+ }+ openlibs+ setup config+ void repl
+ hslua-repl.cabal view
@@ -0,0 +1,78 @@+cabal-version: 2.2+name: hslua-repl+version: 0.1.0+synopsis: Isocline-based Lua REPL+description: An embeddable Lua REPL built with Isocline and HsLua.+homepage: https://hslua.org/+bug-reports: https://github.com/hslua/hslua/issues+license: MIT+license-file: LICENSE+author: Albert Krewinkel+maintainer: Albert Krewinkel <tarleb@hslua.org>+copyright: © lbert Krewinkel+category: Foreign+build-type: Simple+extra-doc-files: README.md+ CHANGELOG.md+tested-with: GHC == 8.4.4+ , GHC == 8.6.5+ , GHC == 8.8.4+ , GHC == 8.10.7+ , GHC == 9.0.2+ , GHC == 9.2.5+ , GHC == 9.4.4++source-repository head+ type: git+ location: https://github.com/hslua/hslua+ subdir: hslua-repl++Flag executable+ description: Compile `luarepl` standalone executable.+ default: False++common common-options+ build-depends: base >= 4.9.1 && < 5+ , hslua-core >= 2.3 && < 2.4+ , text >= 1.2 && < 2.1++ ghc-options: -Wall+ -Wcpp-undef+ -Widentities+ -Wincomplete-record-updates+ -Wincomplete-uni-patterns+ -Wmissing-export-lists+ -Wmissing-signatures+ -Wnoncanonical-monad-instances+ -Wpartial-fields+ -Wredundant-constraints+ -fhide-source-paths++ if impl(ghc >= 8.10)+ ghc-options: -Wunused-packages++ if impl(ghc >= 9.0)+ ghc-options: -Winvalid-haddock+++ default-language: Haskell2010++library+ import: common-options+ hs-source-dirs: src+ exposed-modules: HsLua.REPL+ build-depends: base >= 4.11 && < 5+ , bytestring >= 0.10 && < 0.12+ , isocline >= 1.0 && < 1.1+ , lua >= 2.3 && < 2.4++executable luarepl+ import: common-options+ hs-source-dirs: app+ main-is: luarepl.hs+ ghc-options: -rtsopts -with-rtsopts=-A8m -threaded+ if flag(executable)+ buildable: True+ build-depends: hslua-repl+ else+ buildable: False
+ src/HsLua/REPL.hs view
@@ -0,0 +1,123 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ScopedTypeVariables #-}+{- |+Module : HsLua.REPL+Copyright : Copyright © 2017-2023 Albert Krewinkel+License : MIT+Maintainer : Albert Krewinkel <tarleb@hslua.org>++Embeddable Lua interpreter interface.+-}+module HsLua.REPL+ ( -- * Run scripts as program+ repl+ , setup+ , Config (..)+ , defaultConfig+ ) where++import Control.Applicative ((<|>))+import Control.Monad (void, when)+import Data.ByteString (ByteString)+import Data.Text (Text)+import Lua (pattern LUA_COPYRIGHT)+import HsLua.Core+import System.Console.Isocline+import qualified Data.ByteString.Char8 as Char8+import qualified Data.Text as T+import qualified Data.Text.IO as T+import qualified HsLua.Core.Utf8 as UTF8++-- | Lua runner command line options.+data Config = Config+ { replPrompt :: Text+ , replInfo :: Text+ , replHistory :: Maybe FilePath+ }++defaultConfig :: Config+defaultConfig = Config+ { replPrompt = ""+ , replInfo = T.pack LUA_COPYRIGHT+ , replHistory = Nothing+ }++-- | Setup a new repl. Prints the version and extra info before the+-- first prompt.+setup :: Config -> LuaE e ()+setup config = do+ liftIO $ T.putStrLn (replInfo config)+ case replHistory config of+ Just histfile -> liftIO $ setHistory histfile 200+ Nothing -> pure ()++-- | Checks if the error message hints at incomplete input. Removes the+-- message from the stack in that case.+incomplete :: LuaError e => LuaE e Bool+incomplete = do+ let eofmark = "<eof>"+ msg <- tostring' top+ if eofmark `Char8.isSuffixOf` msg+ then True <$ pop 2 -- error message (duplicated by tostring')+ else False <$ pop 1 -- value pushed by tostring'++-- | Load an input string, mark it as coming from @stdin@.+loadinput :: ByteString -> LuaE e Status+loadinput inp = loadbuffer inp "=stdin"++-- | Try to load input while prepending a @return@ statement.+loadExpression :: LuaError e => ByteString -> LuaE e ()+loadExpression input = loadinput ("return " <> input) >>= \case+ OK -> pure () -- yep, that worked+ _err -> throwErrorAsException++-- | Load a multiline statement; prompts for more lines if the statement+-- looks incomplete.+loadStatement :: LuaError e+ => [ByteString] -- ^ input lines+ -> LuaE e ()+loadStatement lns = do+ loadinput (Char8.unlines $ reverse lns) >>= \case+ OK -> pure ()+ ErrSyntax -> incomplete >>= \isincmplt ->+ if isincmplt+ then liftIO (readlineMaybe ">") >>= \case+ Nothing -> failLua "Multiline input aborted"+ Just input -> loadStatement (UTF8.fromString input : lns)+ else throwErrorAsException+ _ -> throwErrorAsException++-- | Run a Lua repl.+repl :: LuaError e => LuaE e NumResults+repl = try repl' >>= \case+ Right n -> pure n -- Ctrl-D or Ctrl-C+ Left err -> do+ -- something went wrong: report error, reset stack and try again+ void $ getglobal "print"+ pushException err+ call 1 0+ settop 0+ repl+ where+ repl' :: LuaError e => LuaE e NumResults+ repl' = liftIO (readlineMaybe "") >>= \case+ Nothing ->+ -- Return all values left on the stack as results+ NumResults . fromStackIndex <$> gettop+ Just inputStr -> do+ settop 0 -- reset stack+ let input = UTF8.fromString inputStr+ loadExpression input <|> loadStatement [input]+ -- run loaded input+ callTrace 0 multret+ nvalues <- gettop+ -- duplicate everything and call print on the results+ checkstack' (fromIntegral (fromStackIndex nvalues) + 1) "repl'"+ when (nvalues > 0) $ do+ void $ getglobal "print"+ mapM_ pushvalue [1..nvalues]+ call (fromIntegral $ fromStackIndex nvalues) 0+ repl'