diff --git a/CHANGELOG.md b/CHANGELOG.md index 91f53b6..2e80640 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ and this project adheres to the ## Unreleased +- command line interface get improved (with `--help` and subcommand) +- check imports existed, e.g. `use {a, b, c} from m` will ensure `m` does have type definition `a`, `b`, and `c` + ## 0.1.0.0 - wasm interface types supporting diff --git a/app/Main.hs b/app/Main.hs index 50c990a..9015d76 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -8,59 +8,101 @@ cli design -} module Main (main) where +import Control.Monad import Data.Functor import Data.List (isSuffixOf) +import Options.Applicative import Prettyprinter import Prettyprinter.Render.Terminal import System.Directory -import System.Environment import Wit -handle :: [String] -> IO () -handle ["version"] = putStrLn "0.2.0" -handle ["check", file] = checkFileWithDoneHint file -handle ["check"] = do +main :: IO () +main = do + join $ + execParser + ( info + (helper <*> versionOption <*> programOptions) + ( fullDesc + <> progDesc "compiler for wit" + <> header + "witc - compiler for wit, a language for describing wasm interface types" + ) + ) + where + versionOption :: Parser (a -> a) + versionOption = infoOption "0.2.0" (long "version" <> help "Show version") + programOptions :: Parser (IO ()) + programOptions = + subparser + ( command + "check" + ( info + (check <$> optional (strArgument (metavar "FILE" <> help "Name of the thing to create"))) + (progDesc "Validate wit file") + ) + <> command + "instance" + ( info + ( subparser + ( command + "import" + ( info + ( codegen Import Instance + <$> strArgument (metavar "FILE" <> help "Wit file") + <*> strArgument (value "wasmedge" <> help "Name of import") + ) + (progDesc "Generate import code for instance (wasm)") + ) + <> command + "export" + ( info + ((\f -> codegen Export Instance f "wasmedge") <$> strArgument (metavar "FILE" <> help "Wit file")) + (progDesc "Generate export code for instance (wasm)") + ) + ) + ) + (progDesc "Generate code for instance (wasm)") + ) + <> command + "runtime" + ( info + ( subparser + ( command + "import" + ( info + ( codegen Import Runtime + <$> strArgument (metavar "FILE" <> help "Wit file") + <*> strArgument (value "wasmedge" <> help "Name of import") + ) + (progDesc "Generate import code for runtime (WasmEdge)") + ) + <> command + "export" + ( info + ((\f -> codegen Export Runtime f "wasmedge") <$> strArgument (metavar "FILE" <> help "Wit file")) + (progDesc "Generate export code for runtime (WasmEdge)") + ) + ) + ) + (progDesc "Generate code for runtime (WasmEdge)") + ) + ) + +check :: Maybe FilePath -> IO () +check (Just file) = checkFileWithDoneHint file +check Nothing = do dir <- getCurrentDirectory witFileList <- filter (".wit" `isSuffixOf`) <$> listDirectory dir mapM_ checkFileWithDoneHint witFileList -handle ["instance", "import", file, importName] = - parseFile file - >>= eitherIO check0 - >>= eitherIO (putDoc . prettyFile Config {language = Rust, direction = Import, side = Instance} importName) -handle ["runtime", "import", file, importName] = - parseFile file - >>= eitherIO check0 - >>= eitherIO (putDoc . prettyFile Config {language = Rust, direction = Import, side = Runtime} importName) -handle ["instance", mode, file] = do - case mode of - "import" -> - parseFile file - >>= eitherIO check0 - >>= eitherIO (putDoc . prettyFile Config {language = Rust, direction = Import, side = Instance} "wasmedge") - "export" -> - parseFile file - >>= eitherIO check0 - >>= eitherIO (putDoc . prettyFile Config {language = Rust, direction = Export, side = Instance} "wasmedge") - bad -> putStrLn $ "unknown option: " ++ bad -handle ["runtime", mode, file] = - case mode of - "import" -> - parseFile file - >>= eitherIO check0 - >>= eitherIO (putDoc . prettyFile Config {language = Rust, direction = Import, side = Runtime} "wasmedge") - "export" -> - parseFile file - >>= eitherIO check0 - >>= eitherIO (putDoc . prettyFile Config {language = Rust, direction = Export, side = Runtime} "wasmedge") - bad -> putStrLn $ "unknown option: " ++ bad -handle _ = putStrLn "bad usage" checkFileWithDoneHint :: FilePath -> IO () checkFileWithDoneHint file = do checkFile file $> () putDoc $ pretty file <+> annotate (color Green) (pretty "OK") <+> line -main :: IO () -main = do - args <- getArgs - handle args +codegen :: Direction -> Side -> FilePath -> String -> IO () +codegen d s file importName = + parseFile file + >>= eitherIO check0 + >>= eitherIO (putDoc . prettyFile Config {language = Rust, direction = d, side = s} importName) diff --git a/bindings/rust/invoke-witc/src/lib.rs b/bindings/rust/invoke-witc/src/lib.rs index 6ca11db..7988581 100644 --- a/bindings/rust/invoke-witc/src/lib.rs +++ b/bindings/rust/invoke-witc/src/lib.rs @@ -19,7 +19,10 @@ fn name_value_meta(meta: &Meta) -> (String, String) { } fn check_version() { - let ver_output = Command::new("witc-exe").args(["version"]).output().unwrap(); + let ver_output = Command::new("witc-exe") + .args(["--version"]) + .output() + .unwrap(); let ver = String::from_utf8(ver_output.stdout).unwrap(); if ver != "0.2.0\n" { panic!("witc-exe version mismatch: expected 0.2.0, got {}", ver); diff --git a/package.yaml b/package.yaml index ae751af..0957499 100644 --- a/package.yaml +++ b/package.yaml @@ -32,6 +32,7 @@ dependencies: - prettyprinter - prettyprinter-ansi-terminal - template-haskell + - optparse-applicative ghc-options: - -Wall diff --git a/witc.cabal b/witc.cabal index d8a7823..64ffcb7 100644 --- a/witc.cabal +++ b/witc.cabal @@ -53,6 +53,7 @@ library , directory , megaparsec , mtl + , optparse-applicative , prettyprinter , prettyprinter-ansi-terminal , primitive @@ -79,6 +80,7 @@ executable witc-exe , directory , megaparsec , mtl + , optparse-applicative , prettyprinter , prettyprinter-ansi-terminal , primitive @@ -111,6 +113,7 @@ test-suite witc-test , hspec-megaparsec , megaparsec , mtl + , optparse-applicative , prettyprinter , prettyprinter-ansi-terminal , primitive