hslua-2.3.0/0000755000000000000000000000000007346545000011021 5ustar0000000000000000hslua-2.3.0/CHANGELOG.md0000644000000000000000000006407707346545000012650 0ustar0000000000000000# Changelog `hslua` uses [PVP Versioning][]. ## hslua-2.3.0 Released 2023-03-13. - Require version 2.3.* of HsLua packages: hslua-core, hslua-marshalling, hslua-objectorientation, hslua-packaging, hslua-aeson, hslua-classes. - Include `hslua-typing`, re-export `HsLua.Typing`. ## hslua-2.2.1 Released 2022-06-19. - Require hslua-core-2.2.1. - Require hslua-marshalling-2.2.0.1. - Relax upper bound for mtl, allow mtl-2.3. ## hslua-2.2.0 Released 2022-02-19. - Require version 2.2.* of all hslua-* packages. - Include hslua-aeson, and re-export `HsLua.Aeson` from `HsLua`. ## hslua-2.1.0 Released 2022-01-29. - Update to hslua-objectorientation 2.1.0. This entails changes to `deftype'` and `deftypeGeneric`, switching the order of item pusher and list-extractor function in the tuple passed as the last argument. - Update to hslua-core 2.1.0, hslua-marshalling 2.1.0, and hslua-classes 2.1.0. ## hslua-2.0.1 Released 2021-11-04. - Updated lower bounds of hslua packages: - hslua \>= 2.0.0.2, - hslua-marshalling \>= 2.0.1, and - hslua-objectorientation \>= 2.0.1. This fixes a number of smaller issues; see the respective package changelogs for details. ## hslua-2.0.0 Released 2021-10-21. - Move module hierarchy from Foreign.Lua to HsLua. - Error handling has been reworked completely. The type of exceptions used and handled by HsLua is now exposed to the type system. The type `Lua` makes use of a default error type. Custom error handling can be implemented by using the `LuaE` type with an exception type that is an instance of class `LuaError`. - Renamed stack index helpers to `nth`, `nthTop`, `nthBottom`, `top`. The following have been *removed*: `stackTop`, `nthFromTop`, `nthFromBottom`. - Extracted raw Lua bindings into new package *lua*. This means that all cabal flags have been moved to package *lua* as well. Version lua-1.0.0 contained the `Foreign.Lua.Raw` hierarchy as present in hslua-1.3.0. See that package’s changelog for info on the additional modifications since then. - The module Foreign.Lua.Raw.Error was merged into the HsLua.Core.Error module. - The functions `getglobal` and `gettable` now return the Lua `Type` of the pushed value. - Extracted new packages: - *hslua-core*: the package contains all modules from the *Core* sub-hierarchy. - *hslua-classes*: typclasses *Peekable* and *Pushable* for pushing and pulling, as well as function calling. - *tasty-hslua*: makes testing helpers available for reuse. - Moved *run* functions from Util to Core.Run. - Moved module Utf8 from the base level into Core. - Refactored code to expose Haskell functions to Lua: - Removed functions `newCFunction`, `freeCFunction`. Use `pushHaskellFunction` instead, it takes care of garbage collection. - Renamed typeclass `ToHaskellFunction` to `Exposable`, function `callFunc` to `invoke`. All these have been moved to *hslua-classes*. - The type PreCFunction is now defined in package lua; HaskellFunction is defined in hslua-core. - Changed `pushHaskellFunction` to only accept HaskellFunction arguments, move it to hslua-core. - Removed helper functions `addfunction` and `addfield` from *Module*. Use documented functions and fields instead. - Added support for a “since” tag on documented functions; allows to mark the library version when a function was introduced in its present form. ## hslua-1.3.0.1 Released 2021-02-06. - Fixed build with GHC 9.0.1 (Simon Jakobi). - Improved test-suite; fixed memory leaks in some tests. - Moved CI to GitHub Actions. ## hslua-1.3.0 Released 2020-10-16. - Upgrade included Lua version to new bug-fix release 5.3.6. See the upstream documentation https://www.lua.org/bugs.html#5.3.5 for the bugs which have been fixed. - Stop exporting `c_loaded_table` and `c_prelad_table` from module Foreign.Lua.Raw.Auxiliary. Both values are defined only if the flag `HARDCODE_REG_KEYS` is disabled, leading to compilation errors when the flag is enabled. - Add new function `peekStringy` to Peek module. It allows to peek a value of any `IsString` type from an UTF-8 encoded string. - Various improvements to the continuous integration setup, including cleanup of the config files, version bumps to the ghc/cabal versions used for testing, and running the linter in a dedicated GitHub Action. ## 1.2.0 Released 2020-08-15 - New module `Foreign.Lua.Call`: the module offers an alternative method of exposing Haskell functions to Lua. The focus is on maintainability: types and marshaling methods are made explicit; the possibility of adding documentation and parameter names improves error messages and allows for automatic documentation extraction. Work on this module is ongoing; the interface is likely to change. Suggestions and feedback are welcome. - New types `Module`, `Field`, and new functions `registerModule`, `preloadModule`, `pushModule`, and `render` exported from `Foreign.Lua.Module`: this builds on the new `Call` module and allows the creation of documented modules as well as automatic generation of Markdown-formatted module documentation. - Export new items `nth` and `top` from Foreign.Lua.Core and Foreign.Lua. They are short-hands for `nthFromTop` and `stackTop`. - Performance improvements: Calling of Lua functions and creation of Haskell data wrapping userdata has been sped up by about 10%. This is mostly due to using of previously missed optimization opportunities. - All foreign imports have been moved to into the new `Foreign.Lua.Raw` module. This module will replace the current `Foreign.Lua.Core` module in the future and will be distributed as a separate package (likely starting with the 2.0 release); the remaining parts of the current `Core` module will be promoted one level in the module hierarchy. The `Raw` module can be used whenever the full power of HsLua is not needed. - Error-signaling of API wrapper functions has been changed: instead of returning special integer values, functions now take an additional pointer argument, which is set to the status result of the computation. The `Failable` type in Core.Error is no longer needed and has been removed. - CI builds now include GHC 8.8 and GHC 8.10, ensuring that all GHC 8.\* versions are supported. ## hslua-1.1.2 Released 2020-06-27 - Revert signature of function `pushList` to it’s proper 1.1 value. This fixes a mistake which caused the 1.1.1 release to be in violation of the PVP versioning policy. - Module Foreign.Lua.Peek: add function `pushKeyValuePairs` (Alex Loomis). ## hslua-1.1.1 Released 2020-06-02 *WARNING*: This version does not conform to the PVP versioning policy, due to a unintended signature change of function `pushList`. It is recommended not to use this version. - New module Foreign.Lua.Push: provides functions which marshal and push Haskell values onto Lua’s stack. Most functions in Foreign.Lua.Types.Pushable are now defined using functions from this module. - New module Foreign.Lua.Peek: provides functions which unmarshal and retrieve Haskell values from Lua’s stack. Contrary to `peek` from Foreign.Lua.Types.Peekable, the peeker functions in this module will never throw errors, but use an `Either` type to signal retrieval failure. The error type `PeekError` should not be considered final and will likely be subject to change in later versions. - Module Foreign.Lua.Utf8: never throw errors when decoding UTF-8 strings. Invalid UTF-8 input bytes no longer cause exceptions, but are replaced with the Unicode replacement character U+FFFD. - Fixed missing and faulty Haddock documentation. - Fixed a bug which caused unnecessary use of strings to represent floating point numbers under certain configurations. ## hslua-1.1.0 Released 2020-03-25. **WARNING:** The changes in this release are experimental. It is recommended to skip this release unless the newly introduced features are required. - Allow custom error handling: conversion of Lua errors to Haskell exceptions and back is made configurable. Users can define their own exception/error handling strategies, even opening up the option to pass arbitrary exceptions through Lua. - New types exported from `Foreign.Lua.Types`: - `ErrorConversion`: defines the ways in which exceptions and errors are handled and converted. - `LuaEnvironment`: environment in which Lua computations are evaluated. Contains the Lua interpreter state and the error conversion strategy. - The environment of the `Lua` type is changed from a plain Lua `State` to the above mentioned `LuaEnvironment`. - New functions `run'` is exported from `Foreign.Lua.Util` and `Foreign.Lua`: it is analogous to `run`, but allows to run computations with a custom error conversion strategy. - New function `runWithConverter` exported from `Foreign.Lua.Core.Types` and `Foreign.Lua.Core`; like `run'`, but takes a custom state. - New function `unsafeRunWith` exported from `Foreign.Lua.Core.Types` and `Foreign.Lua.Core`; runs a computation without proper error handling. - New function `errorConversion` exported from `Foreign.Lua.Core.Types` and `Foreign.Lua.Core`: extract the error conversion strategy from the Lua type. - New function `throwErrorAsException` exported from `Foreign.Lua.Core.Error` and `Foreign.Lua.Core`: throws a Lua error as Haskell exception, using the current error conversion strategy. - Function `runWith` is moved from module `Foreign.Lua.Core` to `Foreign.Lua.Util`. - The module `Foreign.Lua.Utf8` is now exported. ## hslua-1.0.3.2 Released 2019-08-21. - Added flag to use hardcoded values for registry keys: The names of the registry keys used to store package information are available as CPP values from file lauxlib.h since Lua 5.3.4; compiling HsLua against older Lua versions was not possible, as those values were expected to exist. The respective values are now hardcoded into HsLua, and a new flag `hardcode-reg-key` is introduced, which will cause the use of these hardcoded values instead of those defined in lauxlib.h. Using this flag makes it possible to compile hslua against all Lua 5.3.\* versions. - Added missing C files for benchmarking to list of *extra-source-files*. ## hslua-1.0.3.1 Released 2019-05-08. - Prevent filenames being treated as strings in debug messages. Lua’s `loadbuffer` takes a `source` description as an argument, which is used for debug messages. The `loadfile` function now adds a special prefix (`@`) to `source`, thus marking it as a filename. ## hslua-1.0.3 Released 2019-05-04. - New module `Foreign.Lua.Module`, containing helper functions to define and load modules from Haskell. - Improve documentation of `open` (many thanks to Christian Charukiewicz.) ## hslua-1.0.2 Released 2019-01-05. - Fixed cross-compilation: placement of C import declarations were fixed, thereby resolving issues with cross-compilation. (Vanessa McHale and Faraz Maleknia) - Added .gitattributes file, fixing the wrong language classification of the GitHub repository. (Vanessa McHale) - Improved `toHaskellFunction` documentation. The documentation is now more specific on which Haskell exceptions are caught and which will lead to crashes. ## hslua-1.0.1 - Exposed more functions from Lua’s `lauxlib` library: - `getmetafield`, - `getmetatable'`, - `getsubtable`, and - `traceback`. The function `getsubtable` is a reimplementation instead of a wrapper to the C function for simplicity (thereby avoiding additional C wrappers). - Fixed tests for GHC 8.6 by no longer depending on failable pattern matching. ## hslua-1.0.0 ### New features - Error handling at language borders has been vastly improved and is now mostly automatic. Haskell’s `Foreign.Lua.Exception`s are transformed into Lua errors and *vice versa*. Lua-side wrappers are no longer necessary. - Haskell functions are no longer pushed as userdata by `pushHaskellFunction`, but as C functions. This simplifies tasks where Lua expects true function objects object (for example when looking for module loaders). - Added stack instance for - Data.Set.Set, - Integer, - Int, - Float, and - Double. Instances for numbers fall back to strings when the representation as a Lua number would cause a loss of precision. - Haskell functions pushed with `pushHaskellFunction` can now be garbage collected by Lua without having to call back into Haskell. The callback into Haskell by the GC had previously caused programs to hang in some situations. - Bindings to more Lua C API functions and macros: `isinteger`, `load`, `loadbuffer`, and `pushglobaltable`. - Any Haskell value can be pushed to the Lua stack as userdata via `pushAny` and retrieved via `peekAny`. Additional functions are provided to setup the userdata metatable. - The C preprocessor constants `LUA_LOADED_TABLE` and `LUA_PRELOAD_TABLE` are made available as `loadedTableRegistryField` and `preloadTableRegistryField`, respectively. - Additional small helper functions: - `peekRead` – read value from a string. - `popValue` – peek value at the top of the Lua stack, then remove it from the stack regardless of whether peeking was successful or not. ### Naming - The *Lua* prefix was removed from types (`State`, `Integer`, `Number`, `Exception`) and the respective infix from functions (`try`, `run`, `runWith`, `runEither`). HsLua should be imported qualified to avoid name collisions. - Terminology now consistently uses *exception* to refer to Haskell exceptions, and *error* for Lua errors; function names changed accordingly (`throwException`, `catchException`, `withExceptionMessage`). - Module *Foreign.Lua.Api* was renamed to *Foreign.Lua.Core*. - *Foreign.Lua.lerror* was renamed to *Foreign.Lua.error*. - Typeclass *ToLuaStack* was renamed to *Pushable*. - Typeclass *FromLuaStack* was renamed to *Peekable*. - Cabal flag *use-pkgconfig* was renamed to *pkg-config* (which is the flag name used by other projects such a zlib). ### Type signatures - The return value of `lua_newuserdata` is *CSize* (was *CInt*). - Table index parameter in `rawgeti` and `rawseti` must be of type *LuaInteger*, but were of type *Int*. - The number of upvalues passed to `pushcclosure` must be of type *NumArgs*. - `Lua.error` has type *Lua NumResults*, simplifying its use in HaskellFunctions. - Retrieval functions which can fail, i.e. `tocfunction`, `tointeger`, `tonumber`, `tostring`, `tothread`, and `touserdata`, use the *Maybe* type to indicate success or failure, avoiding the need to perform additional checks. ### Removed Features - Support for Lua versions before 5.3 has been dropped. - Support for GHC 7.8 has been dropped. - `wrapHaskellFunction` has been made internal and is no longer exported. ### Changed behavior - Peekable instances for numbers and strings became more forgiving. Peeking of basic types now follows Lua’s default conversion rules: - numbers can be given as strings, and *vice versa*; - any value can be converted into a boolean – only `nil` and `false` are peeked as `False`, all other as `True`. ### Other - Many internal improvements and additions such as a benchmarking suite, code cleanups, better tests, etc. ## hslua-0.9.5.2 - Relaxed upper bound on *exceptions*. Again. ## hslua-0.9.5.1 - Relaxed upper bound on *exceptions*. ## hslua-0.9.5 - Provide Optional as a replacement for OrNil. Exports of the latter have been fixed. - Provide utility function `raiseError`: Its argument will be thrown as an error in Lua. - Add `modifyLuaError`: The function lives in Foreign.Lua.Error and allows to alter error messages. This is most useful for amending errors with additional information. - Fixed a bug in `toList` which left a element on the stack if deserializing that element lead to an error. This also affected the FromLuaStack instance for lists. - Fixed a bug in `pairsFromTable` which left a key-value pair on the stack if either of them could not be read into the expected type. This also affected the FromLuaStack instance for Map. ## hslua-0.9.4 - Make Lua an instance of MonadMask: MonadMask from Control.Monad.Catch allows to mask asynchronous exceptions. This allows to define a finalizer for Lua operations. - Add functions and constants to refer to stack indices: The functions `nthFromBottom`, `nthFromTop` as well as the constants `stackTop` and `stackBottom` have been introduced. Numeric constants are less clear, and named constants can aid readability. - Add type OrNil: This type can be used when dealing with optional arguments to Lua functions. - Add function absindex: it converts the acceptable index `idx` into an equivalent absolute index (that is, one that does not depend on the stack top). The function calls `lua_absindex` when compiled with Lua 5.2 or later; for Lua 5.1, it is reimplemented in Haskell. - Functions in `tasty` which have been deprecated have been replaced with non-deprecated alternatives. ## hslua-0.9.3 - Re-export more FunctionCalling helpers in `Foreign.Lua`: The typeclass `ToHaskellFunction` and the helper function `toHaskellFunction` are useful when working with functions. Importing them separately from `Foreign.Lua.FunctionCalling` was an unnecessary burden; they are therefor now re-exported by the main module. - Export registry-relatd constants `refnil` and `noref`: The constants are related to Lua’s registry functions (`ref` and `unref`). - Add helper to convert functions into CFunction: A new helper `wrapHaskellFunction` is provided. It expects a HaskellImportedFunction userdata (as produced by `pushHaskellFunction`) on top of the stack and replaces it with a C function. The new function converts error values generated with `lerror` into Lua errors, i.e. it calls `lua_error`. - Add utility function `setglobal'`: It works like `setglobal`, but works with packages and nested tables (dot-notation only). ## hslua-0.9.2 - Add cabal flag ‘export-dynamic’: Default behavior is to include all symbols in the dynamic symbol table, as this enables users to load dynamic lua libraries. However, it is sometimes desirable to disable, e.g., when compiling a fully static binary. See jgm/pandoc#3986. ## hslua-0.9.1 - Increase user-friendlyness of error messages: The error message returned by `toHaskellFunction` hinted at the fact that the failing function is a Haskell function. This is mostly unnecessary information and might have confused users. ## hslua-0.9.0 - Added cabal flag to allow fully safe garbage collection: Lua garbage collection can occur in most of the API functions, even in those usually not calling back into haskell and hence marked as optimizable. The effect of this is that finalizers which call Haskell functions will cause the program to hang. A new flag `allow-unsafe-gc` is introduced and enabled by default. Disabling this flag will mark more C API functions as potentially calling back into Haskell. This has a serious performance impact. - `FromLuaStack` and `ToLuaStack` instances for lazy ByteStrings are added. - None-string error messages are handled properly: Lua allows error messages to be of any type, but the haskell error handlers expected string values. Tables, booleans, and other non-string values are now handled as well and converted to strings. ## hslua-0.8.0 - Use newtype definitions instead of type aliases for LuaNumber and LuaInteger. This makes it easier to ensure the correct numeric instances in situations where Lua might have been compiled with 32-bit numbers. - Instances of `FromLuaStack` and `ToLuaStack` for `Int` are removed. The correctness of these instances cannot be guaranteed if Lua was compiled with a non-standard integer type. ## hslua-0.7.1 - The flag `lua_32bits` was added to allow users to compile Lua for 32-bit systems. - When reading a list, throw an error if the lua value isn’t a table instead of silently returning an empty list. ## hslua-0.7.0 - Tuples from pairs to octuples have been made instances of `FromLuaStack` and `ToLuaStack`. - New functions `dostring` and `dofile` are provided to load and run strings and files in a single step. - `LuaStatus` was renamed to `Status`, the *Lua* prefix was removed from its type constructors. - The constructor `ErrFile` was added to `Status`. It is returned by `loadfile` if the file cannot be read. - Remove unused FFI bindings and unused types, including all functions unsafe to use from within Haskell and the library functions added with 0.5.0. Users with special requirements should define their own wrappers and raw bindings. - The module *Foreign.Lua.Api.SafeBindings* was merge into *Foreign.Lua.Api.RawBindings*. - FFI bindings are changed to use newtypes where sensible, most notably `StackIndex`, `NumArgs`, and `NumResults`, but also the newly introduced newtypes `StatusCode`, `TypeCode`, and `LuaBool`. - Add functions `tointegerx` and `tonumberx` which can be used to get and check values from the stack in a single step. - The signature of `concat` was changed from `Int -> Lua ()` to `NumArgs -> Lua ()`. - The signature of `loadfile` was changed from `String -> Lua Int` to `String -> Lua Status`. - The type `LTYPE` was renamed to `Type`, its constructors were renamed to follow the pattern `Type`. `LuaRelation` was renamed to `RelationalOperator`, the *Lua* prefix was removed from its constructors. - Add function `tolist` to allow getting a generic list from the stack without having to worry about the overlapping instance with `[Char]`. ## hslua-0.6.0 - Supported Lua Versions now include Lua 5.2 and Lua 5.3. LuaJIT and Lua 5.1 remain supported as well. - Flag `use-pkgconfig` was added to allow discovery of library and include paths via pkg-config. Setting a specific Lua version flag now implies `system-lua`. (Sean Proctor) - The module was renamed from `Scripting.Lua` to `Foreign.Lua`. The code is now split over multiple sub-modules. Files processed with hsc2hs are restricted to Foreign.Lua.Api. - A `Lua` monad (reader monad over LuaState) is introduced. Functions which took a LuaState as their first argument are changed into monadic functions within that monad. - Error handling has been redesigned completely. A new LuaException was introduced and is thrown in unexpected situations. Errors in lua which are leading to a `longjmp` are now caught with the help of additional C wrapper functions. Those no longer lead to uncontrolled program termination but are converted into a LuaException. - `peek` no longer returns `Maybe a` but just `a`. A LuaException is thrown if an error occurs (i.e. in situtations where Nothing would have been returned previously). - The `StackValue` typeclass has been split into `FromLuaStack` and `ToLuaStack`. Instances not satisfying the law `x == push x *> peek (-1)` have been dropped. - Documentation of API functions was improved. Most docstrings have been copied from the official Lua manual, enriched with proper markup and links, and changed to properly describe hslua specifics when necessary. - Example programs have been moved to a separate repository. - Unused files were removed. (Sean Proctor) ## hslua-0.5.0 - New raw functions for `luaopen_base`, `luaopen_package`, `luaopen_string`, `luaopen_table`, `luaopen_math`, `luaopen_io`, `luaopen_os`, `luaopen_debug` and their high-level wrappers (with names `openbase`, `opentable` etc.) implemented. - Remove custom versions of `loadfile` and `loadstring`. - Drop support for GHC versions \< 7.8, avoid compiler warnings. - Ensure no symbols are stripped when linking the bundled lua interpreter. - Simplify `tostring` function definition. (Sean Proctor) - Explicitly deprecate `strlen`. (Sean Proctor) - Add links to lua documentation for functions wrapping the official lua C API. (Sean Proctor). ## hslua-0.4.1 - Bugfix(#30): `tolist` wasn’t popping elements of the list from stack. ## hslua-0.4.0 - `pushstring` and `tostring` now uses `ByteString` instead of `[Char]`. - `StackValue [Char]` instance is removed, `StackValue ByteString` is added. - `StackValue a => StackValue [a]` instance is added. It pushes a Lua array to the stack. `pushlist`, `islist` and `tolist` functions are added. - Type errors in Haskell functions now propagated differently. See the `Scripting.Lua` documentation for detailed explanation. This should fix segfaults reported several times. - `lua_error` function is removed, it’s never safe to call in Haskell. Related issues and pull requests: #12, #26, #24, #23, #18. ## hslua-0.3.14 - Pkgconf-based setup removed. Cabal is now using `extra-libraries` to link with Lua. - `luajit` flag is added to link hslua with LuaJIT. ## hslua-0.3.13 - Small bugfix related with GHCi running under Windows. ## hslua-0.3.12 - `pushrawhsfunction` and `registerrawhsfunction` functions are added. - `apicheck` flag is added to Cabal package to enable Lua API checking. (useful for debugging) ## hslua-0.3.11 - `luaL_ref` and `luaL_unref` functions are added. [PVP Versioning]: https://pvp.haskell.org hslua-2.3.0/LICENSE0000644000000000000000000000224107346545000012025 0ustar0000000000000000Copyright © 1994-2022 Lua.org, PUC-Rio. Copyright © 2007-2012 Gracjan Polak Copyright © 2012-2015 Ömer Sinan Ağacan Copyright © 2016-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. hslua-2.3.0/README.md0000644000000000000000000001115607346545000012304 0ustar0000000000000000# HsLua – Bindings to Lua, an embeddable scripting language [![Build status][GitHub Actions badge]][GitHub Actions] [![AppVeyor Status]](https://ci.appveyor.com/project/tarleb/hslua-r2y18) [![Hackage]](https://hackage.haskell.org/package/hslua) HsLua provides bindings, wrappers, types, and helper functions to bridge Haskell and Lua. [GitHub Actions badge]: https://img.shields.io/github/workflow/status/hslua/hslua/CI.svg?logo=github [GitHub Actions]: https://github.com/hslua/hslua/actions [AppVeyor Status]: https://ci.appveyor.com/api/projects/status/ldutrilgxhpcau94/branch/main?svg=true [Hackage]: https://img.shields.io/hackage/v/hslua.svg This package is part of [HsLua], a Haskell framework built around the embeddable scripting language [Lua]. [HsLua]: https://hslua.org/ [Lua]: https://lua.org/ Overview -------- [Lua](https://lua.org) is a small, well-designed, embeddable scripting language. It has become the de-facto default to make programs extensible and is widely used everywhere from servers over games and desktop applications up to security software and embedded devices. This package provides Haskell bindings to Lua, enable coders to embed the language into their programs, making them scriptable. HsLua ships with batteries included and includes Lua 5.4.4. Cabal flags make it easy to compile against a system-wide Lua installation. Interacting with Lua -------------------- HsLua provides the `Lua` type to define Lua operations. The operations are executed by calling `run`. A simple "Hello, World" program, using the Lua `print` function, is given below: ``` haskell import Foreign.Lua as Lua main :: IO () main = Lua.run prog where prog :: Lua () prog = do Lua.openlibs -- load Lua libraries so we can use 'print' Lua.callFunc "print" "Hello, World!" ``` ### The Lua stack Lua's API is stack-centered: most operations involve pushing values to the stack or receiving items from the stack. E.g., calling a function is performed by pushing the function onto the stack, followed by the function arguments in the order they should be passed to the function. The API function `call` then invokes the function with given numbers of arguments, pops the function and parameters off the stack, and pushes the results. ,----------. | arg 3 | +----------+ | arg 2 | +----------+ | arg 1 | +----------+ ,----------. | function | call 3 1 | result 1 | +----------+ ===========> +----------+ | | | | | stack | | stack | | | | | Manually pushing and pulling arguments can become tiresome, so HsLua makes function calling simple by providing `callFunc`. It uses type-magic to allow different numbers of arguments. Think about it as having the signature callFunc :: String -> a1 -> a2 -> … -> res where the arguments `a1, a2, …` must be of a type which can be pushed to the Lua stack, and the result-type `res` must be constructable from a value on the Lua stack. ### Getting values from and to the Lua stack Conversion between Haskell and Lua values is governed by two type classes: ``` haskell -- | A value that can be read from the Lua stack. class Peekable a where -- | Check if at index @n@ there is a convertible Lua value and -- if so return it. Throws a @'LuaException'@ otherwise. peek :: StackIndex -> Lua a ``` and ``` haskell -- | A value that can be pushed to the Lua stack. class Pushable a where -- | Pushes a value onto Lua stack, casting it into meaningfully -- nearest Lua type. push :: a -> Lua () ``` Many basic data types (except for numeric types, see the FAQ) have instances for these type classes. New instances can be defined for custom types using the functions in `Foreign.Lua.Core` (also exported in `Foreign.Lua`). Q&A --- - **Can I see some examples?** Basic examples are available in the [*hslua-examples*](https://github.com/hslua/hslua-examples) repository. A big project build with hslua is [Pandoc](https://pandoc.org), the universal document converter. It is written in Haskell and includes a Lua interpreter, enabling programmatic modifications of documents via Lua. Furthermore, custom output formats can be defined via Lua scripts. - **Where are the coroutine related functions?** Yielding from a coroutine works via `longjmp`, which plays very badly with Haskell's RTS. Tests to get coroutines working with HsLua were unsuccessful. No coroutine related functions are exported from the default module for that reason. Pull requests intended to fix this are very welcome. hslua-2.3.0/hslua.cabal0000644000000000000000000001131107346545000013116 0ustar0000000000000000cabal-version: 2.2 name: hslua version: 2.3.0 synopsis: Bindings to Lua, an embeddable scripting language description: HsLua provides wrappers and helpers to bridge Haskell and . . It builds upon the /lua/ package, which allows to bundle a Lua interpreter with a Haskell program. . Example programs are can be found in the @hslua-examples@ subdir of the project . homepage: https://hslua.org/ bug-reports: https://github.com/hslua/hslua/issues license: MIT license-file: LICENSE author: Albert Krewinkel, Gracjan Polak, Ömer Sinan Ağacan maintainer: tarleb@hslua.org copyright: © 2007–2012 Gracjan Polak; © 2012–2016 Ömer Sinan Ağacan; © 2017-2023 Albert Krewinkel category: Foreign build-type: Simple extra-source-files: README.md , CHANGELOG.md , test/lua/*.lua 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.git common common-options default-language: Haskell2010 build-depends: base >= 4.11 && < 5 , bytestring >= 0.10.2 && < 0.12 , containers >= 0.5.9 && < 0.7 , exceptions >= 0.8 && < 0.11 , hslua-aeson >= 2.3 && < 2.4 , hslua-core >= 2.3 && < 2.4 , hslua-classes >= 2.2 && < 2.4 , hslua-marshalling >= 2.3 && < 2.4 , hslua-objectorientation >= 2.3 && < 2.4 , hslua-packaging >= 2.3 && < 2.4 , hslua-typing >= 0.1 && < 0.2 , mtl >= 2.2 && < 2.4 , text >= 1.2 && < 2.1 ghc-options: -Wall -Wincomplete-record-updates -Wnoncanonical-monad-instances -Wredundant-constraints if impl(ghc >= 8.2) ghc-options: -Wcpp-undef -Werror=missing-home-modules if impl(ghc >= 8.4) ghc-options: -Widentities -Wincomplete-uni-patterns -Wpartial-fields -fhide-source-paths library import: common-options exposed-modules: HsLua , HsLua.Util reexported-modules: HsLua.Aeson , HsLua.Core , HsLua.Core.Error , HsLua.Core.Types , HsLua.Core.Utf8 , HsLua.Class.Exposable , HsLua.Class.Invokable , HsLua.Class.Peekable , HsLua.Class.Pushable , HsLua.Class.Util , HsLua.Marshalling , HsLua.ObjectOrientation , HsLua.Packaging , HsLua.Packaging.Function , HsLua.Packaging.Module , HsLua.Packaging.Rendering , HsLua.Typing hs-source-dirs: src test-suite test-hslua import: common-options type: exitcode-stdio-1.0 main-is: test-hslua.hs hs-source-dirs: test ghc-options: -threaded -Wno-unused-do-bind other-modules: HsLuaTests , HsLua.UtilTests build-depends: hslua -- The lua package is needed only to check for it's -- version so we know whether to expect behavior of -- Lua 5.3 or Lua 5.4. , lua >= 2.0 , lua-arbitrary >= 1.0 , QuickCheck >= 2.7 , quickcheck-instances >= 0.3 , tasty-hslua , tasty >= 0.11 , tasty-hunit >= 0.9 other-extensions: LambdaCase , OverloadedStrings , TypeApplications hslua-2.3.0/src/0000755000000000000000000000000007346545000011610 5ustar0000000000000000hslua-2.3.0/src/HsLua.hs0000644000000000000000000000263607346545000013167 0ustar0000000000000000{-| Module : HsLua Copyright : © 2007–2012 Gracjan Polak; © 2012–2016 Ömer Sinan Ağacan; © 2017-2023 Albert Krewinkel License : MIT Maintainer : Albert Krewinkel Stability : beta Portability : non-portable (depends on GHC) Functions and utilities enabling the seamless integration of a Lua interpreter into a Haskell project. This module combines and re-exports the functionality of the HsLua framework. Basic access to the Lua API is provided by @'Lua.Core'@ from Hackage package /lua/. -} module HsLua ( -- * Core functionality module HsLua.Core -- * Marshalling , module HsLua.Marshalling -- * Module, data, and function packaging , module HsLua.ObjectOrientation , module HsLua.Packaging -- * Type classes , module HsLua.Class.Exposable , module HsLua.Class.Invokable , module HsLua.Class.Peekable , module HsLua.Class.Pushable -- * Marshal to and from JSON-like structures , module HsLua.Aeson -- * Utility functions , getglobal' , setglobal' , module HsLua.Class.Util ) where import Prelude hiding (compare, concat) import HsLua.Aeson import HsLua.Core import HsLua.Class.Exposable import HsLua.Class.Invokable import HsLua.Class.Peekable import HsLua.Class.Pushable hiding (pushList) import HsLua.Class.Util import HsLua.Packaging import HsLua.Marshalling import HsLua.ObjectOrientation import HsLua.Util hslua-2.3.0/src/HsLua/0000755000000000000000000000000007346545000012624 5ustar0000000000000000hslua-2.3.0/src/HsLua/Util.hs0000644000000000000000000000357207346545000014104 0ustar0000000000000000{-| Module : HsLua.Util Copyright : © 2007–2012 Gracjan Polak; © 2012–2016 Ömer Sinan Ağacan; © 2017-2023 Albert Krewinkel License : MIT Maintainer : Albert Krewinkel Stability : beta Portability : non-portable (depends on GHC) HsLua utility functions. -} module HsLua.Util ( getglobal' , setglobal' ) where import Data.List (groupBy) import Data.String (IsString (fromString)) import HsLua.Core ( LuaE, LuaError (..), Name (..), getfield, getglobal, nth, pop , pushvalue, remove, setfield, setglobal, top ) import qualified HsLua.Core.Utf8 as Utf8 -- | Like @getglobal@, but knows about packages and nested tables. E.g. -- -- > getglobal' "math.sin" -- -- will return the function @sin@ in package @math@. getglobal' :: LuaError e => Name -> LuaE e () getglobal' = getnested . splitdot -- | Like @setglobal@, but knows about packages and nested tables. E.g. -- -- > pushstring "0.9.4" -- > setglobal' "mypackage.version" -- -- All tables and fields, except for the last field, must exist. setglobal' :: LuaError e => Name -> LuaE e () setglobal' s = case reverse (splitdot s) of [] -> return () [_] -> setglobal s (lastField : xs) -> do getnested (reverse xs) pushvalue (nth 2) setfield (nth 2) lastField pop 1 -- | Gives the list of the longest substrings not containing dots. splitdot :: Name -> [Name] splitdot = map fromString . filter (/= ".") . groupBy (\a b -> a /= '.' && b /= '.') . Utf8.toString . fromName -- | Pushes the value described by the strings to the stack; where the first -- value is the name of a global variable and the following strings are the -- field values in nested tables. getnested :: LuaError e => [Name] -> LuaE e () getnested [] = return () getnested (x:xs) = do _ <- getglobal x mapM_ (\a -> getfield top a *> remove (nth 2)) xs hslua-2.3.0/test/HsLua/0000755000000000000000000000000007346545000013014 5ustar0000000000000000hslua-2.3.0/test/HsLua/UtilTests.hs0000644000000000000000000000344507346545000015316 0ustar0000000000000000{-# LANGUAGE OverloadedStrings #-} {-| Module : HsLua.UtilTests Copyright : © 2017-2023 Albert Krewinkel License : MIT Maintainer : Albert Krewinkel Stability : stable Portability : portable Tests for utility types and functions -} module HsLua.UtilTests (tests) where import HsLua import Test.Tasty.HsLua ((=:), shouldBeResultOf) import Test.Tasty (TestTree, testGroup) -- | Specifications for Attributes parsing functions. tests :: TestTree tests = testGroup "Util" [ testGroup "getglobbal'" [ "returns nil if global does not exist" =: TypeNil `shouldBeResultOf` do getglobal' "nope" ltype top , "returns global" =: TypeTable `shouldBeResultOf` do openlibs getglobal' "math" ltype top , "can access nested fields" =: TypeFunction `shouldBeResultOf` do openlibs getglobal' "math.log" ltype top , "can access 3rd level fields" =: TypeTable `shouldBeResultOf` do openlibs getglobal' "package.loaded.math" ltype top ] , testGroup "setglobbal'" [ "sets a global" =: Just "new value" `shouldBeResultOf` do pushstring "new value" setglobal' "new" getglobal "new" tostring top , "can change nested values" =: Just "euler" `shouldBeResultOf` do openlibs pushstring "euler" setglobal' "math.test" getglobal "math" getfield top "test" tostring top , "can modify 3rd level fields" =: Just 42 `shouldBeResultOf` do openlibs pushinteger 42 setglobal' "package.loaded.math.foo" getglobal "package" getfield top "loaded" getfield top "math" getfield top "foo" tointeger top ] ] hslua-2.3.0/test/0000755000000000000000000000000007346545000012000 5ustar0000000000000000hslua-2.3.0/test/HsLuaTests.hs0000644000000000000000000001530107346545000014373 0ustar0000000000000000{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-} {-| Module : HsLua.Packaging.Module Copyright : © 2019-2023 Albert Krewinkel License : MIT Maintainer : Albert Krewinkel Stability : alpha Portability : Requires GHC 8 or later. Tests for HsLua. -} module HsLuaTests (tests) where import Prelude hiding (concat) import Control.Monad (void) import Data.ByteString (append) import Data.Data (Typeable) import Data.Either (isLeft) import HsLua as Lua import System.Mem (performMajorGC) import Test.Tasty.HsLua ( (=:), (?:), pushLuaExpr, shouldBeErrorMessageOf , shouldHoldForResultOf) import Test.Tasty (TestTree, testGroup) import Test.Tasty.HUnit ((@?=), assertBool, assertEqual, testCase) import qualified Control.Monad.Catch as Catch import qualified Data.ByteString.Char8 as Char8 import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified HsLua.Core.Utf8 as Utf8 -- | Specifications for Attributes parsing functions. tests :: TestTree tests = testGroup "Lua integration tests" [ testCase "print version" . run $ do openlibs void $ getglobal @Lua.Exception "assert" pushstring "Hello from " void $ getglobal @Lua.Exception "_VERSION" concat 2 call 1 0 , "getting a nested global works" ?: do pushLuaExpr @Lua.Exception "{greeting = 'Moin'}" setglobal "hamburg" getglobal' "hamburg.greeting" pushLuaExpr "'Moin'" equal (-1) (-2) , "setting a nested global works" ?: do let v = "Mitte" newtable setglobal @Lua.Exception "berlin" pushstring v setglobal' "berlin.neighborhood" v' <- getglobal' "berlin.neighborhood" *> tostring (-1) return (Just v == v') , testCase "table reading" . run @Lua.Exception $ do openbase let tableStr = "{firstname = 'Jane', surname = 'Doe'}" pushLuaExpr $ "setmetatable(" `append` tableStr `append` ", {'yup'})" void $ getfield top "firstname" firstname <- tostring top <* pop 1 liftIO (assertEqual "Wrong value for firstname" (Just "Jane") firstname) pushstring "surname" rawget (-2) surname <- tostring top <* pop 1 liftIO (assertEqual "Wrong value for surname" surname (Just "Doe")) hasMetaTable <- getmetatable (-1) liftIO (assertBool "getmetatable returned wrong result" hasMetaTable) rawgeti (-1) 1 mt1 <- tostring top <* pop 1 liftIO (assertEqual "Metatable content not as expected " mt1 (Just "yup")) , testGroup "Getting strings to and from the stack" [ testCase "unicode ByteString" $ do let val = T.pack "öçşiğüİĞı" val' <- run $ do pushstring (T.encodeUtf8 val) fmap T.decodeUtf8 `fmap` tostring 1 assertEqual "Popped a different value or pop failed" (Just val) val' , testCase "ByteString should survive after GC/Lua destroyed" $ do (val, val') <- run $ do let v = "ByteString should survive" pushstring v v' <- tostring 1 pop 1 return (Just v, v') performMajorGC assertEqual "Popped a different value or pop failed" val val' , testCase "String with NUL byte should be pushed/popped correctly" $ do let str = "A\NULB" str' <- run $ pushstring (Char8.pack str) *> tostring 1 assertEqual "Popped string is different than what's pushed" (Just str) (Char8.unpack <$> str') ] , testGroup "luaopen_* functions" $ map (uncurry testOpen) [ ("base", openbase) , ("debug", opendebug) , ("io", openio) , ("math", openmath) , ("os", openos) , ("package", openpackage) , ("string", openstring) , ("table", opentable) ] , testGroup "error handling" [ "catching error of a failing meta method" =: isLeft `shouldHoldForResultOf` let comp = do pushLuaExpr "setmetatable({}, {__index = error})" void $ getfield (-1) "foo" in try comp , "calling a function that errors throws exception" =: "[string \"return error('error message')\"]:1: error message" `shouldBeErrorMessageOf` do openbase loadstring "return error('error message')" *> call 0 1 , let errTbl ="setmetatable({}, {__index = function(t, k) error(k) end})" in testGroup "error conversion" [ "throw custom exceptions" =: do let comp = do openlibs pushLuaExpr errTbl pushnumber 23 void $ gettable (Lua.nth 2) result <- tryCustom comp result @?= Left (ExceptionWithNumber 23) , "catch custom exception in exposed function" =: do let frob = do openlibs pushLuaExpr errTbl pushnumber 42 _ <- gettable (Lua.nth 2) return (NumResults 1) result <- tryCustom $ do openlibs pushHaskellFunction frob call (NumArgs 0) (NumResults 1) result @?= Left (ExceptionWithNumber 42) , "pass exception through Lua" =: do let frob :: LuaE CustomException NumResults frob = Catch.throwM (ExceptionWithMessage "borked") result <- tryCustom $ do pushHaskellFunction frob call (NumArgs 0) (NumResults 0) result @?= Left (ExceptionWithMessage "borked") ] ] ] ------------------------------------------------------------------------------- -- luaopen_* functions testOpen :: String -> Lua () -> TestTree testOpen lib openfn = testCase ("open" ++ lib) $ assertBool "opening the library failed" =<< run (openfn *> istable (-1)) ------------------------------------------------------------------------------- -- Custom exception handling data CustomException = ExceptionWithNumber Lua.Number | ExceptionWithMessage String deriving (Eq, Show, Typeable) instance Catch.Exception CustomException instance LuaError CustomException where pushException = \case ExceptionWithMessage m -> pushstring (Utf8.fromString m) ExceptionWithNumber n -> pushnumber n popException = do Lua.tonumber Lua.top >>= \case Just num -> do Lua.pop 1 return (ExceptionWithNumber num) _ -> do l <- Lua.state msg <- Lua.liftIO (Lua.popErrorMessage l) return (ExceptionWithMessage (Utf8.toString msg)) luaException = ExceptionWithMessage tryCustom :: LuaE CustomException a -> IO (Either CustomException a) tryCustom = Catch.try . Lua.run -- instance Lua -- customAlternative :: Lua a -> Lua a -> Lua a -- customAlternative x y = Catch.try x >>= \case -- Left (_ :: CustomException) -> y -- Right x' -> return x' hslua-2.3.0/test/lua/0000755000000000000000000000000007346545000012561 5ustar0000000000000000hslua-2.3.0/test/lua/error.lua0000644000000000000000000000006107346545000014412 0ustar0000000000000000error 'running this program will cause an error' hslua-2.3.0/test/lua/example.lua0000644000000000000000000000021407346545000014714 0ustar0000000000000000--- Compute the n-th fibonacci number. function fib(n) local a, b = 0, 1 for i = 0, (n - 1) do a, b = b, b + a end return a end hslua-2.3.0/test/lua/syntax-error.lua0000644000000000000000000000001307346545000015733 0ustar0000000000000000just wrong hslua-2.3.0/test/test-hslua.hs0000644000000000000000000000065007346545000014426 0ustar0000000000000000{-| Module : Main Copyright : © 2017-2023 Albert Krewinkel License : MIT Maintainer : Albert Krewinkel Tests for HsLua. -} import Test.Tasty (TestTree, defaultMain, testGroup) import qualified HsLuaTests import qualified HsLua.UtilTests main :: IO () main = defaultMain tests -- | HSpec tests tests :: TestTree tests = testGroup "hslua" [ HsLua.UtilTests.tests , HsLuaTests.tests ]