mirror of https://github.com/voidlizard/hbs2
wip
This commit is contained in:
parent
b3f51e5259
commit
92bb0ba911
|
@ -2,7 +2,10 @@
|
||||||
{-# Language UndecidableInstances #-}
|
{-# Language UndecidableInstances #-}
|
||||||
module Main where
|
module Main where
|
||||||
|
|
||||||
import HBS2.Prelude.Plated
|
import HBS2.CLI.Prelude
|
||||||
|
import HBS2.CLI.Run
|
||||||
|
import HBS2.CLI.Run.KeyMan
|
||||||
|
|
||||||
import HBS2.OrDie
|
import HBS2.OrDie
|
||||||
|
|
||||||
import HBS2.Data.Types.Refs
|
import HBS2.Data.Types.Refs
|
||||||
|
@ -19,13 +22,9 @@ import HBS2.Peer.RPC.API.Storage
|
||||||
import HBS2.Peer.RPC.Client.StorageClient
|
import HBS2.Peer.RPC.Client.StorageClient
|
||||||
|
|
||||||
import HBS2.Peer.Proto hiding (request)
|
import HBS2.Peer.Proto hiding (request)
|
||||||
import HBS2.Peer.Proto.RefLog
|
|
||||||
import HBS2.Base58
|
import HBS2.Base58
|
||||||
import HBS2.Net.Auth.Credentials
|
import HBS2.Net.Auth.Credentials
|
||||||
import HBS2.Net.Auth.Schema()
|
import HBS2.Net.Auth.Schema()
|
||||||
import HBS2.Net.Auth.Credentials
|
|
||||||
import HBS2.Net.Auth.Credentials.Sigil
|
|
||||||
import HBS2.Data.Types.SignedBox
|
|
||||||
|
|
||||||
|
|
||||||
import HBS2.KeyMan.Keys.Direct
|
import HBS2.KeyMan.Keys.Direct
|
||||||
|
@ -63,187 +62,6 @@ import Prettyprinter
|
||||||
|
|
||||||
type RefLogId = PubKey 'Sign 'HBS2Basic
|
type RefLogId = PubKey 'Sign 'HBS2Basic
|
||||||
|
|
||||||
pattern StringLike :: forall {c} . String -> Syntax c
|
|
||||||
pattern StringLike e <- (stringLike -> Just e)
|
|
||||||
|
|
||||||
pattern StringLikeList :: forall {c} . [String] -> [Syntax c]
|
|
||||||
pattern StringLikeList e <- (stringLikeList -> e)
|
|
||||||
|
|
||||||
class OptionalVal c b where
|
|
||||||
optional :: b -> Syntax c -> b
|
|
||||||
|
|
||||||
instance IsContext c => OptionalVal c Int where
|
|
||||||
optional d = \case
|
|
||||||
LitIntVal x -> fromIntegral x
|
|
||||||
_ -> d
|
|
||||||
|
|
||||||
stringLike :: Syntax c -> Maybe String
|
|
||||||
stringLike = \case
|
|
||||||
LitStrVal s -> Just $ Text.unpack s
|
|
||||||
SymbolVal (Id s) -> Just $ Text.unpack s
|
|
||||||
_ -> Nothing
|
|
||||||
|
|
||||||
stringLikeList :: [Syntax c] -> [String]
|
|
||||||
stringLikeList syn = [ stringLike s | s <- syn ] & takeWhile isJust & catMaybes
|
|
||||||
|
|
||||||
data BindAction c ( m :: Type -> Type) =
|
|
||||||
BindLambda { fromLambda :: [Syntax c] -> RunM c m (Syntax c) }
|
|
||||||
| BindValue (Syntax c)
|
|
||||||
|
|
||||||
data Bind c ( m :: Type -> Type) = Bind
|
|
||||||
{ bindAction :: BindAction c m
|
|
||||||
, bindName :: Id
|
|
||||||
, bindDescShort :: Text
|
|
||||||
} deriving (Generic)
|
|
||||||
|
|
||||||
deriving newtype instance Hashable Id
|
|
||||||
|
|
||||||
newtype NameNotBoundException = NameNotBound Id
|
|
||||||
deriving stock Show
|
|
||||||
deriving newtype (Generic,Typeable)
|
|
||||||
|
|
||||||
|
|
||||||
newtype NotLambda = NotLambda Id
|
|
||||||
deriving stock Show
|
|
||||||
deriving newtype (Generic,Typeable)
|
|
||||||
|
|
||||||
instance Exception NotLambda
|
|
||||||
|
|
||||||
data BadFormException c = BadFormException (Syntax c)
|
|
||||||
|
|
||||||
newtype TypeCheckError c = TypeCheckError (Syntax c)
|
|
||||||
|
|
||||||
instance Exception (TypeCheckError C)
|
|
||||||
|
|
||||||
newtype BadValueException = BadValueException String
|
|
||||||
deriving stock Show
|
|
||||||
deriving newtype (Generic,Typeable)
|
|
||||||
|
|
||||||
instance Exception NameNotBoundException
|
|
||||||
|
|
||||||
instance IsContext c => Show (BadFormException c) where
|
|
||||||
show (BadFormException sy) = show $ "BadFormException" <+> pretty sy
|
|
||||||
|
|
||||||
instance IsContext c => Show (TypeCheckError c) where
|
|
||||||
show (TypeCheckError sy) = show $ "TypeCheckError" <+> pretty sy
|
|
||||||
|
|
||||||
instance Exception (BadFormException C)
|
|
||||||
|
|
||||||
instance Exception BadValueException
|
|
||||||
|
|
||||||
newtype Dict c m = Dict { fromDict :: HashMap Id (Bind c m) }
|
|
||||||
deriving newtype (Semigroup, Monoid)
|
|
||||||
|
|
||||||
newtype RunM c m a = RunM { fromRunM :: ReaderT (TVar (Dict c m)) m a }
|
|
||||||
deriving newtype ( Applicative
|
|
||||||
, Functor
|
|
||||||
, Monad
|
|
||||||
, MonadIO
|
|
||||||
, MonadUnliftIO
|
|
||||||
, MonadReader (TVar (Dict c m))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
splitForms :: [String] -> [[String]]
|
|
||||||
splitForms s0 = runIdentity $ S.toList_ (go mempty s0)
|
|
||||||
where
|
|
||||||
go acc ( "then" : rest ) = emit acc >> go mempty rest
|
|
||||||
go acc ( "and" : rest ) = emit acc >> go mempty rest
|
|
||||||
go acc ( x : rest ) | isPrefixOf "-" x = go ( x : acc ) rest
|
|
||||||
go acc ( x : rest ) | isPrefixOf "--" x = go ( x : acc ) rest
|
|
||||||
go acc ( x : rest ) = go ( x : acc ) rest
|
|
||||||
go acc [] = emit acc
|
|
||||||
|
|
||||||
emit = S.yield . reverse
|
|
||||||
|
|
||||||
apply :: forall c m . ( IsContext c
|
|
||||||
, MonadUnliftIO m
|
|
||||||
, Exception (BadFormException c)
|
|
||||||
)
|
|
||||||
=> Id
|
|
||||||
-> [Syntax c]
|
|
||||||
-> RunM c m (Syntax c)
|
|
||||||
apply name args' = do
|
|
||||||
-- notice $ red "APPLY" <+> pretty name
|
|
||||||
what <- ask >>= readTVarIO <&> HM.lookup name . fromDict
|
|
||||||
case bindAction <$> what of
|
|
||||||
Just (BindLambda e) -> mapM runExpr args' >>= e
|
|
||||||
Just (BindValue v) -> throwIO (NotLambda name)
|
|
||||||
Nothing -> throwIO (NameNotBound name)
|
|
||||||
|
|
||||||
|
|
||||||
runExpr :: forall c m . ( IsContext c
|
|
||||||
, MonadUnliftIO m
|
|
||||||
, Exception (BadFormException c)
|
|
||||||
) => Syntax c -> RunM c m (Syntax c)
|
|
||||||
runExpr syn = handle (handleForm syn) $ case syn of
|
|
||||||
|
|
||||||
ListVal [ w, SymbolVal ".", b] -> do
|
|
||||||
pure $ mkList [w, b]
|
|
||||||
|
|
||||||
ListVal [ SymbolVal "quot", ListVal b] -> do
|
|
||||||
pure $ mkList b
|
|
||||||
|
|
||||||
ListVal [SymbolVal "lambda", arglist, body] -> do
|
|
||||||
pure $ mkForm @c "lambda" [ arglist, body ]
|
|
||||||
|
|
||||||
ListVal (ListVal [SymbolVal "lambda", ListVal decl, body] : args) -> do
|
|
||||||
error "oopsie"
|
|
||||||
-- d <- ask
|
|
||||||
-- void $ liftIO do
|
|
||||||
-- dd <- readTVarIO d
|
|
||||||
-- undefined
|
|
||||||
-- runReaderT $ runExpr body
|
|
||||||
-- error "FUCK!"
|
|
||||||
-- -- liftIO (run d body)
|
|
||||||
pure nil
|
|
||||||
|
|
||||||
ListVal (SymbolVal name : args') -> do
|
|
||||||
apply name args'
|
|
||||||
|
|
||||||
SymbolVal (Id s) | Text.isPrefixOf ":" s -> do
|
|
||||||
pure (mkSym @c (Text.drop 1 s))
|
|
||||||
|
|
||||||
SymbolVal name -> do
|
|
||||||
what <- ask >>= readTVarIO
|
|
||||||
<&> HM.lookup name . fromDict
|
|
||||||
<&> maybe (BindValue (mkSym name)) bindAction
|
|
||||||
|
|
||||||
case what of
|
|
||||||
BindValue e -> pure e
|
|
||||||
BindLambda e -> pure $ mkForm "lambda" [mkSym name, mkSym "..."]
|
|
||||||
|
|
||||||
e -> pure e
|
|
||||||
|
|
||||||
where
|
|
||||||
handleForm syn = \case
|
|
||||||
(BadFormException _ :: BadFormException c) -> do
|
|
||||||
throwIO (BadFormException syn)
|
|
||||||
|
|
||||||
run :: forall c m . ( IsContext c
|
|
||||||
, MonadUnliftIO m
|
|
||||||
, Exception (BadFormException c)
|
|
||||||
) => Dict c m -> [Syntax c] -> m (Syntax c)
|
|
||||||
run d sy = do
|
|
||||||
tvd <- newTVarIO d
|
|
||||||
lastDef nil <$> runReaderT (fromRunM (mapM runExpr sy)) tvd
|
|
||||||
|
|
||||||
bindMatch :: Id -> ([Syntax c] -> RunM c m (Syntax c)) -> Dict c m
|
|
||||||
bindMatch n fn = Dict (HM.singleton n (Bind (BindLambda fn) n ""))
|
|
||||||
|
|
||||||
nil :: forall c . IsContext c => Syntax c
|
|
||||||
nil = List noContext []
|
|
||||||
|
|
||||||
nil_ :: (IsContext c, MonadIO m) => (a -> RunM c m b) -> a -> RunM c m (Syntax c)
|
|
||||||
nil_ m w = m w >> pure (List noContext [])
|
|
||||||
|
|
||||||
bind :: (MonadUnliftIO m, IsContext c) => Id -> Syntax c -> RunM c m (Syntax c)
|
|
||||||
bind name expr = do
|
|
||||||
tv <- ask -- >>= readTVarIO
|
|
||||||
atomically do
|
|
||||||
w@(Dict x) <- readTVar tv
|
|
||||||
writeTVar tv w
|
|
||||||
pure nil
|
|
||||||
|
|
||||||
setupLogger :: MonadIO m => m ()
|
setupLogger :: MonadIO m => m ()
|
||||||
setupLogger = do
|
setupLogger = do
|
||||||
|
@ -264,54 +82,6 @@ silence = do
|
||||||
setLoggingOff @WARN
|
setLoggingOff @WARN
|
||||||
setLoggingOff @NOTICE
|
setLoggingOff @NOTICE
|
||||||
|
|
||||||
class Display a where
|
|
||||||
display :: MonadIO m => a -> m ()
|
|
||||||
|
|
||||||
instance {-# OVERLAPPABLE #-} Pretty w => Display w where
|
|
||||||
display = liftIO . print . pretty
|
|
||||||
|
|
||||||
instance Display (Syntax c) where
|
|
||||||
display = \case
|
|
||||||
LitStrVal s -> liftIO $ TIO.putStr s
|
|
||||||
x -> liftIO $ putStr (show $ pretty x)
|
|
||||||
|
|
||||||
instance Display Text where
|
|
||||||
display = liftIO . TIO.putStr
|
|
||||||
|
|
||||||
instance Display String where
|
|
||||||
display = liftIO . putStr
|
|
||||||
|
|
||||||
display_ :: (MonadIO m, Show a) => a -> m ()
|
|
||||||
display_ = liftIO . print
|
|
||||||
|
|
||||||
{- HLINT ignore "Functor law" -}
|
|
||||||
|
|
||||||
class IsContext c => MkSym c a where
|
|
||||||
mkSym :: a -> Syntax c
|
|
||||||
|
|
||||||
instance IsContext c => MkSym c String where
|
|
||||||
mkSym s = Symbol noContext (Id $ Text.pack s)
|
|
||||||
|
|
||||||
instance IsContext c => MkSym c Text where
|
|
||||||
mkSym s = Symbol noContext (Id s)
|
|
||||||
|
|
||||||
instance IsContext c => MkSym c Id where
|
|
||||||
mkSym = Symbol noContext
|
|
||||||
|
|
||||||
class IsContext c => MkStr c s where
|
|
||||||
mkStr :: s -> Syntax c
|
|
||||||
|
|
||||||
instance IsContext c => MkStr c String where
|
|
||||||
mkStr s = Literal noContext $ LitStr (Text.pack s)
|
|
||||||
|
|
||||||
instance IsContext c => MkStr c Text where
|
|
||||||
mkStr s = Literal noContext $ LitStr s
|
|
||||||
|
|
||||||
mkForm :: forall c . IsContext c => String -> [Syntax c] -> Syntax c
|
|
||||||
mkForm s sy = List noContext ( mkSym s : sy )
|
|
||||||
|
|
||||||
mkList :: forall c. IsContext c => [Syntax c] -> Syntax c
|
|
||||||
mkList = List noContext
|
|
||||||
|
|
||||||
getCredentialsForReflog :: MonadUnliftIO m => String -> m (PeerCredentials 'HBS2Basic)
|
getCredentialsForReflog :: MonadUnliftIO m => String -> m (PeerCredentials 'HBS2Basic)
|
||||||
getCredentialsForReflog reflog = do
|
getCredentialsForReflog reflog = do
|
||||||
|
@ -377,6 +147,8 @@ helpList p = do
|
||||||
|
|
||||||
display_ $ vcat (fmap pretty ks)
|
display_ $ vcat (fmap pretty ks)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
|
||||||
|
@ -385,9 +157,12 @@ main = do
|
||||||
cli <- getArgs <&> unlines . fmap unwords . splitForms
|
cli <- getArgs <&> unlines . fmap unwords . splitForms
|
||||||
>>= either (error.show) pure . parseTop
|
>>= either (error.show) pure . parseTop
|
||||||
|
|
||||||
let dict = execWriter do
|
let dict = makeDict do
|
||||||
|
|
||||||
tell $ bindMatch "help" $ nil_ $ \syn -> do
|
internalEntries
|
||||||
|
keymanEntries
|
||||||
|
|
||||||
|
entry $ bindMatch "help" $ nil_ $ \syn -> do
|
||||||
|
|
||||||
display_ $ "hbs2-cli tool" <> line
|
display_ $ "hbs2-cli tool" <> line
|
||||||
|
|
||||||
|
@ -403,81 +178,15 @@ main = do
|
||||||
_ -> helpList Nothing
|
_ -> helpList Nothing
|
||||||
|
|
||||||
|
|
||||||
tell $ bindMatch "concat" $ \syn -> do
|
entry $ bindMatch "debug:show-cli" $ nil_ \case
|
||||||
|
|
||||||
case syn of
|
|
||||||
[ListVal (StringLikeList xs)] -> do
|
|
||||||
pure $ mkStr @C ( mconcat xs )
|
|
||||||
|
|
||||||
StringLikeList xs -> do
|
|
||||||
pure $ mkStr ( mconcat xs )
|
|
||||||
|
|
||||||
_ -> throwIO (BadFormException @C nil)
|
|
||||||
|
|
||||||
tell $ bindMatch "list" $ \case
|
|
||||||
es -> do
|
|
||||||
pure $ mkList @C es
|
|
||||||
|
|
||||||
tell $ bindMatch "dict" $ \case
|
|
||||||
es -> do
|
|
||||||
pure $ mkForm "dict" es
|
|
||||||
|
|
||||||
tell $ bindMatch "lambda" $ \case
|
|
||||||
[a, b] -> do
|
|
||||||
pure $ mkForm @C "lamba" [ mkSym "_", mkSym "..." ]
|
|
||||||
|
|
||||||
_ -> error "SHIT"
|
|
||||||
|
|
||||||
tell $ bindMatch "map" $ \syn -> do
|
|
||||||
case syn of
|
|
||||||
[ListVal (SymbolVal "lambda" : SymbolVal fn : _), ListVal rs] -> do
|
|
||||||
mapM (apply fn . List.singleton) rs
|
|
||||||
<&> mkList
|
|
||||||
|
|
||||||
w -> do
|
|
||||||
throwIO (BadFormException @C nil)
|
|
||||||
|
|
||||||
tell $ bindMatch "head" $ \case
|
|
||||||
[ ListVal es ] -> pure (head es)
|
|
||||||
_ -> throwIO (TypeCheckError @C nil)
|
|
||||||
|
|
||||||
tell $ bindMatch "tail" $ \case
|
|
||||||
[] -> pure nil
|
|
||||||
[ListVal []] -> pure nil
|
|
||||||
[ListVal es] -> pure $ mkList @C (tail es)
|
|
||||||
_ -> throwIO (BadFormException @C nil)
|
|
||||||
|
|
||||||
tell $ bindMatch "lookup" $ \case
|
|
||||||
[s, ListVal (SymbolVal "dict" : es) ] -> do
|
|
||||||
let val = headDef nil [ v | ListVal [k, v] <- es, k == s ]
|
|
||||||
pure val
|
|
||||||
|
|
||||||
[StringLike s, ListVal [] ] -> do
|
|
||||||
pure nil
|
|
||||||
|
|
||||||
_ -> throwIO (BadFormException @C nil)
|
|
||||||
|
|
||||||
tell $ bindMatch "display" $ nil_ \case
|
|
||||||
[ sy ] -> display sy
|
|
||||||
ss -> display (mkList ss)
|
|
||||||
|
|
||||||
tell $ bindMatch "newline" $ nil_ $ \case
|
|
||||||
[] -> liftIO (putStrLn "")
|
|
||||||
_ -> throwIO (BadFormException @C nil)
|
|
||||||
|
|
||||||
tell $ bindMatch "print" $ nil_ $ \case
|
|
||||||
[ sy ] -> display sy >> liftIO (putStrLn "")
|
|
||||||
ss -> mapM_ display ss >> liftIO (putStrLn "")
|
|
||||||
|
|
||||||
tell $ bindMatch "debug:show-cli" $ nil_ \case
|
|
||||||
_ -> display cli
|
_ -> display cli
|
||||||
|
|
||||||
tell $ bindMatch "hbs2:peer:detect" $ nil_ \case
|
entry $ bindMatch "hbs2:peer:detect" $ nil_ \case
|
||||||
_ -> do
|
_ -> do
|
||||||
so <- detectRPC
|
so <- detectRPC
|
||||||
display so
|
display so
|
||||||
|
|
||||||
tell $ bindMatch "hbs2:peer:poke" $ \case
|
entry $ bindMatch "hbs2:peer:poke" $ \case
|
||||||
_ -> do
|
_ -> do
|
||||||
so <- detectRPC `orDie` "hbs2-peer not found"
|
so <- detectRPC `orDie` "hbs2-peer not found"
|
||||||
r <- newTVarIO nil
|
r <- newTVarIO nil
|
||||||
|
@ -492,7 +201,7 @@ main = do
|
||||||
|
|
||||||
readTVarIO r
|
readTVarIO r
|
||||||
|
|
||||||
tell $ bindMatch "hbs2:keyring:list-encryption" $ \syn -> do
|
entry $ bindMatch "hbs2:keyring:list-encryption" $ \syn -> do
|
||||||
lbs <- case syn of
|
lbs <- case syn of
|
||||||
|
|
||||||
[ ListVal [ SymbolVal "file", StringLike fn ] ] -> do
|
[ ListVal [ SymbolVal "file", StringLike fn ] ] -> do
|
||||||
|
@ -510,7 +219,7 @@ main = do
|
||||||
|
|
||||||
pure $ mkList @C e
|
pure $ mkList @C e
|
||||||
|
|
||||||
tell $ bindMatch "hbs2:keyring:new" $ \syn -> do
|
entry $ bindMatch "hbs2:keyring:new" $ \syn -> do
|
||||||
n <- case syn of
|
n <- case syn of
|
||||||
[LitIntVal k] -> pure k
|
[LitIntVal k] -> pure k
|
||||||
[] -> pure 1
|
[] -> pure 1
|
||||||
|
@ -520,13 +229,7 @@ main = do
|
||||||
cred <- foldM (\cred _ -> addKeyPair Nothing cred) cred0 [1..n]
|
cred <- foldM (\cred _ -> addKeyPair Nothing cred) cred0 [1..n]
|
||||||
pure $ mkStr @C $ show $ pretty $ AsCredFile $ AsBase58 cred
|
pure $ mkStr @C $ show $ pretty $ AsCredFile $ AsBase58 cred
|
||||||
|
|
||||||
tell $ bindMatch "hbs2:keyman:list" $ nil_ \case
|
entry $ bindMatch "hbs2:reflog:tx:create-raw" $ \case
|
||||||
_ -> do
|
|
||||||
void $ runKeymanClient $ KeyManClient $ do
|
|
||||||
k <- listKeys
|
|
||||||
display_ $ vcat (fmap pretty k)
|
|
||||||
|
|
||||||
tell $ bindMatch "hbs2:reflog:tx:create-raw" $ \case
|
|
||||||
[SymbolVal "stdin", StringLike reflog] -> do
|
[SymbolVal "stdin", StringLike reflog] -> do
|
||||||
mkRefLogUpdateFrom ( liftIO BS.getContents ) reflog
|
mkRefLogUpdateFrom ( liftIO BS.getContents ) reflog
|
||||||
|
|
||||||
|
@ -535,24 +238,24 @@ main = do
|
||||||
|
|
||||||
_ -> throwIO (BadFormException @C nil)
|
_ -> throwIO (BadFormException @C nil)
|
||||||
|
|
||||||
tell $ bindMatch "str:read-stdin" $ \case
|
entry $ bindMatch "str:read-stdin" $ \case
|
||||||
[] -> liftIO getContents <&> mkStr @C
|
[] -> liftIO getContents <&> mkStr @C
|
||||||
|
|
||||||
_ -> throwIO (BadFormException @C nil)
|
_ -> throwIO (BadFormException @C nil)
|
||||||
|
|
||||||
tell $ bindMatch "str:read-file" $ \case
|
entry $ bindMatch "str:read-file" $ \case
|
||||||
[StringLike fn] -> liftIO (readFile fn) <&> mkStr @C
|
[StringLike fn] -> liftIO (readFile fn) <&> mkStr @C
|
||||||
|
|
||||||
_ -> throwIO (BadFormException @C nil)
|
_ -> throwIO (BadFormException @C nil)
|
||||||
|
|
||||||
tell $ bindMatch "str:save" $ nil_ \case
|
entry $ bindMatch "str:save" $ nil_ \case
|
||||||
[StringLike fn, StringLike what] ->
|
[StringLike fn, StringLike what] ->
|
||||||
liftIO (writeFile fn what)
|
liftIO (writeFile fn what)
|
||||||
|
|
||||||
_ -> throwIO (BadFormException @C nil)
|
_ -> throwIO (BadFormException @C nil)
|
||||||
|
|
||||||
|
|
||||||
tell $ bindMatch "hbs2:tree:metadata:get" $ \case
|
entry $ bindMatch "hbs2:tree:metadata:get" $ \case
|
||||||
[ SymbolVal how, StringLike hash ] -> do
|
[ SymbolVal how, StringLike hash ] -> do
|
||||||
|
|
||||||
-- FIXME: put-to-the-state
|
-- FIXME: put-to-the-state
|
||||||
|
@ -595,7 +298,7 @@ main = do
|
||||||
|
|
||||||
_ -> throwIO (BadFormException @C nil)
|
_ -> throwIO (BadFormException @C nil)
|
||||||
|
|
||||||
tell $ bindMatch "hbs2:tree:metadata:create" $ \syn -> do
|
entry $ bindMatch "hbs2:tree:metadata:create" $ \syn -> do
|
||||||
|
|
||||||
case syn of
|
case syn of
|
||||||
|
|
||||||
|
@ -616,7 +319,7 @@ main = do
|
||||||
|
|
||||||
_ -> throwIO (BadFormException @C nil)
|
_ -> throwIO (BadFormException @C nil)
|
||||||
|
|
||||||
tell $ bindMatch "cbor:base58" $ \case
|
entry $ bindMatch "cbor:base58" $ \case
|
||||||
[ LitStrVal x ] -> do
|
[ LitStrVal x ] -> do
|
||||||
pure $ mkForm "cbor:base58" [mkStr x]
|
pure $ mkForm "cbor:base58" [mkStr x]
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,12 @@ library
|
||||||
|
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
HBS2.CLI
|
HBS2.CLI
|
||||||
|
HBS2.CLI.Prelude
|
||||||
|
HBS2.CLI.Bind
|
||||||
|
HBS2.CLI.Run
|
||||||
|
HBS2.CLI.Run.Internal
|
||||||
|
HBS2.CLI.Run.KeyMan
|
||||||
|
HBS2.CLI.Run.Help
|
||||||
|
|
||||||
build-depends: base
|
build-depends: base
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
module HBS2.CLI.Bind where
|
||||||
|
|
||||||
|
import HBS2.CLI.Prelude
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
module HBS2.CLI.Prelude
|
||||||
|
( module HBS2.Prelude.Plated
|
||||||
|
, module UnliftIO
|
||||||
|
, module Data.Config.Suckless
|
||||||
|
, module Data.HashMap.Strict
|
||||||
|
, module Control.Monad.Reader
|
||||||
|
, Generic
|
||||||
|
) where
|
||||||
|
|
||||||
|
import HBS2.Prelude.Plated
|
||||||
|
|
||||||
|
import Data.HashMap.Strict
|
||||||
|
import Data.Config.Suckless
|
||||||
|
|
||||||
|
import Control.Monad.Reader
|
||||||
|
import UnliftIO
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
{-# Language UndecidableInstances #-}
|
||||||
|
module HBS2.CLI.Run
|
||||||
|
( module HBS2.CLI.Run.Internal
|
||||||
|
) where
|
||||||
|
|
||||||
|
import HBS2.CLI.Run.Internal
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
module HBS2.CLI.Run.Help where
|
|
@ -0,0 +1,333 @@
|
||||||
|
{-# Language UndecidableInstances #-}
|
||||||
|
module HBS2.CLI.Run.Internal where
|
||||||
|
|
||||||
|
import HBS2.CLI.Prelude
|
||||||
|
|
||||||
|
import Data.List (isPrefixOf)
|
||||||
|
import Data.List qualified as List
|
||||||
|
import Data.Kind
|
||||||
|
import Data.Maybe
|
||||||
|
import Data.HashMap.Strict qualified as HM
|
||||||
|
import Data.Text qualified as Text
|
||||||
|
import Data.Text.IO qualified as TIO
|
||||||
|
import Control.Monad.Identity
|
||||||
|
import Control.Monad.Writer
|
||||||
|
|
||||||
|
import Streaming.Prelude qualified as S
|
||||||
|
|
||||||
|
pattern StringLike :: forall {c} . String -> Syntax c
|
||||||
|
pattern StringLike e <- (stringLike -> Just e)
|
||||||
|
|
||||||
|
pattern StringLikeList :: forall {c} . [String] -> [Syntax c]
|
||||||
|
pattern StringLikeList e <- (stringLikeList -> e)
|
||||||
|
|
||||||
|
class Display a where
|
||||||
|
display :: MonadIO m => a -> m ()
|
||||||
|
|
||||||
|
instance {-# OVERLAPPABLE #-} Pretty w => Display w where
|
||||||
|
display = liftIO . print . pretty
|
||||||
|
|
||||||
|
instance Display (Syntax c) where
|
||||||
|
display = \case
|
||||||
|
LitStrVal s -> liftIO $ TIO.putStr s
|
||||||
|
x -> liftIO $ putStr (show $ pretty x)
|
||||||
|
|
||||||
|
instance Display Text where
|
||||||
|
display = liftIO . TIO.putStr
|
||||||
|
|
||||||
|
instance Display String where
|
||||||
|
display = liftIO . putStr
|
||||||
|
|
||||||
|
display_ :: (MonadIO m, Show a) => a -> m ()
|
||||||
|
display_ = liftIO . print
|
||||||
|
|
||||||
|
{- HLINT ignore "Functor law" -}
|
||||||
|
|
||||||
|
class IsContext c => MkSym c a where
|
||||||
|
mkSym :: a -> Syntax c
|
||||||
|
|
||||||
|
instance IsContext c => MkSym c String where
|
||||||
|
mkSym s = Symbol noContext (Id $ Text.pack s)
|
||||||
|
|
||||||
|
instance IsContext c => MkSym c Text where
|
||||||
|
mkSym s = Symbol noContext (Id s)
|
||||||
|
|
||||||
|
instance IsContext c => MkSym c Id where
|
||||||
|
mkSym = Symbol noContext
|
||||||
|
|
||||||
|
class IsContext c => MkStr c s where
|
||||||
|
mkStr :: s -> Syntax c
|
||||||
|
|
||||||
|
instance IsContext c => MkStr c String where
|
||||||
|
mkStr s = Literal noContext $ LitStr (Text.pack s)
|
||||||
|
|
||||||
|
instance IsContext c => MkStr c Text where
|
||||||
|
mkStr s = Literal noContext $ LitStr s
|
||||||
|
|
||||||
|
mkForm :: forall c . IsContext c => String -> [Syntax c] -> Syntax c
|
||||||
|
mkForm s sy = List noContext ( mkSym s : sy )
|
||||||
|
|
||||||
|
mkList :: forall c. IsContext c => [Syntax c] -> Syntax c
|
||||||
|
mkList = List noContext
|
||||||
|
|
||||||
|
|
||||||
|
class OptionalVal c b where
|
||||||
|
optional :: b -> Syntax c -> b
|
||||||
|
|
||||||
|
instance IsContext c => OptionalVal c Int where
|
||||||
|
optional d = \case
|
||||||
|
LitIntVal x -> fromIntegral x
|
||||||
|
_ -> d
|
||||||
|
|
||||||
|
stringLike :: Syntax c -> Maybe String
|
||||||
|
stringLike = \case
|
||||||
|
LitStrVal s -> Just $ Text.unpack s
|
||||||
|
SymbolVal (Id s) -> Just $ Text.unpack s
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
|
stringLikeList :: [Syntax c] -> [String]
|
||||||
|
stringLikeList syn = [ stringLike s | s <- syn ] & takeWhile isJust & catMaybes
|
||||||
|
|
||||||
|
data BindAction c ( m :: Type -> Type) =
|
||||||
|
BindLambda { fromLambda :: [Syntax c] -> RunM c m (Syntax c) }
|
||||||
|
| BindValue (Syntax c)
|
||||||
|
|
||||||
|
data Bind c ( m :: Type -> Type) = Bind
|
||||||
|
{ bindAction :: BindAction c m
|
||||||
|
, bindName :: Id
|
||||||
|
, bindDescShort :: Text
|
||||||
|
} deriving (Generic)
|
||||||
|
|
||||||
|
deriving newtype instance Hashable Id
|
||||||
|
|
||||||
|
newtype NameNotBoundException =
|
||||||
|
NameNotBound Id
|
||||||
|
deriving stock Show
|
||||||
|
deriving newtype (Generic,Typeable)
|
||||||
|
|
||||||
|
newtype NotLambda = NotLambda Id
|
||||||
|
deriving stock Show
|
||||||
|
deriving newtype (Generic,Typeable)
|
||||||
|
|
||||||
|
instance Exception NotLambda
|
||||||
|
|
||||||
|
data BadFormException c = BadFormException (Syntax c)
|
||||||
|
|
||||||
|
newtype TypeCheckError c = TypeCheckError (Syntax c)
|
||||||
|
|
||||||
|
instance Exception (TypeCheckError C)
|
||||||
|
|
||||||
|
newtype BadValueException = BadValueException String
|
||||||
|
deriving stock Show
|
||||||
|
deriving newtype (Generic,Typeable)
|
||||||
|
|
||||||
|
instance Exception NameNotBoundException
|
||||||
|
|
||||||
|
instance IsContext c => Show (BadFormException c) where
|
||||||
|
show (BadFormException sy) = show $ "BadFormException" <+> pretty sy
|
||||||
|
|
||||||
|
instance IsContext c => Show (TypeCheckError c) where
|
||||||
|
show (TypeCheckError sy) = show $ "TypeCheckError" <+> pretty sy
|
||||||
|
|
||||||
|
instance Exception (BadFormException C)
|
||||||
|
|
||||||
|
instance Exception BadValueException
|
||||||
|
|
||||||
|
newtype Dict c m = Dict { fromDict :: HashMap Id (Bind c m) }
|
||||||
|
deriving newtype (Semigroup, Monoid)
|
||||||
|
|
||||||
|
newtype RunM c m a = RunM { fromRunM :: ReaderT (TVar (Dict c m)) m a }
|
||||||
|
deriving newtype ( Applicative
|
||||||
|
, Functor
|
||||||
|
, Monad
|
||||||
|
, MonadIO
|
||||||
|
, MonadUnliftIO
|
||||||
|
, MonadReader (TVar (Dict c m))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
newtype MakeDictM c m a = MakeDictM { fromMakeDict :: Writer (Dict c m) a }
|
||||||
|
deriving newtype ( Applicative
|
||||||
|
, Functor
|
||||||
|
, Monad
|
||||||
|
, MonadWriter (Dict c m)
|
||||||
|
)
|
||||||
|
|
||||||
|
makeDict :: (IsContext c, Monad m) => MakeDictM c m () -> Dict c m
|
||||||
|
makeDict w = execWriter ( fromMakeDict w )
|
||||||
|
|
||||||
|
entry :: Dict c m -> MakeDictM c m ()
|
||||||
|
entry = tell
|
||||||
|
|
||||||
|
splitForms :: [String] -> [[String]]
|
||||||
|
splitForms s0 = runIdentity $ S.toList_ (go mempty s0)
|
||||||
|
where
|
||||||
|
go acc ( "then" : rest ) = emit acc >> go mempty rest
|
||||||
|
go acc ( "and" : rest ) = emit acc >> go mempty rest
|
||||||
|
go acc ( x : rest ) | isPrefixOf "-" x = go ( x : acc ) rest
|
||||||
|
go acc ( x : rest ) | isPrefixOf "--" x = go ( x : acc ) rest
|
||||||
|
go acc ( x : rest ) = go ( x : acc ) rest
|
||||||
|
go acc [] = emit acc
|
||||||
|
|
||||||
|
emit = S.yield . reverse
|
||||||
|
|
||||||
|
apply :: forall c m . ( IsContext c
|
||||||
|
, MonadUnliftIO m
|
||||||
|
, Exception (BadFormException c)
|
||||||
|
)
|
||||||
|
=> Id
|
||||||
|
-> [Syntax c]
|
||||||
|
-> RunM c m (Syntax c)
|
||||||
|
apply name args' = do
|
||||||
|
-- notice $ red "APPLY" <+> pretty name
|
||||||
|
what <- ask >>= readTVarIO <&> HM.lookup name . fromDict
|
||||||
|
case bindAction <$> what of
|
||||||
|
Just (BindLambda e) -> mapM runExpr args' >>= e
|
||||||
|
Just (BindValue v) -> throwIO (NotLambda name)
|
||||||
|
Nothing -> throwIO (NameNotBound name)
|
||||||
|
|
||||||
|
|
||||||
|
runExpr :: forall c m . ( IsContext c
|
||||||
|
, MonadUnliftIO m
|
||||||
|
, Exception (BadFormException c)
|
||||||
|
) => Syntax c -> RunM c m (Syntax c)
|
||||||
|
runExpr syn = handle (handleForm syn) $ case syn of
|
||||||
|
|
||||||
|
ListVal [ w, SymbolVal ".", b] -> do
|
||||||
|
pure $ mkList [w, b]
|
||||||
|
|
||||||
|
ListVal [ SymbolVal "quot", ListVal b] -> do
|
||||||
|
pure $ mkList b
|
||||||
|
|
||||||
|
ListVal [SymbolVal "lambda", arglist, body] -> do
|
||||||
|
pure $ mkForm @c "lambda" [ arglist, body ]
|
||||||
|
|
||||||
|
ListVal (ListVal [SymbolVal "lambda", ListVal decl, body] : args) -> do
|
||||||
|
error "oopsie"
|
||||||
|
-- d <- ask
|
||||||
|
-- void $ liftIO do
|
||||||
|
-- dd <- readTVarIO d
|
||||||
|
-- undefined
|
||||||
|
-- runReaderT $ runExpr body
|
||||||
|
-- error "FUCK!"
|
||||||
|
-- -- liftIO (run d body)
|
||||||
|
pure nil
|
||||||
|
|
||||||
|
ListVal (SymbolVal name : args') -> do
|
||||||
|
apply name args'
|
||||||
|
|
||||||
|
SymbolVal (Id s) | Text.isPrefixOf ":" s -> do
|
||||||
|
pure (mkSym @c (Text.drop 1 s))
|
||||||
|
|
||||||
|
SymbolVal name -> do
|
||||||
|
what <- ask >>= readTVarIO
|
||||||
|
<&> HM.lookup name . fromDict
|
||||||
|
<&> maybe (BindValue (mkSym name)) bindAction
|
||||||
|
|
||||||
|
case what of
|
||||||
|
BindValue e -> pure e
|
||||||
|
BindLambda e -> pure $ mkForm "lambda" [mkSym name, mkSym "..."]
|
||||||
|
|
||||||
|
e -> pure e
|
||||||
|
|
||||||
|
where
|
||||||
|
handleForm syn = \case
|
||||||
|
(BadFormException _ :: BadFormException c) -> do
|
||||||
|
throwIO (BadFormException syn)
|
||||||
|
|
||||||
|
run :: forall c m . ( IsContext c
|
||||||
|
, MonadUnliftIO m
|
||||||
|
, Exception (BadFormException c)
|
||||||
|
) => Dict c m -> [Syntax c] -> m (Syntax c)
|
||||||
|
run d sy = do
|
||||||
|
tvd <- newTVarIO d
|
||||||
|
lastDef nil <$> runReaderT (fromRunM (mapM runExpr sy)) tvd
|
||||||
|
|
||||||
|
bindMatch :: Id -> ([Syntax c] -> RunM c m (Syntax c)) -> Dict c m
|
||||||
|
bindMatch n fn = Dict (HM.singleton n (Bind (BindLambda fn) n ""))
|
||||||
|
|
||||||
|
nil :: forall c . IsContext c => Syntax c
|
||||||
|
nil = List noContext []
|
||||||
|
|
||||||
|
nil_ :: (IsContext c, MonadIO m) => (a -> RunM c m b) -> a -> RunM c m (Syntax c)
|
||||||
|
nil_ m w = m w >> pure (List noContext [])
|
||||||
|
|
||||||
|
bind :: (MonadUnliftIO m, IsContext c) => Id -> Syntax c -> RunM c m (Syntax c)
|
||||||
|
bind name expr = do
|
||||||
|
tv <- ask -- >>= readTVarIO
|
||||||
|
atomically do
|
||||||
|
w@(Dict x) <- readTVar tv
|
||||||
|
writeTVar tv w
|
||||||
|
pure nil
|
||||||
|
|
||||||
|
internalEntries :: MonadUnliftIO m => MakeDictM C m ()
|
||||||
|
internalEntries = do
|
||||||
|
entry $ bindMatch "concat" $ \syn -> do
|
||||||
|
|
||||||
|
case syn of
|
||||||
|
[ListVal (StringLikeList xs)] -> do
|
||||||
|
pure $ mkStr @C ( mconcat xs )
|
||||||
|
|
||||||
|
StringLikeList xs -> do
|
||||||
|
pure $ mkStr ( mconcat xs )
|
||||||
|
|
||||||
|
_ -> throwIO (BadFormException @C nil)
|
||||||
|
|
||||||
|
entry $ bindMatch "list" $ \case
|
||||||
|
es -> do
|
||||||
|
pure $ mkList @C es
|
||||||
|
|
||||||
|
entry $ bindMatch "dict" $ \case
|
||||||
|
es -> do
|
||||||
|
pure $ mkForm "dict" es
|
||||||
|
|
||||||
|
entry $ bindMatch "lambda" $ \case
|
||||||
|
[a, b] -> do
|
||||||
|
pure $ mkForm @C "lamba" [ mkSym "_", mkSym "..." ]
|
||||||
|
|
||||||
|
_ -> error "SHIT"
|
||||||
|
|
||||||
|
entry $ bindMatch "map" $ \syn -> do
|
||||||
|
case syn of
|
||||||
|
[ListVal (SymbolVal "lambda" : SymbolVal fn : _), ListVal rs] -> do
|
||||||
|
mapM (apply fn . List.singleton) rs
|
||||||
|
<&> mkList
|
||||||
|
|
||||||
|
w -> do
|
||||||
|
throwIO (BadFormException @C nil)
|
||||||
|
|
||||||
|
entry $ bindMatch "head" $ \case
|
||||||
|
[ ListVal es ] -> pure (head es)
|
||||||
|
_ -> throwIO (TypeCheckError @C nil)
|
||||||
|
|
||||||
|
entry $ bindMatch "tail" $ \case
|
||||||
|
[] -> pure nil
|
||||||
|
[ListVal []] -> pure nil
|
||||||
|
[ListVal es] -> pure $ mkList @C (tail es)
|
||||||
|
_ -> throwIO (BadFormException @C nil)
|
||||||
|
|
||||||
|
entry $ bindMatch "lookup" $ \case
|
||||||
|
[s, ListVal (SymbolVal "dict" : es) ] -> do
|
||||||
|
let val = headDef nil [ v | ListVal [k, v] <- es, k == s ]
|
||||||
|
pure val
|
||||||
|
|
||||||
|
[StringLike s, ListVal [] ] -> do
|
||||||
|
pure nil
|
||||||
|
|
||||||
|
_ -> throwIO (BadFormException @C nil)
|
||||||
|
|
||||||
|
entry $ bindMatch "display" $ nil_ \case
|
||||||
|
[ sy ] -> display sy
|
||||||
|
ss -> display (mkList ss)
|
||||||
|
|
||||||
|
entry $ bindMatch "newline" $ nil_ $ \case
|
||||||
|
[] -> liftIO (putStrLn "")
|
||||||
|
_ -> throwIO (BadFormException @C nil)
|
||||||
|
|
||||||
|
entry $ bindMatch "print" $ nil_ $ \case
|
||||||
|
[ sy ] -> display sy >> liftIO (putStrLn "")
|
||||||
|
ss -> mapM_ display ss >> liftIO (putStrLn "")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
module HBS2.CLI.Run.KeyMan where
|
||||||
|
|
||||||
|
import HBS2.CLI.Prelude
|
||||||
|
import HBS2.CLI.Run.Internal
|
||||||
|
|
||||||
|
import HBS2.Hash
|
||||||
|
import HBS2.System.Dir
|
||||||
|
|
||||||
|
import HBS2.KeyMan.Keys.Direct
|
||||||
|
import HBS2.KeyMan.State
|
||||||
|
import HBS2.KeyMan.App.Types
|
||||||
|
|
||||||
|
import Codec.Serialise
|
||||||
|
import Data.Either
|
||||||
|
import Data.ByteString.Lazy qualified as LBS
|
||||||
|
import Data.Text.Encoding qualified as TE
|
||||||
|
import Data.Text.IO qualified as TIO
|
||||||
|
import System.Process.Typed
|
||||||
|
import Text.InterpolatedString.Perl6 (qc)
|
||||||
|
|
||||||
|
fixContext :: (IsContext c1, IsContext c2) => Syntax c1 -> Syntax c2
|
||||||
|
fixContext = go
|
||||||
|
where
|
||||||
|
go = \case
|
||||||
|
List _ xs -> List noContext (fmap go xs)
|
||||||
|
Symbol _ w -> Symbol noContext w
|
||||||
|
Literal _ l -> Literal noContext l
|
||||||
|
|
||||||
|
|
||||||
|
keymanGetConfig :: (IsContext c, MonadUnliftIO m) => m [Syntax c]
|
||||||
|
keymanGetConfig = do
|
||||||
|
(_,lbs,_) <- readProcess (shell [qc|hbs2-keyman config|] & setStderr closed)
|
||||||
|
|
||||||
|
let conf = TE.decodeUtf8 (LBS.toStrict lbs)
|
||||||
|
& parseTop
|
||||||
|
& fromRight mempty
|
||||||
|
|
||||||
|
pure $ fmap fixContext conf
|
||||||
|
|
||||||
|
keymanUpdate :: MonadUnliftIO m => m ()
|
||||||
|
keymanUpdate = do
|
||||||
|
void $ runProcess (shell [qc|hbs2-keyman update|])
|
||||||
|
|
||||||
|
keymanEntries :: (MonadUnliftIO m, IsContext c) => MakeDictM c m ()
|
||||||
|
keymanEntries = do
|
||||||
|
entry $ bindMatch "hbs2:keyman:list" $ nil_ \case
|
||||||
|
_ -> do
|
||||||
|
void $ runKeymanClient $ KeyManClient $ do
|
||||||
|
k <- listKeys
|
||||||
|
display_ $ vcat (fmap pretty k)
|
||||||
|
|
||||||
|
entry $ bindMatch "hbs2:keyman:update" $ nil_ $ \_ -> do
|
||||||
|
keymanUpdate
|
||||||
|
|
||||||
|
entry $ bindMatch "hbs2:keyman:config" $ \_ -> do
|
||||||
|
mkForm "dict" <$> keymanGetConfig
|
||||||
|
|
||||||
|
entry $ bindMatch "hbs2:keyman:keys:add" $ \case
|
||||||
|
[ LitStrVal ke ] -> do
|
||||||
|
conf <- keymanGetConfig @C
|
||||||
|
let path = head [ s | ListVal [ SymbolVal "default-key-path", StringLike s ] <- conf ]
|
||||||
|
mkdir path
|
||||||
|
let n = hashObject @HbSync (serialise ke) & pretty & show
|
||||||
|
let fname = n `addExtension` ".key"
|
||||||
|
let fpath = path </> fname
|
||||||
|
liftIO $ TIO.writeFile fpath ke
|
||||||
|
keymanUpdate
|
||||||
|
pure $ mkStr fpath
|
||||||
|
|
||||||
|
_ -> throwIO (BadFormException @C nil)
|
||||||
|
|
Loading…
Reference in New Issue