language-dickinson 0.1.1.1 → 0.1.1.2
raw patch · 25 files changed
+358/−78 lines, 25 filesdep ~prettyprinterPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: prettyprinter
API changes (from Hackage documentation)
Files
- CHANGELOG.md +7/−0
- bench/Bench.hs +46/−6
- examples/catherineOfSienaBot.dck +104/−0
- examples/fionaBot.dck +19/−3
- examples/fortune.dck +7/−2
- language-dickinson.cabal +5/−2
- lib/adjectives.dck +6/−0
- lib/noun.dck +5/−0
- lib/profession.dck +24/−0
- man/emd.1 +13/−0
- run/Format.hs +15/−0
- run/Main.hs +17/−12
- run/REPL.hs +1/−2
- run/REPL/Completions.hs +1/−1
- src/Language/Dickinson/Check/Internal.hs +3/−0
- src/Language/Dickinson/Eval.hs +8/−5
- src/Language/Dickinson/File.hs +13/−22
- src/Language/Dickinson/Lexer.x +2/−1
- src/Language/Dickinson/Pipeline.hs +27/−0
- src/Language/Dickinson/Type.hs +10/−3
- test/Eval.hs +7/−6
- test/data/flattenLambda.dck +5/−0
- test/data/lexDollarSign.pretty +8/−8
- test/data/multiQuoteify.pretty +2/−2
- test/data/nestLet.pretty +3/−3
CHANGELOG.md view
@@ -1,5 +1,12 @@ # dickinson +## 0.1.1.2++ * Ignore lines starting with `#!` (for shell shebangs)+ * Fix bug in evaluator which caused `:flatten` to work improperly.+ * Fix bug which caused `:match` within `:flatten` to work improperly.+ * Formatter is now usable; added `--inplace` flag to `emd fmt`+ ## 0.1.1.1 * Run typechecker before evaluator in executable/REPL
bench/Bench.hs view
@@ -1,20 +1,32 @@ module Main (main) where import Control.Exception (throw)+import Control.Exception.Value (eitherThrow) import Control.Monad (void) import Criterion.Main import Data.Binary (decode, encode) import qualified Data.ByteString.Lazy as BSL+import qualified Data.Text as T import Language.Dickinson.Check+import Language.Dickinson.Check.Internal import Language.Dickinson.DuplicateCheck+import Language.Dickinson.Eval import Language.Dickinson.File import Language.Dickinson.Lexer import Language.Dickinson.Parser+import Language.Dickinson.Pipeline import Language.Dickinson.Rename import Language.Dickinson.ScopeCheck import Language.Dickinson.Type+import Language.Dickinson.TypeCheck import Language.Dickinson.Unique +benchResult :: FilePath -> Benchmark+benchResult fp = bench fp $ nfIO (evalFile [] fp)++benchPipeline :: FilePath -> Benchmark+benchPipeline fp = bench fp $ nfIO (pipeline [] fp)+ main :: IO () main = defaultMain [ env parses $ \ ~(c, s) ->@@ -46,19 +58,36 @@ , bench "bench/data/multiple.dck" $ nf checkDuplicates p -- TODO: better example ] , bgroup "result"- [ bench "test/eval/context.dck" $ nfIO (evalFile [] "test/eval/context.dck")- , bench "examples/shakespeare.dck" $ nfIO (evalFile [] "examples/shakespeare.dck")+ [ benchResult "test/eval/context.dck"+ , benchResult "examples/shakespeare.dck" , bench "examples/doggo.dck" $ nfIO (evalFile ["prelude"] "examples/doggo.dck") , bench "test/demo/animal.dck" $ nfIO (evalFile ["lib"] "test/demo/animal.dck")- , bench "examples/fortune.dck" $ nfIO (evalFile [] "examples/fortune.dck")+ , benchResult "examples/fortune.dck" ] , bgroup "pipeline"- [ bench "examples/shakespeare.dck" $ nfIO (pipeline [] "examples/shakespeare.dck")- , bench "examples/fortune.dck" $ nfIO (pipeline [] "examples/fortune.dck")+ [ benchPipeline "examples/shakespeare.dck"+ , benchPipeline "examples/fortune.dck"+ , benchPipeline "examples/catherineOfSienaBot.dck" ] , bgroup "tcFile"- [ bench "examples/fortune.dck" $ nfIO (tcFile [] "examples/fortune.dck")+ [ bench "examples/fortune.dck" $ nfIO (tcFile [] "examples/fortune.dck") -- TODO: tc with syntax tree in env? ]+ , env amalFortune $ \f ->+ bgroup "typecheck"+ [ bench "examples/fortune.dck" $ nf tyRun f ]+ , env amalgamated $ \ ~(s, c) ->+ bgroup "check + eval"+ [ bench "examples/shakespeare.dck" $ nfIO (txtIO s)+ , bench "examples/catherineOfSienaBot.dck" $ nfIO (txtIO c)+ ]+ , env amalgamated $ \ ~(s, c) ->+ bgroup "eval"+ [ bench "examples/shakespeare.dck" $ nfIO (evalIO $ evalDickinsonAsMain s)+ , bench "examples/catherineOfSienaBot.dck" $ nfIO (evalIO $ evalDickinsonAsMain c)+ ]+ , env multiParsed $ \p ->+ bgroup "maxUnique"+ [ bench "bench/data/multiple.dck" $ nf maxUniqueDickinson p ] ] where libFile = BSL.readFile "lib/color.dck"@@ -69,6 +98,17 @@ encoded = encode . void <$> multiParsed encodeShakespeare = encode . void . either throw id . parse <$> shakespeare encodeEnv = (,) <$> encoded <*> encodeShakespeare+ amalFortune = amalgamateRename [] "examples/fortune.dck"+ amalgamated = (,)+ <$> amalgamateRename [] "examples/shakespeare.dck"+ <*> amalgamateRename [] "examples/catherineOfSienaBot.dck" plainExpr :: (UniqueCtx, Dickinson a) -> Dickinson a plainExpr = fst . uncurry renameDickinson++-- FIXME: StdGen in env?+txtIO :: [Declaration AlexPosn] -> IO T.Text+txtIO = fmap eitherThrow . evalIO . checkEvalM++maxUniqueDickinson :: Dickinson AlexPosn -> Int+maxUniqueDickinson (Dickinson _ ds) = maximum (maxUniqueDeclaration <$> ds)
examples/catherineOfSienaBot.dck view
@@ -24,6 +24,14 @@ (| "If you have conceived the virtue of courage within you, you will always be strong and constant.") (| '''+ Their disordered love for themselves, out of which grew all their wickedness, will burn and torture them intolerably,+ for along with pride it is the head and source of all evil.+ ''')+ (| "Just as a mirror reflect's a person's face, just so, the fruit of their labors will be reflected in their bodies.")+ (| "The soul by its nature always craves what is good.")+ (| "Conscience always pulls in one direction, and sensuality in the other.")+ (|+ ''' I bound her into a body formed from the vilest earth so that when she saw her beauty she would not lift up her head in pride. ''')@@ -31,12 +39,14 @@ ''' I am the rewarder of every labor, and I give to all in accordance with their state in life and effort. ''')+ (| "Every good is rewarded and every sin punished.") (| "One cannot be deprived of the practice of doing good unless one so chooses.") (| ''' The more they have to endure, the more delighted they are. Indeed, suffering many difficulties is for them a kind of refreshment. ''')+ (| "Every evil is grounded in selfish love of oneself.") (| "You should build your foundation by slaying and annhilating your self-will.") (| "Humility comes from knowledge and holy hatred of oneself.") (| "All the sufferings the soul bears or can bear in this life are not enough to punish one smallest sin.")@@ -44,11 +54,105 @@ (| "Suffering and sorrow increase in proportion to love.") (| "Everywhere, on all levels of society, all are giving birth to sin.") (| "All virtues are bound together.")+ (| "Neither the devil nor any other creature can force you to the least sin unless you want it.")+ (| "Though the world may persecute you, I am at your side and never will my providence fail you.")+ (| "Weep for the damnation of the foolish and be glad for the perfection of my beloved children.")+ (| "In whatever situation people may be, let their will be good and holy.") (| '''+ Just as venom is painful to the body and ultimately causes death unless a person makes the effort to vomit+ it out and take some medicine, so it is with the scorpion of the world's pleasure.+ ''')+ (|+ '''+ Because the world's troubles sometimes weary them, they begin to dislike the world. And if they take advantage+ of this fear enlightened by faith, they will progress to the love of virtue.+ ''')+ (| "Perseverance is the virtue that receives glory.")+ (| "While you are alive you have a season of mercy, but once you are dead it is your season of justice.")+ ; (| "The soul cannot stand still: she either to advance toward virtue or turn back.") FIXME+ (| "Ordinary people are deluded in their sensual love.")+ (| "The soul in the purity of her conscience sees guilt even when there was no guilt.")+ (| "The world holds them in reverence because they have despised the world.")+ (| "Sufferings increase and strengthen virtue.")+ (| "Those in power rule with great injustice and vanity.")+ (|+ '''+ And they are happier to see many different ways than if they were to see everyone walking the same way,+ because this way they see the greatness of my goodness more fully revealed. In everything they find joy+ and the fragrance of the rose. This is true not only of good things; even when they see something that is+ clearly sinful they do not pass judgment, but rather feel a holy and genuine compassion, praying for the+ sinner and saying with perfect humility "Today it is your turn; tomorrow it will be mine unless divine+ grace holds up."+ ''')+ (| "There is no one who can judge the hidden heart.")+ (| "The perfect receive eternal life, and the wicked eternal damnation.")+ (| "The heart is source of all emotions.")+ (| "You reach perfection through knowledge and contempt of yourself.")+ (| "If she were anything at all of herself, she would be able to get rid of what she did not want.")+ (| "The more the heart loves, the more sorrow it has.")+ (|+ '''+ The devil fled. But he returned with another attack, wanting to exalt you in pride. He said "You are perfect+ and pleasing to God. You no longer need to torture yourself or weep over your sins."+ ''')+ (|+ '''+ It is far better to walk in the spiritual counsel of a humble and unschooled person with a holy and upright+ conscience than by that of a well-read but proud scholar.+ ''')+ (|+ ''' Just as you can better see the blemish on your face when you look at yourself in a mirror, so the soul who in true self-knowledge rises up with desire to look at herself in the gentle mirror of God with the eye of understanding sees all the more clearly her own defects because of the purity she sees in him.+ ''')+ (|+ '''+ Even if your neighbors' sins are clearly shown to your spirit not just once or twice but many times, you+ should still not confront them with specific sins. Rather, when they come to visit you, you should correct+ their bad habits in a general way and kindly plant the virtues, adding severity to your kindness when you+ must.+ ''')+ (| "Penance is good for beating down the body when it wants to fight against the spirit.")+ (| "Things can be better known by looking at their opposites.")+ (| "You cannot live without love.")+ (| "Your being was given to you for love.")+ (| "Your dull bodily senses are deceived.")+ (| "No cloak can hide anything from my sight.")+ (| "Those whose reprimands are only words unsupported by good and well-ordered life are doing wrong.")+ (| "Pleasures are for worldly people.")+ (| "The body is a dead thing because it has no life in itself.")+ (| "Hundred is a perfect number.")+ (| "It is in every respect dangerous to be content with mediocre obedience.")+ (| "All, no matter what their state in life, can have perfect merit.")+ (|+ '''+ So it is with prelates or anyone else in authority. If they see the members who are their subjects rotting+ because of the filth of deadly sin and apply only the ointment of soft words without reproof, they will+ never get well. Rather, they will infect the other members with whom they form one body under their shepherd.+ ''')+ (| "There is no service without hope, for servants serve in the hope of pleasing")+ (| "Those who trust in themselves are afraid of their own shadow; they expect both heaven and earth to let them down.")+ (| "Those who were perfect took on qualities of the sun.")+ (| "Everyone who is virtuous is worthy of love.")+ (| "There is no one in this life, no matter how perfect, who cannot grow to greater perfection.")+ (| "As long as you are alive you can still grow in perfection and merit.")+ (| "One's catch will be as perfect as one's cast.")+ (| "The human body cannot live on nothing but greens.")+ (| "People are humble as they are obedient and obedient as they are humble.")+ (|+ '''+ It is impossible to keep one's mind pure while indulging in a great social life, bodily delicacy, and+ inordinate eating.+ ''')+ (|+ '''+ If you turn to purgatory, there you will find my gentle immeasurable providence.+ ''')+ (|+ '''+ Those who go the way of great self-contempt are, it is true, more apt to reach perfection. ''') (| '''
examples/fionaBot.dck view
@@ -1,6 +1,6 @@ %- -; see https://twitter.com/fionalyric for a fully fleshed-out implementation of this idea+; see https://twitter.com/fionalyric for a fleshed-out implementation of this idea (:def fiona (:oneof@@ -13,19 +13,35 @@ (| "What does she think of me?") (| "You raped me in the same bed your daughter was born in.") (| "I want to suffer for my sins")+ (| "I'm full as a tick")+ (| "I wanna make a mistake")+ (| "Scratch me out, free yourself.")+ (| "Run, free yourself of me.")+ (|+ '''+ Oh darling, it's so sweet+ You think you know how crazy, how crazy I am.+ ''') (| "I need to be redeemed to the one I've sinned against") (| '''+ He said "It's all in your head,"+ And I said "so's everything" but he didn't get it.+ ''')+ (|+ ''' My feel for you, boy Is decaying in front of me Like the carrion of a murdered prey ''')+ (| "I don't feel anything until I smash it up")+ (| "I may need a chaperone") (| ''' All that love must've been lacking something If I got bored trying to figure you out ''')- (| + (| ''' So I will keep a deliberate pace Let the damned breeze dry my face@@ -36,7 +52,7 @@ If I let you get too close ''') (| "Hunger hurts but starving works.")- (| + (| ''' What's so impressive about a diamond Except the mining
examples/fortune.dck view
@@ -24,18 +24,23 @@ (| "Guilt redeems, not love.") (| "There is no such thing as metaphors.") (| "Excess is a sin.")+ (| "Hunger is hope.") (| "Spurn your family.") (| "Salvation is finality.") (| "Knowledge begets humility.") (| "Love animals.")- ; judgment+ (| "Today is a good day to practice bilocation.")+ (| "Drugs have no mystic content.") (| "Irony is the weakest brand of pessimism") (| "Sex wastes the male body.")+ (| "Did you remember to put apotheosis on your to-do list?") (| "Cultivate weakness.") (| "Beauty is a moral imperative.")- (| "We are all damned by our own personalities. That is beauty.")+ (| "We are all united in being damned by our own personalities. That is beauty.")+ (| "What do you know about dietetics?") (| "Hobbies are sublunary") (| "To err is immoral.")+ (| "Bats can give humans rabies.") (| $ quote ("« Le beau est ce qu'on désire sans vouloir le manger. »", "Simone Weil")) (| $ quote ("\"You're more likely to get cut with a dull tool than a sharp one.\"", "Fiona Apple")) (| $ quote ("\"You forgot the difference between equanimity and passivity.\"", "Fiona Apple"))
language-dickinson.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.0 name: language-dickinson-version: 0.1.1.1+version: 0.1.1.2 license: BSD3 license-file: LICENSE copyright: Copyright: (c) 2020 Vanessa McHale@@ -85,6 +85,7 @@ Language.Dickinson.DuplicateCheck Language.Dickinson.Unique Language.Dickinson.File+ Language.Dickinson.Pipeline Language.Dickinson.Import Language.Dickinson.Lib Language.Dickinson.Check.Internal@@ -153,6 +154,7 @@ REPL REPL.Save REPL.Completions+ Format Paths_language_dickinson autogen-modules: Paths_language_dickinson@@ -247,7 +249,8 @@ dickinson -any, binary -any, criterion -any,- bytestring -any+ bytestring -any,+ text -any if impl(ghc >=8.0) ghc-options:
lib/adjectives.dck view
@@ -2,4 +2,10 @@ (:def adjective (:oneof+ (| "sententious")+ (| "poetic")+ (| "plain")+ (| "bromide")+ (| "banal")+ (| "pithy") (| "stentorian")))
lib/noun.dck view
@@ -3,5 +3,10 @@ (:def noun (:oneof (| "valetudinarian")+ (| "heliophagy") (| "valedictorian")+ (| "apothegm")+ (| "apotheosis")+ (| "aphelion")+ (| "perihelion") (| "folderol")))
+ lib/profession.dck view
@@ -0,0 +1,24 @@+%-++(:def profession+ (:oneof+ (| "professor")+ (| "psychiatrist")+ (| "physician")+ (| "poet")+ (| "psychologist")+ (| "banker")+ (| "sociologist")+ (| "scientist")+ (| "biologist")+ (| "ecologist")+ (| "mathematician")+ (| "statistician")+ (| "epidemiologist")+ (| "sanitation worker")+ (| "teacher")+ (| "police officer")+ (| "lawyer")+ (| "engineer")+ (| "writer")+ (| "artist")))
man/emd.1 view
@@ -10,6 +10,8 @@ \f[B]Dickinson\f[R] is a text-generation language .SH SYNOPSIS .PP+emd fortune.dck+.PP emd repl .PP emd run literature.dck@@ -17,6 +19,17 @@ emd run project.dck --include lib .PP man $(emd man)+.SS SHEBANG+.PP+Dickinson ignores lines starting with \f[C]#!\f[R] so we can put+.IP+.nf+\f[C]+#!/usr/bin/env emd+\f[R]+.fi+.PP+at the top of a file and \f[C]emd\f[R] will be used as an interpreter. .SH SUBCOMMANDS .PP \f[B]repl\f[R] - Start a repl
+ run/Format.hs view
@@ -0,0 +1,15 @@+module Format ( fmtFile+ , fmtInplace+ ) where++import Control.Monad ((<=<))+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as BSL+import Data.Text.IO as TIO+import Language.Dickinson.Pipeline++fmtFile :: FilePath -> IO ()+fmtFile = TIO.putStrLn . format <=< BSL.readFile++fmtInplace :: FilePath -> IO ()+fmtInplace fp = TIO.writeFile fp . format . BSL.fromStrict =<< BS.readFile fp
run/Main.hs view
@@ -1,7 +1,9 @@ module Main (main) where +import Data.Foldable (traverse_) import Data.Semigroup import qualified Data.Text.IO as TIO+import Format import Language.Dickinson (dickinsonVersionString) import Language.Dickinson.File import Language.Dickinson.Lib@@ -13,9 +15,9 @@ -- TODO debug/verbosity options... data Act = Run !FilePath ![FilePath] | REPL ![FilePath]- | Check !FilePath ![FilePath]- | Lint !FilePath- | Format !FilePath+ | Check ![FilePath] ![FilePath]+ | Lint ![FilePath]+ | Format !FilePath Bool | Man main :: IO ()@@ -32,7 +34,9 @@ ) <|> runP formatP :: Parser Act-formatP = Format <$> dckFile+formatP = Format+ <$> dckFile+ <*> switch (long "inplace" <> short 'i' <> help "Overwrite file in-place") replP :: Parser Act replP = REPL <$> many dckFile@@ -41,10 +45,10 @@ runP = Run <$> dckFile <*> includes checkP :: Parser Act-checkP = Check <$> dckFile <*> includes+checkP = Check <$> some dckFile <*> includes lintP :: Parser Act-lintP = Lint <$> dckFile+lintP = Lint <$> some dckFile dckFile :: Parser FilePath dckFile = argument str@@ -75,9 +79,10 @@ versionMod = infoOption dickinsonVersionString (short 'V' <> long "version" <> help "Show version") run :: Act -> IO ()-run (Run fp is) = do { pGo <- defaultLibPath ; TIO.putStrLn =<< pipeline (pGo is) fp }-run (REPL _) = dickinsonRepl-run (Check f i) = do { pathMod <- defaultLibPath ; validateFile (pathMod i) f } -- FIXME: reuse-run (Lint f) = warnFile f-run (Format fp) = fmtFile fp-run Man = putStrLn =<< (</> "emd.1") . (</> "man") <$> getDataDir+run (Run fp is) = do { pGo <- defaultLibPath ; TIO.putStrLn =<< pipeline (pGo is) fp }+run (REPL _) = dickinsonRepl+run (Check fs i) = do { pathMod <- defaultLibPath ; traverse_ (validateFile (pathMod i)) fs } -- FIXME: reuse+run (Lint fs) = traverse_ warnFile fs+run (Format fp False) = fmtFile fp+run (Format fp True) = fmtInplace fp+run Man = putStrLn . (</> "emd.1") . (</> "man") =<< getDataDir
run/REPL.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TupleSections #-} module REPL ( dickinsonRepl ) where@@ -118,7 +117,7 @@ listNames = liftIO . traverse_ TIO.putStrLn =<< names names :: Repl AlexPosn [T.Text]-names = lift $ namesState+names = lift namesState bindDisplay :: T.Text -> Repl AlexPosn () bindDisplay t = do
run/REPL/Completions.hs view
@@ -14,7 +14,7 @@ namesState = gets (M.keys . topLevel) namesStr :: StateT (EvalSt a) IO [String]-namesStr = fmap T.unpack <$> gets (M.keys . topLevel)+namesStr = gets (fmap T.unpack . M.keys . topLevel) cyclicSimple :: [String] -> [Completion] cyclicSimple [] = []
src/Language/Dickinson/Check/Internal.hs view
@@ -1,5 +1,6 @@ module Language.Dickinson.Check.Internal ( sanityCheck , sanityCheckLexer+ , maxUniqueDeclaration ) where import Control.Monad (when)@@ -28,6 +29,8 @@ when (storedMax < computedMax) $ error "Sanity check failed!" +-- TODO: see http://hackage.haskell.org/package/uniplate-1.6.12/docs/Data-Generics-Uniplate-Operations.html+-- TODO: recursion schemes? would need benchmark... maxUniqueDeclaration :: Declaration a -> Int maxUniqueDeclaration (Define _ (Name _ (Unique i) _) e) = max i (maxUniqueExpression e) maxUniqueDeclaration (TyDecl _ (Name _ (Unique i) _) tns) =
src/Language/Dickinson/Eval.hs view
@@ -49,7 +49,7 @@ -- Used in the REPL, for instance , lexerState :: AlexUserState -- For error messages- , tyEnv :: (TyEnv a)+ , tyEnv :: TyEnv a } @@ -250,6 +250,7 @@ mapChoice f (MultiInterp l es) = MultiInterp l (mapChoice f <$> es) mapChoice f (Concat l es) = Concat l (mapChoice f <$> es) mapChoice f (Annot l e ty) = Annot l (mapChoice f e) ty+mapChoice _ _ = error "Internal error in function mapChoice." setFrequency :: NonEmpty (Double, Expression a) -> NonEmpty (Double, Expression a) setFrequency = fmap (\(_, e) -> (fromIntegral $ {-# SCC "countNodes" #-} countNodes e, e))@@ -262,6 +263,7 @@ countNodes (MultiInterp _ es) = product (fmap countNodes es) countNodes (Concat _ es) = product (fmap countNodes es) countNodes (Annot _ e _) = countNodes e+countNodes _ = error "Internal error in function countNodes" concatOrFail :: (MonadState (EvalSt a) m, MonadError (DickinsonError a) m) => (T.Text -> T.Text) -> a -> [Expression a] -> m (Expression a) concatOrFail process l = fmap (Literal l . process . mconcat) . traverse evalExpressionAsTextM@@ -279,7 +281,7 @@ resolveFlattenM e@Literal{} = pure e resolveFlattenM e@StrChunk{} = pure e resolveFlattenM e@Constructor{} = pure e-resolveFlattenM (Var _ n) = lookupName n+resolveFlattenM (Var _ n) = resolveFlattenM =<< lookupName n resolveFlattenM (Choice l pes) = do let ps = fst <$> pes es <- traverse resolveFlattenM (snd <$> pes)@@ -300,9 +302,10 @@ resolveFlattenM e''' _ -> error "Ill-typed expression" resolveFlattenM e@Lambda{} = pure e-resolveFlattenM (Match _ e p e') =- (bindPattern p =<< resolveFlattenM e) *>- resolveFlattenM e'+resolveFlattenM (Match _ e p e') = do+ modSt <- bindPattern p =<< resolveFlattenM e+ withSt modSt $+ resolveFlattenM e' resolveFlattenM (Flatten l e) = Flatten l <$> resolveFlattenM e resolveFlattenM (Annot _ e _) = resolveFlattenM e
src/Language/Dickinson/File.hs view
@@ -8,35 +8,33 @@ , tcFile , amalgamateRename , amalgamateRenameM- , fmtFile , pipeline , resolveFile ) where -import Control.Applicative ((<|>))-import Control.Exception (Exception)+import Control.Applicative ((<|>))+import Control.Exception (Exception) import Control.Exception.Value-import Control.Monad ((<=<))-import Control.Monad.Except (ExceptT, MonadError, runExceptT)-import Control.Monad.IO.Class (MonadIO)-import Control.Monad.State (MonadState, StateT, evalStateT)-import qualified Data.ByteString.Lazy as BSL-import Data.Semigroup ((<>))-import Data.Text as T-import Data.Text.Prettyprint.Doc (hardline, pretty)-import Data.Text.Prettyprint.Doc.Render.Text (putDoc)+import Control.Monad ((<=<))+import Control.Monad.Except (ExceptT, MonadError, runExceptT)+import Control.Monad.IO.Class (MonadIO)+import Control.Monad.State (MonadState, StateT, evalStateT)+import qualified Data.ByteString.Lazy as BSL+import Data.Semigroup ((<>))+import Data.Text as T import Language.Dickinson.Check import Language.Dickinson.DuplicateCheck import Language.Dickinson.Error import Language.Dickinson.Eval import Language.Dickinson.Lexer import Language.Dickinson.Parser+import Language.Dickinson.Pipeline import Language.Dickinson.Rename import Language.Dickinson.Rename.Amalgamate import Language.Dickinson.ScopeCheck import Language.Dickinson.Type import Language.Dickinson.TypeCheck-import System.Random (StdGen, newStdGen, randoms)+import System.Random (StdGen, newStdGen, randoms) data AmalgamateSt = AmalgamateSt { amalgamateRenames :: Renames , amalgamateLexerState :: AlexUserState@@ -72,10 +70,6 @@ -> IO [Declaration AlexPosn] amalgamateRename is fp = flip evalStateT initAmalgamateSt $ fmap eitherThrow $ runExceptT $ amalgamateRenameM is fp --- TODO: smart formatter-fmtFile :: FilePath -> IO ()-fmtFile = putDoc . (<> hardline) . pretty . eitherThrow . parse <=< BSL.readFile- -- | Check scoping checkFile :: [FilePath] -> FilePath -> IO () checkFile = ioChecker checkScope@@ -106,8 +100,5 @@ resolveFile is = fmap eitherThrow . evalIO . (traverse resolveDeclarationM <=< amalgamateRenameM is) pipeline :: [FilePath] -> FilePath -> IO T.Text-pipeline is fp = fmap eitherThrow $ evalIO $ do- ds <- amalgamateRenameM is fp- maybeThrow $ checkScope ds- tyTraverse ds- evalDickinsonAsMain ds+pipeline is fp = fmap eitherThrow $ evalIO $+ checkEvalM =<< amalgamateRenameM is fp
src/Language/Dickinson/Lexer.x view
@@ -72,6 +72,7 @@ tokens :- + <0> "#!".* ; -- ignore shebangs <0> { $white+ ;@@ -154,7 +155,7 @@ mod_ust (\(x,push,y,z) -> (x,st:push,y,z)) exitInterp :: Alex ()-exitInterp = do +exitInterp = do (_,iSt:_,_,_) <- get_ust case iSt of InStr -> set_scd string
+ src/Language/Dickinson/Pipeline.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE FlexibleContexts #-}++module Language.Dickinson.Pipeline ( checkEvalM+ , format+ ) where++import Control.Exception.Value (eitherThrow)+import Control.Monad.Except (MonadError)+import Control.Monad.State.Lazy (MonadState)+import qualified Data.ByteString.Lazy as BSL+import qualified Data.Text as T+import Data.Text.Prettyprint.Doc.Ext (prettyText)+import Language.Dickinson.Error+import Language.Dickinson.Eval+import Language.Dickinson.Parser+import Language.Dickinson.ScopeCheck+import Language.Dickinson.Type+import Language.Dickinson.TypeCheck++checkEvalM :: (MonadState (EvalSt a) m, MonadError (DickinsonError a) m) => [Declaration a] -> m T.Text+checkEvalM ds = do+ maybeThrow $ checkScope ds+ tyTraverse ds+ evalDickinsonAsMain ds++format :: BSL.ByteString -> T.Text+format = prettyText . eitherThrow . parse
src/Language/Dickinson/Type.hs view
@@ -14,7 +14,7 @@ import Control.DeepSeq (NFData) import Data.Binary (Binary) import Data.Foldable (toList)-import Data.List.NonEmpty (NonEmpty)+import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.List.NonEmpty as NE import Data.Semigroup ((<>)) import qualified Data.Text as T@@ -117,6 +117,9 @@ prettyChoiceBranch :: (Double, Expression a) -> Doc b prettyChoiceBranch (d, e) = parens (pipe <+> pretty d <+> pretty e) +prettyChoiceOneof :: Expression a -> Doc b+prettyChoiceOneof e = parens (pipe <+> pretty e)+ prettyInterp :: Expression a -> Doc b prettyInterp (StrChunk _ t) = pretty (escReplace t) prettyInterp e = "${" <> pretty e <> "}"@@ -141,14 +144,18 @@ . T.replace "\n" "\\n" . T.replace "${" "\\${" +allEq :: Eq a => NonEmpty a -> Bool+allEq (x :| xs) = all (== x) xs+ -- figure out indentation instance Pretty (Expression a) where pretty (Var _ n) = pretty n pretty (Literal _ l) = dquotes $ pretty (escReplace l) pretty (Let _ ls e) = group (parens (":let" <^> vsep (toList (fmap prettyLetLeaf ls) ++ [pretty e])))- -- TODO: if they're all equal, use :oneof -- also comments lol- pretty (Choice _ brs) = parens (":branch" <#> indent 2 (hardSep (toList $ fmap prettyChoiceBranch brs)))+ pretty (Choice _ brs)+ | allEq (fst <$> brs) = parens (":oneof" <#> indent 2 (hardSep (toList $ fmap prettyChoiceOneof (snd <$> brs))))+ | otherwise = parens (":branch" <#> indent 2 (hardSep (toList $ fmap prettyChoiceBranch brs))) pretty (Lambda _ n ty e) = parens (":lambda" <+> pretty n <+> pretty ty <#*> pretty e) pretty (Apply _ e e') = parens ("$" <+> pretty e <+> pretty e') pretty (Interp _ es) = group (dquotes (foldMap prettyInterp es))
test/Eval.hs view
@@ -3,6 +3,7 @@ module Eval ( evalTests ) where +import Control.Monad ((<=<)) import qualified Data.Text as T import Language.Dickinson.File import Test.Tasty (TestTree, testGroup)@@ -22,6 +23,7 @@ , resolveCase "test/data/hangIndefinitely.dck" , testCase "Should handle interpolated multiline strings" multiQuoteEval , testCase "Should handle nested interpolations" multiInterpolatedNestedEval+ , testCase "test/data/flattenLambda.dck" example ] forceResult :: a -> Assertion@@ -34,14 +36,13 @@ resolveCase fp = testCase fp $ resolve fp resolve :: FilePath -> Assertion-resolve fp = do- res <- resolveFile ["prelude", "lib"] fp- forceResult res+resolve = forceResult <=< resolveFile ["prelude", "lib"] result :: FilePath -> Assertion-result fp = do- res <- evalFile ["prelude", "lib"] fp- forceResult res+result = forceResult <=< evalFile ["prelude", "lib"]++example :: Assertion+example = forceResult =<< evalFile ["examples"] "test/data/flattenLambda.dck" evalTo :: FilePath -> T.Text -> Assertion evalTo fp t = do
+ test/data/flattenLambda.dck view
@@ -0,0 +1,5 @@+(:include fortune)++%-++(:def main (:flatten fortune))
test/data/lexDollarSign.pretty view
@@ -1,11 +1,11 @@ %- (:def main- (:branch- (| 0.14285714285714285 "$")- (| 0.14285714285714285 "$a")- (| 0.14285714285714285 "$$")- (| 0.14285714285714285 "$${a}")- (| 0.14285714285714285 "$\${a}")- (| 0.14285714285714285 "$a${a}")- (| 0.14285714285714285 "${a}$")))+ (:oneof+ (| "$")+ (| "$a")+ (| "$$")+ (| "$${a}")+ (| "$\${a}")+ (| "$a${a}")+ (| "${a}$")))
test/data/multiQuoteify.pretty view
@@ -9,5 +9,5 @@ '''))) (:def main- (:branch- (| 1.0 ($ ($ quote "God created war so that Americans would learn geography.") "Mark Twain"))))+ (:oneof+ (| ($ ($ quote "God created war so that Americans would learn geography.") "Mark Twain"))))
test/data/nestLet.pretty view
@@ -5,6 +5,6 @@ [a (:let [a "man"] a)] [b (:let [a "woman"] a)] [c (:let [a "non-binary"] a)]- (:branch- (| 1.0 (:let [b a] b))- (| 1.0 b))))+ (:oneof+ (| (:let [b a] b))+ (| b))))