Support a more complete (and simple) requirements gathering mechanism,

and add support for binary operations.

This version of requirements generation simply generates every numeric
size within a provided range, and then will reject trait implementations
that rely on values outside this range. It should be a little more easy
to reason about, and easier to make local changes as I (inevitably) need
to modify rules.
This commit is contained in:
2019-07-22 08:14:40 -07:00
parent ab465296f2
commit aff88eb2f0
8 changed files with 243 additions and 384 deletions

66
generation/src/File.hs Normal file
View File

@@ -0,0 +1,66 @@
module File(
File(..),
Task(..),
addModuleTasks,
makeTask
)
where
import Control.Monad(forM_)
import Data.Char(toUpper)
import qualified Data.Map.Strict as Map
import Gen(Gen,blank,out)
import System.FilePath(takeBaseName,takeDirectory,takeFileName,(</>))
data File = File {
predicate :: Word -> [Word] -> Bool,
outputName :: FilePath,
generator :: Word -> Gen ()
}
data Task = Task {
outputFile :: FilePath,
fileGenerator :: Gen ()
}
makeTask :: FilePath ->
Word -> [Word] ->
File ->
Maybe Task
makeTask base size allSizes file
| predicate file size allSizes =
Just Task {
outputFile = base </> ("u" ++ show size) </> outputName file <> ".rs",
fileGenerator = generator file size
}
| otherwise =
Nothing
addModuleTasks :: FilePath -> [Task] -> [Task]
addModuleTasks base baseTasks = unsignedTask : (baseTasks ++ moduleTasks)
where
moduleMap = foldr addModuleInfo Map.empty baseTasks
addModuleInfo task =
Map.insertWith (++) (takeDirectory (outputFile task))
[takeBaseName (outputFile task)]
moduleTasks = Map.foldrWithKey generateModuleTask [] moduleMap
generateModuleTask directory mods acc = acc ++ [Task {
outputFile = directory </> "mod.rs",
fileGenerator =
do forM_ mods $ \ modle -> out ("mod " ++ modle ++ ";")
blank
out ("pub use base::" ++ upcase (takeFileName directory) ++ ";")
}]
unsignedTask = Task {
outputFile = base </> "unsigned" </> "mod.rs",
fileGenerator =
do forM_ (Map.keys moduleMap) $ \ key ->
out ("mod " ++ takeFileName key ++ ";")
blank
forM_ (Map.keys moduleMap) $ \ key ->
out ("pub use " ++ takeFileName key ++ "::" ++
upcase (takeFileName key) ++ ";")
}
upcase :: String -> String
upcase = map toUpper