packages feed

madlang 2.1.0.4 → 2.1.1.0

raw patch · 10 files changed

+179/−131 lines, 10 filesdep +template-haskelldep ~ansi-wl-pprintdep ~basedep ~composition

Dependencies added: template-haskell

Dependency ranges changed: ansi-wl-pprint, base, composition, containers, criterion, directory, hspec, hspec-megaparsec, madlang, megaparsec, microlens, mtl, mwc-random, optparse-applicative, text, tibetan-utils

Files

README.md view
@@ -1,18 +1,21 @@ # Madlang DSL for generating random text [![Build Status](https://travis-ci.org/vmchale/madlibs.svg?branch=master)](https://travis-ci.org/vmchale/madlibs) -This is the Madlang DSL for generating random text. There is also a vim plugin, available [here](https://github.com/vmchale/madlang-vim).  +This is the Madlang DSL for generating text. You specify a template, and Madlang+will create randomized text from the template. -It enables you to generate random templated text with very little effort or expertise. +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). -It can be used for twitter bots and provides human-readable syntax for Markov-chains often used in natural language processing. +There is also a vim plugin for syntax highlighting, available [here](https://github.com/vmchale/madlang-vim). -## Exmaples+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. -An exmaple is worth a thousand words, so suppose you wanted to generate a mediocre fortune telling bot. You could write the following code:+## Examples -```+An example is worth a thousand words, so suppose you wanted to generate a mediocre fortune telling bot. You could write the following code:++```madlang :define person     0.7 "A close friend will "     0.3 "You will "@@ -22,36 +25,45 @@ :define fortune     0.5 "drink a boatload of milk"     0.5 "get angry for no reason"+:define intense+    1.0 person "wrestle in the WWE".to_upper+    1.0 person "bite in a bottle of hot sauce".to_upper :return-    0.8 person fortune+    0.7 person fortune+    0.1 intense     0.2 goodfortune ``` -There are two "statements" 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.+### 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. -## Using the libary+There is also 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 [] "test/templates/gambling.mad"- "heads"+ λ:> runFile [] "demo/shakespeare.mad"+ "Thou hasty-witted gleeking puttock!" ``` -Haddock documentation of all available functionality is located [here](https://hackage.haskell.org/package/madlang#readme).+Haddock documentation of all library functionality is located [here](https://hackage.haskell.org/package/madlang#readme).  ## Installation  ### Releases -If you're on windows or linux, grabbing release binaries is probably the-easiest. Find them [here](https://github.com/vmchale/madlibs/releases).+If you're on windows or linux, grabbing release binaries simplest. +Find them [here](https://github.com/vmchale/madlibs/releases).  ### Nix -If you're on linux or mac, you can just grab the binaries via nix.+If you're on linux or mac, you can get up-to-date binaries via nix.  Download nix with @@ -69,17 +81,14 @@ curl -sSL http://haskellstack.org | sh ``` -Then run `stack install madlang --resolver nightly` and you'll get the `madlang` executable installed on your path.--You can also run `stack install` in the appropriate directory after cloning this-repository. +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  To use it, try  ```- $ madlang run fortune-teller.mad+ $ madlang run demo/shakespeare.mad ```  You can do `madlang --help` if you want a couple other options for debugging.
madlang.cabal view
@@ -1,102 +1,112 @@-name:                madlang-version:             2.1.0.4-synopsis:            Randomized templating language DSL-description:         Please see README.md-homepage:            https://github.com/vmchale/madlang#readme-license:             BSD3-license-file:        LICENSE-author:              Vanessa McHale-maintainer:          tmchale@wisc.edu-copyright:           Copyright: (c) 2016 Vanessa McHale-category:            Web-build-type:          Simple-stability:           experimental-extra-source-files:  README.md-                   , test/templates/fortune-teller.mad-                   , test/templates/gambling.mad-                   , test/templates/var.mad-                   , test/templates/ordered.mad-                   , test/templates/include.mad-                   , test/templates/err/*.mad-                   , bench/templates/*.mad-                   , stack.yaml-                   , bash/mkCompletions-cabal-version:       >=1.10+name: madlang+version: 2.1.1.0+cabal-version: >=1.10+build-type: Simple+license: BSD3+license-file: LICENSE+copyright: Copyright: (c) 2016 Vanessa McHale+maintainer: tmchale@wisc.edu+stability: experimental+homepage: https://github.com/vmchale/madlang#readme+synopsis: Randomized templating language DSL+description:+    Please see README.md+category: Web+author: Vanessa McHale+extra-source-files:+    README.md+    test/templates/fortune-teller.mad+    test/templates/gambling.mad+    test/templates/var.mad+    test/templates/ordered.mad+    test/templates/include.mad+    test/templates/modifiers.mad+    test/templates/err/*.mad+    bench/templates/*.mad+    stack.yaml+    bash/mkCompletions -Flag llvm-fast {-  Description: Enable build with llvm backend-  Default: False-}+source-repository head+    type: git+    location: https://github.com/vmchale/madlang +flag llvm-fast+    description:+        Enable build with llvm backend+    default: False+ library-  hs-source-dirs:      src-  exposed-modules:     Text.Madlibs-  other-modules:       Text.Madlibs.Ana.ParseUtils-                     , Text.Madlibs.Cata.Run-                     , Text.Madlibs.Ana.Parse-                     , Text.Madlibs.Ana.Resolve-                     , Text.Madlibs.Internal.Types-                     , Text.Madlibs.Internal.Utils-                     , Text.Madlibs.Cata.SemErr-                     , Text.Madlibs.Exec.Main-  build-depends:       base >= 4.7 && < 5-                     , megaparsec-                     , text-                     , optparse-applicative-                     , composition-                     , directory-                     , mwc-random-                     , microlens-                     , mtl-                     , ansi-wl-pprint-                     , containers-                     , tibetan-utils-  default-language:    Haskell2010-  default-extensions:  OverloadedStrings-                     , DeriveGeneric-                     , DeriveFunctor-                     , DeriveAnyClass+    exposed-modules:+        Text.Madlibs+    build-depends:+        base >=4.7 && <5,+        megaparsec >=5.2.0 && <5.3,+        text >=1.2.2.1 && <1.3,+        optparse-applicative >=0.13.2.0 && <0.14,+        composition >=1.0.2.1 && <1.1,+        directory >=1.3.0.0 && <1.4,+        mwc-random >=0.13.5.0 && <0.14,+        template-haskell >=2.11.1.0 && <2.12,+        microlens >=0.4.8.0 && <0.5,+        mtl >=2.2.1 && <2.3,+        ansi-wl-pprint >=0.6.7.3 && <0.7,+        containers >=0.5.7.1 && <0.6,+        tibetan-utils >=0.1.1.2 && <0.2+    default-language: Haskell2010+    default-extensions: OverloadedStrings DeriveGeneric DeriveFunctor+                        DeriveAnyClass+    hs-source-dirs: src+    other-modules:+        Text.Madlibs.Ana.ParseUtils+        Text.Madlibs.Cata.Run+        Text.Madlibs.Ana.Parse+        Text.Madlibs.Ana.Resolve+        Text.Madlibs.Internal.Types+        Text.Madlibs.Internal.Utils+        Text.Madlibs.Cata.SemErr+        Text.Madlibs.Exec.Main  executable madlang-  hs-source-dirs:      app-  main-is:             Main.hs-  if flag(llvm-fast)-    ghc-options:       -threaded -rtsopts -with-rtsopts=-N -fllvm -optlo-O3 -O3-  else-    ghc-options:       -threaded -rtsopts -with-rtsopts=-N -  build-depends:       base-                     , madlang-  default-language:    Haskell2010--benchmark tweeths-bench-  type:             exitcode-stdio-1.0-  hs-source-dirs:   bench-  main-is:          Bench.hs-  build-depends:    base-                  , criterion-                  , madlang-                  , megaparsec-                  , text-  if flag(llvm-fast)-    ghc-options:       -threaded -rtsopts -with-rtsopts=-N -fllvm -optlo-O3 -O3-  else-    ghc-options:       -threaded -rtsopts -with-rtsopts=-N -O3-  default-language: Haskell2010+    +    if flag(llvm-fast)+        ghc-options: -threaded -rtsopts -with-rtsopts=-N -fllvm -optlo-O3 -O3+    else+        ghc-options: -threaded -rtsopts -with-rtsopts=-N+    main-is: Main.hs+    build-depends:+        base >=4.9.1.0 && <4.10,+        madlang >=2.1.1.0 && <2.2+    default-language: Haskell2010+    hs-source-dirs: app  test-suite madlang-test-  type:                exitcode-stdio-1.0-  hs-source-dirs:      test-  main-is:             Spec.hs-  build-depends:       base-                     , madlang-                     , hspec-                     , megaparsec-                     , text-                     , mtl-                     , hspec-megaparsec-  ghc-options:         -threaded -rtsopts -with-rtsopts=-N -  default-language:    Haskell2010+    type: exitcode-stdio-1.0+    main-is: Spec.hs+    build-depends:+        base >=4.9.1.0 && <4.10,+        madlang >=2.1.1.0 && <2.2,+        hspec >=2.4.3 && <2.5,+        megaparsec >=5.2.0 && <5.3,+        text >=1.2.2.1 && <1.3,+        mtl >=2.2.1 && <2.3,+        hspec-megaparsec >=0.3.1 && <0.4+    default-language: Haskell2010+    hs-source-dirs: test+    ghc-options: -threaded -rtsopts -with-rtsopts=-N -source-repository head-  type:     git-  location: https://github.com/vmchale/madlang+benchmark tweeths-bench+    +    if flag(llvm-fast)+        ghc-options: -threaded -rtsopts -with-rtsopts=-N -fllvm -optlo-O3 -O3+    else+        ghc-options: -threaded -rtsopts -with-rtsopts=-N -O3+    type: exitcode-stdio-1.0+    main-is: Bench.hs+    build-depends:+        base >=4.9.1.0 && <4.10,+        criterion >=1.1.4.0 && <1.2,+        madlang >=2.1.1.0 && <2.2,+        megaparsec >=5.2.0 && <5.3,+        text >=1.2.2.1 && <1.3+    default-language: Haskell2010+    hs-source-dirs: bench
src/Text/Madlibs/Ana/Parse.hs view
@@ -12,8 +12,10 @@ import qualified Text.Megaparsec.Lexer as L import Data.Monoid import Control.Monad+import qualified Data.Map as M import Control.Monad.State import Control.Exception hiding (try)+import Data.Char import Data.Composition  -- | Parse a lexeme, aka deal with whitespace nicely. @@ -75,17 +77,32 @@ name :: Parser String name = lexeme (some (letterChar <|> oneOf ("-/" :: String))) <?> "template name" +-- | Parse a modifier+modifier :: Parser (T.Text -> T.Text)+modifier = do+    char '.'+    str <- try (string "to_upper") <|> (string "to_lower") +    let modifiers = M.fromList [("to_upper", T.map toUpper), ("to_lower", T.map toLower)] in +        pure $ maybe id id (M.lookup str modifiers)+ -- | Parse template into a `PreTok` of referents and strings preStr :: [T.Text] -> Parser PreTok-preStr ins = (fmap (Name . T.pack) name) <|>+preStr ins = do { +        n <- name ;+        mod <- optional $ modifier ;+        spaceConsumer ;+        pure $ Name (T.pack n) (maybe id id mod)+    } <|>     do {         v <- var ;+        spaceConsumer ;         pure . PreTok $ ins `access` (v-1) -- ins !! (v - 1)     } <|>     do {         s <- quote (many $ noneOf ("\n\"" :: String)) ;+        mod <- optional $ modifier ;         spaceConsumer ;-        pure $ PreTok . T.pack $ s+        pure $ PreTok . (maybe id id mod) . T.pack $ s     }      <?> "string or function name" @@ -101,10 +118,9 @@ inclusions :: Parser [String] inclusions = many . try $ do     include-    str <- name+    str <- name -- make this broader     string ".mad"-    pure (str ++ ".mad")-        -- still needs dependency resolution but eh+    pure (str ++ ".mad") -- TODO dependency resolution (?)  -- | Parse a `define` block definition :: [T.Text] -> Parser (Key, [(Prob, [PreTok])])
src/Text/Madlibs/Ana/ParseUtils.hs view
@@ -24,7 +24,7 @@ concatTok param pretoks = do     ctx <- get     let unList (List a) = a-    let toRand (Name str) = List . snd . (head' str param) . (filter ((== str) . fst)) . (map (second unList)) $ ctx-- TODO fix head' which can fail because of lack of scope too+    let toRand (Name str f) = (apply f) . List . snd . (head' str param) . (filter ((== str) . fst)) . (map (second unList)) $ ctx-- TODO fix head' which can fail because of lack of scope too         toRand (PreTok txt) = Value txt     fold . (map toRand) <$> pretoks @@ -33,7 +33,7 @@ buildTok param pretoks = do     ctx <- get     let unList (List a) = a-    let toRand (Name str) = List . snd . (head' str param) . (filter ((==str) . fst)) . (map (second unList)) $ ctx+    let toRand (Name str f) = (apply f) . List . snd . (head' str param) . (filter ((==str) . fst)) . (map (second unList)) $ ctx -- TODO use modifier alongside name?         toRand (PreTok txt) = Value txt     List . zip ([1..]) . (map toRand) <$> pretoks 
src/Text/Madlibs/Internal/Types.hs view
@@ -20,12 +20,16 @@ type Key = T.Text  -- | Pretoken, aka token as first read in-data PreTok = Name T.Text | PreTok T.Text-    deriving (Show, Eq)+data PreTok = Name T.Text (T.Text -> T.Text) | PreTok T.Text+    --deriving (Show, Eq)  -- | datatype for a token returning a random string data RandTok = List [(Prob, RandTok)] | Value T.Text     deriving (Show, Eq)++apply :: (T.Text -> T.Text) -> RandTok -> RandTok -- make a base functor so we can map f over stuff?+apply f (Value str) = Value (f str)+apply f (List l) = List $ map (over _2 (apply f)) l  -- | Function to transform a `RandTok` into a `Tree String` so that it can be pretty-printed.  --
src/Text/Madlibs/Internal/Utils.hs view
@@ -52,7 +52,7 @@ -- | Strip a pre-token's name unTok :: PreTok -> T.Text unTok (PreTok txt) = ""-unTok (Name txt) = txt+unTok (Name txt _) = txt  -- | Read a file in as a `Text` readFile' :: FilePath -> IO T.Text
test/Spec.hs view
@@ -15,9 +15,9 @@ main :: IO () main = hspec $ do     describe "parseTok" $ do-        parallel $ it "parses a .mad string" $ do+        parallel $ it "parses a .mad string with modifiers" $ do             file <- madFile-            parseTok "" [] [] file `shouldParse` (List [(1.0,List [(0.5,Value "heads"),(0.5,Value "tails")])])+            parseTok "" [] [] file `shouldParse` (List [(1.0,List [(0.5,Value "HEADS"),(0.5,Value "tails")])])         parallel $ it "fails when quotes aren't closed" $ do             file <- madFileFailure             parseTok "" [] [] `shouldFailOn` file@@ -39,7 +39,9 @@         --    file <- madFileTibetan         --    parseTok "" [] file `shouldParse` (List [(1.0,List [(0.5,Value "heads"),(0.5,Value "tails")])])     describe "runFile" $ do-        parallel $ it "parses file with inclusions" $ \file -> do+        parallel $ it "parses nested modifiers correctly" $ \file -> do+            runFile [] "test/templates/modifiers.mad" >>= (`shouldSatisfy` (\a -> any (a==) ["AAAaaa","AAAaa","AAaaa","AAaa"]))+        parallel $ it "parses file with inclusions and modifiers on functions" $ \file -> do             runFile [] "test/templates/include.mad" >>= (`shouldSatisfy` (\a -> any (a==) ["heads","tails","on its side"]))         parallel $ it "runs on a file out of order" $ \file -> do             runFile [] "test/templates/ordered.mad" >>= (`shouldSatisfy` (\a -> any (a==) ["heads","tails","one","two","three","third"]))
test/templates/gambling.mad view
@@ -1,5 +1,5 @@ :define something-    0.5 "heads"-    0.5 "tails"+    0.5 "heads".to_upper+    0.5 "tailS".to_lower :return     1.0 something
test/templates/include.mad view
@@ -1,6 +1,6 @@ :include gambling.mad :define realistic-    1.0 something+    1.0 something.to_lower     0.03 "on its side" :return     1.0 realistic
+ test/templates/modifiers.mad view
@@ -0,0 +1,7 @@+:define scream+    1.0 "aaa".to_upper+    1.0 "aa".to_upper+:define sedated+    1.0 scream.to_lower+:return+    1.0 scream sedated