Skip to content

Commit

Permalink
FutharkScript: add $loadbytes builtin.
Browse files Browse the repository at this point in the history
  • Loading branch information
athas authored and CKuke committed Nov 8, 2023
1 parent af98e86 commit 69620da
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 13 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

### Added

* FutharkScript now has a `$loadbytes` builtin function for reading
arbitrary bytes into Futhark programs.

### Removed

### Changed
Expand Down
3 changes: 3 additions & 0 deletions docs/man/futhark-literate.rst
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,9 @@ Futhark. The following builtins are supported:
of values is returned, which should be destructured before use. For example:
``let (a, b) = $loaddata "foo.in" in bar a b``.

* ``$loadbytes "file"`` reads the contents of the given file as an
array of type ``[]u8``.

* ``$loadaudio "file"`` reads audio from the given file and returns it as a
``[][]f64``, where each row corresponds to a channel of the original
soundfile. Most common audio-formats are supported, including mp3, ogg, wav,
Expand Down
8 changes: 4 additions & 4 deletions docs/man/futhark-test.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ floating-point constants (always with type suffix) are also permitted.
If ``input`` is preceded by ``script``, the text between the curly
braces is interpreted as a FutharkScript expression (see
:ref:`futhark-literate(1)`), which is executed to generate the input.
It must use only functions explicitly declared as entry points. If
the expression produces an *n*-element tuple, it will be unpacked and
its components passed as *n* distinct arguments to the test function.
The only builtin function supported is ``$loaddata``.
It must use only functions explicitly declared as entry points. If the
expression produces an *n*-element tuple, it will be unpacked and its
components passed as *n* distinct arguments to the test function. The
only builtin functions supported are ``$loaddata`` and ``$loadbytes``.

If ``input`` is followed by an ``@`` and a file name (which must not
contain any whitespace) instead of curly braces, values will be read
Expand Down
32 changes: 23 additions & 9 deletions src/Futhark/Script.hs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import Control.Monad
import Control.Monad.Except (MonadError (..))
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Bifunctor (bimap)
import Data.ByteString qualified as BS
import Data.ByteString.Lazy qualified as LBS
import Data.Char
import Data.Foldable (toList)
Expand Down Expand Up @@ -356,20 +357,33 @@ loadData datafile = do
Just vs ->
pure $ V.ValueTuple $ map V.ValueAtom vs

-- | Handles the following builtin functions: @loaddata@. Fails for
-- everything else. The 'FilePath' indicates the directory that files
-- should be read relative to.
scriptBuiltin :: (MonadIO m, MonadError T.Text m) => FilePath -> EvalBuiltin m
scriptBuiltin dir "loaddata" vs =
pathArg ::
(MonadError T.Text f) =>
FilePath ->
T.Text ->
[V.Compound V.Value] ->
f FilePath
pathArg dir cmd vs =
case vs of
[V.ValueAtom v]
| Just path <- V.getValue v -> do
let path' = map (chr . fromIntegral) (path :: [Word8])
loadData $ dir </> path'
| Just path <- V.getValue v ->
pure $ dir </> map (chr . fromIntegral) (path :: [Word8])
_ ->
throwError $
"$loaddata does not accept arguments of types: "
"$"
<> cmd
<> " does not accept arguments of types: "
<> T.intercalate ", " (map (prettyText . fmap V.valueType) vs)

-- | Handles the following builtin functions: @loaddata@, @loadbytes@.
-- Fails for everything else. The 'FilePath' indicates the directory
-- that files should be read relative to.
scriptBuiltin :: (MonadIO m, MonadError T.Text m) => FilePath -> EvalBuiltin m
scriptBuiltin dir "loaddata" vs = do
loadData =<< pathArg dir "loaddata" vs
scriptBuiltin dir "loadbytes" vs = do
fmap (V.ValueAtom . V.putValue1) . liftIO . BS.readFile
=<< pathArg dir "loadbytes" vs
scriptBuiltin _ f _ =
throwError $ "Unknown builtin function $" <> prettyText f

Expand Down
6 changes: 6 additions & 0 deletions tests/script/script6.fut
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- Can we read our own source code?
-- ==
-- script input { $loadbytes "script6.fut" }
-- output { 139i64 }

def main (s: []u8) = length s

0 comments on commit 69620da

Please sign in to comment.