madlang 2.3.0.3 → 2.3.0.4
raw patch · 12 files changed
+123/−55 lines, 12 filesdep +file-embeddep −file-embed-polydep ~base
Dependencies added: file-embed
Dependencies removed: file-embed-poly
Dependency ranges changed: base
Files
- README.md +33/−19
- default.nix +7/−5
- demo/example.mad +42/−0
- madlang.cabal +7/−5
- src/Text/Madlibs/Ana/Parse.hs +1/−1
- src/Text/Madlibs/Ana/ParseUtils.hs +11/−2
- src/Text/Madlibs/Cata/Display.hs +1/−0
- src/Text/Madlibs/Cata/Run.hs +1/−1
- src/Text/Madlibs/Exec/Main.hs +9/−14
- src/Text/Madlibs/Generate/TH.hs +7/−3
- src/Text/Madlibs/Internal/Utils.hs +3/−3
- stack.yaml +1/−2
README.md view
@@ -4,12 +4,12 @@ This is the Madlang DSL for generating text. You specify a template, and Madlang will create randomized text from the template. -It is an interpreted language, written in Haskell. It runs from the command line, but it is also a Haskell library that can be integrated into [other projects](https://github.com/vmchale/toboggan).+Madlang is an interpreted language, written in Haskell. It runs from the command line, but also provides a Haskell library that can be integrated into [other projects](https://github.com/vmchale/toboggan), compiled to a [web app](https://github.com/vmchale/madlang-reflex), or used as an EDSL. There is also a vim plugin for syntax highlighting, available [here](https://github.com/vmchale/madlang-vim). -It can be used for twitter bots (among other things) and provides human-readable syntax for the Markov-chains that are often used to generate text.+It can be used for twitter bots (among other things) and provides human-readable+syntax for generating text. ## Examples @@ -36,24 +36,11 @@ ### Syntax -There are two keywords in madlang: `:define` and `:return`. `:return` is the main string we'll be spitting back, so there can be only one per file. `:define` on the other hand can be used to make multiple templates. These templates are combinations of strings (enclosed in quotes) and names of other templates.--Of course, you can't have a circular reference with names - if `goodfortune` depends on `fortune` while `fortune` depends on `goodfortune`, we end up with either no fortune or an infinite fortune. So we throw an error.+There are two keywords in madlang you'll use most: `:define` and `:return`. `:return` is the main string we'll be spitting back; there can be only one per file. `:define` on the other hand can be used to make functions. These functions are combinations of templates, organizing pairs of weights and strings. -There is also a Shakespearean insult generator demo available in+There is a Shakespearean insult generator demo available in `demo/shakespeare.mad` -## Using the library--The main function you'll want to use is probably `runFile`; it reads a file and generates randomized text:--```- λ:> runFile [] "demo/shakespeare.mad"- "Thou hasty-witted gleeking puttock!"-```--Haddock documentation of all library functionality is located [here](https://hackage.haskell.org/package/madlang#readme).- ## Installation ### Releases@@ -81,7 +68,7 @@ curl -sSL http://haskellstack.org | sh ``` -Then run `stack install madlang --resolver nightly` and you'll get the `madlang` executable installed on your path. This may take a bit of time, as it will build *all* dependencies of `madlang` first. +Then run `stack install madlang --resolver nightly` and you'll get the `madlang` executable installed on your path. This may take a bit of time, as it will build *all* dependencies of `madlang` first. ### Use @@ -93,6 +80,33 @@ You can do `madlang --help` if you want a couple other options for debugging. +## Using the library++One function you might want to use is `runFile`; it reads a file and generates randomized text:++```+ λ:> runFile [] "demo/shakespeare.mad"+ "Thou hasty-witted gleeking puttock!"+```++To use the library as an EDSL, there are two options: splicing in a file or+using a quasi-quoter, viz.++```haskell+demo :: IO T.Text+demo = run+ $(madFile "demo/shakespeare.mad")++demo :: IO T.Text+demo = run [|madlang+:define f+ 1.0 "heads"+ 1.0 "tails"+:return+ 1.0 f|]+```++Haddock documentation of all library functionality is located [here](https://hackage.haskell.org/package/madlang#readme). ## Syntax Highlighting Syntax highlighting for the DSL is provided in the vim plugin [here](http://github.com/vmchale/madlang-vim). It includes integration with [syntastic](https://github.com/vim-syntastic/syntastic).
default.nix view
@@ -1,16 +1,18 @@ { mkDerivation, ansi-wl-pprint, base, composition, containers-, directory, hspec, hspec-megaparsec, megaparsec, microlens, mtl-, mwc-random, optparse-applicative, random-shuffle, stdenv, text+, directory, file-embed-poly, hspec, hspec-megaparsec, megaparsec+, microlens, MonadRandom, mtl, optparse-applicative, random-shuffle+, stdenv, template-haskell, text }: mkDerivation { pname = "madlang";- version = "2.2.0.0";+ version = "2.3.0.3"; src = ./.; isLibrary = true; isExecutable = true; libraryHaskellDepends = [- ansi-wl-pprint base composition containers directory megaparsec- microlens mtl mwc-random optparse-applicative random-shuffle text+ ansi-wl-pprint base composition containers directory+ file-embed-poly megaparsec microlens MonadRandom mtl+ optparse-applicative random-shuffle template-haskell text ]; executableHaskellDepends = [ base ]; testHaskellDepends = [
+ demo/example.mad view
@@ -0,0 +1,42 @@+:define mainCharacter+ 1.0 "mechanic"+ 1.0 "professor"+ 1.0 "madonna"+ 1.0 "miner"+ 1.0 "mercenary"+ 1.0 "pilot"++:define mainCharacterTrait+ 1.0 "prolix "+ 1.0 "maudlin "+ 1.0 "pompous "+ 1.0 "prevaricating "+ 1.0 "miniscule "+ 1.0 "preening "++:define superlative+ 1.0 "grandiose "+ 1.0 "accomplished "+ 1.0 "saturnine "+ 1.0 "beautiful "+ 1.0 "gracious "+ 1.0 "lithe "++:define predicate+ 1.0 "fell asleep."+ 1.0 "wishes she could journey around the world."+ 1.0 "falls down on the subway escalator."+ 1.0 "meets a handsome dark stranger."+ 1.0 "suffers because mercury is in powerade."+ 1.0 "charms a prince."++:define subject+ 3.0 "A " mainCharacterTrait mainCharacter " "+ 1.0 "The most " superlative "of " mainCharacterTrait mainCharacter "s "++:define final+ 1.0 subject.to_upper predicate+ 6.0 subject predicate+:return+ 1.0 final+ 0.02 final.oulipo
madlang.cabal view
@@ -1,5 +1,5 @@ name: madlang-version: 2.3.0.3+version: 2.3.0.4 synopsis: Randomized templating language DSL description: Please see README.md homepage: https://github.com/vmchale/madlang#readme@@ -39,6 +39,7 @@ , Text.Madlibs.Cata.SemErr , Text.Madlibs.Cata.Display , Text.Madlibs.Exec.Main+ , Paths_madlang build-depends: base >= 4.7 && < 5 , megaparsec , text@@ -47,7 +48,7 @@ , MonadRandom , composition , directory- , file-embed-poly+ , file-embed , random-shuffle , microlens , mtl@@ -63,14 +64,15 @@ hs-source-dirs: app main-is: Main.hs if flag(llvm-fast)- ghc-options: -threaded -rtsopts -with-rtsopts=-N -fllvm -optlo-O3 -O3+ ghc-options: -threaded -static -fllvm -optlo-O3 -O3+---optc-static -optl-static else ghc-options: -threaded -rtsopts -with-rtsopts=-N build-depends: base , madlang default-language: Haskell2010 -benchmark tweeths-bench+benchmark madlang-bench type: exitcode-stdio-1.0 hs-source-dirs: bench main-is: Bench.hs@@ -80,7 +82,7 @@ , megaparsec , text if flag(llvm-fast)- ghc-options: -threaded -rtsopts -with-rtsopts=-N -fllvm -optlo-O3 -O3+ ghc-options: -threaded -fllvm -optlo-O3 -O3 else ghc-options: -threaded -rtsopts -with-rtsopts=-N -O3 default-language: Haskell2010
src/Text/Madlibs/Ana/Parse.hs view
@@ -81,7 +81,7 @@ modifier :: Parser (T.Text -> T.Text) modifier = do char '.'- str <- (try $ string "to_upper") <|> (string "to_lower")+ str <- foldr (<|>) (pure "") $ map (try . string) ["to_upper", "to_lower", "reverse", "reverse_words", "oulipo"] pure (fromMaybe id (M.lookup str modifierList)) <?> "modifier" -- | Parse template into a `PreTok` of referents and strings
src/Text/Madlibs/Ana/ParseUtils.hs view
@@ -13,15 +13,24 @@ import System.Random.Shuffle import qualified Data.Map as M import Data.Char+import Control.Monad.Random.Class --TODO consider moving Ana.ParseUtils to Cata.Sorting +-- | A map with all the modifiers we modifierList :: M.Map String (T.Text -> T.Text)-modifierList = M.fromList [("to_upper", T.map toUpper), ("to_lower", T.map toLower)]+modifierList = M.fromList [("to_upper", T.map toUpper)+ , ("to_lower", T.map toLower)+ , ("reverse", T.reverse)+ , ("reverse_words", T.unwords . reverse . T.words)+ , ("oulipo", T.filter (/='e'))] -jumble :: T.Text -> IO T.Text+-- | Jumble the words in a string+jumble :: (MonadRandom m) => T.Text -> m T.Text jumble = (fmap (T.pack . unwords)) . shuffleM . words . T.unpack +-- | Strip file extension+strip :: String -> T.Text strip = T.pack . reverse . drop 4 . reverse -- | Get the :return value
src/Text/Madlibs/Cata/Display.hs view
@@ -1,3 +1,4 @@+-- | Module with helper functions for displaying the parsed tree module Text.Madlibs.Cata.Display where import Data.Tree
src/Text/Madlibs/Cata/Run.hs view
@@ -16,7 +16,7 @@ -- @ run :: (MonadRandom m) => RandTok -> m T.Text run tok@(List rs) = do- value <- getRandomR (0,1) --(withSystemRandom . asGenST $ \gen -> uniform gen)+ value <- getRandomR (0,1) let ret = ((snd . head) . filter ((>=value) . fst)) $ mkCdf tok case ret of (Value txt) -> pure txt
src/Text/Madlibs/Exec/Main.hs view
@@ -14,6 +14,8 @@ import Data.Maybe import Data.Composition import System.Directory+import Paths_madlang+import Data.Version -- | datatype for the program data Program = Program { sub :: Subcommand @@ -21,7 +23,7 @@ } -- | datatype for the subcommands-data Subcommand = Debug { version :: Bool }+data Subcommand = Debug | Run { rep :: Maybe Int , clInputs :: [String] } | Lint { clInputs :: [String] } @@ -30,20 +32,12 @@ orders = Program <$> (hsubparser (command "run" (info temp (progDesc "Generate text from a .mad file"))- <> command "debug" (info debug (progDesc "Debug a template"))+ <> command "debug" (info (pure Debug) (progDesc "Debug a template")) <> command "lint" (info lint (progDesc "Lint a file")))) <*> (argument str (metavar "FILEPATH" <> help "File path to madlang template")) --- | Parser for debug subcommand-debug :: Parser Subcommand-debug = Debug- <$> switch- (long "version"- <> short 'v'- <> help "Show version information")- -- | Parser for the run subcommand temp :: Parser Subcommand temp = Run@@ -74,11 +68,13 @@ runMadlang :: IO () runMadlang = execParser wrapper >>= template +versionInfo = infoOption ("madlang version: " ++ showVersion version) (short 'v' <> long "version" <> help "Show version")+ -- | Wraps parser with help parser-wrapper = info (helper <*> orders)+wrapper = info (helper <*> versionInfo <*> orders) (fullDesc <> progDesc "Madlang templating language"- <> header "Madlang - markov chains made easy")+ <> header ("Madlang - templating text made easy")) -- | given a parsed record perform the appropriate IO action template :: Program -> IO ()@@ -91,8 +87,7 @@ (Run reps _) -> do parsed <- parseFile ins "" filepath replicateM_ (fromMaybe 1 reps) $ runFile ins filepath >>= TIO.putStrLn - (Debug _) -> do- putStr . (either show displayTree) =<< makeTree ins "" filepath + Debug -> putStr . (either show displayTree) =<< makeTree ins "" filepath (Lint _) -> do parsed <- parseFile ins "" filepath putStrLn $ either parseErrorPretty (const "No syntax errors found.") parsed
src/Text/Madlibs/Generate/TH.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE TemplateHaskell #-} +-- | Module containing Quasi-Quoter and Template Haskell splice for use as an EDSL. module Text.Madlibs.Generate.TH ( textToExpression , madFile@@ -14,6 +15,7 @@ import Language.Haskell.TH.Quote import Data.FileEmbed import Text.Megaparsec+import Data.Text.Encoding -- | `QuasiQuoter` for an EDSL, e.g. -- @@ -35,13 +37,15 @@ , quotePat = error "quasi-quoter does not support patterns" , quoteType = error "quasi-quoter does not support types" , quoteDec = error "quasi-quoter does not support top-level quotes"- } -- TODO add quasiQuoter w/context etc.+ } -- TODO add quasiQuoter w/inclusions or context +-- | Convert a `String` containing to a `Q Exp` with the parsed syntax tree. textToExpression :: String -> Q Exp textToExpression txt = do parse <- [|parseTok "source" [] []|] pure $ (VarE 'errorgen) `AppE` (parse `AppE` ((VarE 'T.pack) `AppE` (LitE (StringL (txt))))) +-- | Turn a parse error into an error that will be caught when Template Haskell compiles at runtime. errorgen :: Either (ParseError Char Dec) a -> a errorgen = either (error . T.unpack . show') id @@ -56,6 +60,6 @@ -- Note that the embedded code cannot have any inclusions. madFile :: FilePath -> Q Exp madFile path = do- file <- embedFile path- parse <- [|parseTok "source" [] []|] -- TODO make this recurse but still work!+ file <- (embedFile path)+ parse <- [|(parseTok "source" [] []) . decodeUtf8|] -- TODO make this recurse but still work! pure $ (VarE 'errorgen) `AppE` (parse `AppE` file)
src/Text/Madlibs/Internal/Utils.hs view
@@ -27,9 +27,9 @@ -- | Add a PR for this? Could be useful in Megaparsec idk -- Allows us to use monoidal addition on parsers-instance (Monoid a) => Monoid (Parser a) where- mempty = pure mempty- mappend x y = mappend <$> x <*> y+--instance (Monoid a) => Monoid (Parser a) where+-- mempty = pure mempty+-- mappend x y = mappend <$> x <*> y -- | Normalize pre-tokens/corresponding probabilities normalize :: [(Prob, [PreTok])] -> [(Prob, [PreTok])]
stack.yaml view
@@ -3,5 +3,4 @@ packages: - '.' extra-deps:-- file-embed-poly-0.1.0-resolver: lts-8.11+resolver: lts-8.12