Skip to content

Commit 2e2a213

Browse files
authored
Merge pull request #23 from mlabs-haskell/common/proto-types-validated
Create Common Proto Types conversion
2 parents 4822fe8 + 8df9647 commit 2e2a213

File tree

20 files changed

+1431
-64
lines changed

20 files changed

+1431
-64
lines changed

flake.nix

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,23 +66,37 @@
6666
inherit (pre-commit-check) shellHook;
6767
};
6868

69-
# Compiler build
7069
index-state = "2022-12-01T00:00:00Z";
7170
compiler-nix-name = "ghc924";
7271

73-
compilerBuild = import ./lambda-buffers-compiler/build.nix {
74-
inherit pkgs compiler-nix-name index-state haskell-nix mlabs-tooling commonTools;
75-
inherit (protosBuild) compilerHsPb;
76-
inherit (pre-commit-check) shellHook;
72+
# Common build abstraction for the components.
73+
buildAbstraction = { import-location, additional ? { } }:
74+
import import-location ({
75+
inherit pkgs compiler-nix-name index-state haskell-nix mlabs-tooling commonTools;
76+
inherit (protosBuild) compilerHsPb;
77+
inherit (pre-commit-check) shellHook;
78+
} // additional);
79+
80+
# Common Flake abstraction for the components.
81+
flakeAbstraction = component-name: component-name.hsNixProj.flake { };
82+
83+
# Compiler Build
84+
compilerBuild = buildAbstraction { import-location = ./lambda-buffers-compiler/build.nix; };
85+
compilerFlake = flakeAbstraction compilerBuild;
86+
87+
# Extras Build
88+
extrasBuild = buildAbstraction {
89+
import-location = ./lambda-buffers-extras/build.nix;
90+
additional = { lambda-buffers-compiler = ./lambda-buffers-compiler; };
7791
};
78-
compilerFlake = compilerBuild.hsNixProj.flake { };
92+
extrasFlake = flakeAbstraction extrasBuild;
7993

80-
frontendBuild = import ./lambda-buffers-frontend/build.nix {
81-
inherit pkgs compiler-nix-name index-state haskell-nix mlabs-tooling commonTools;
82-
inherit (protosBuild) compilerHsPb;
83-
inherit (pre-commit-check) shellHook;
94+
# Frontend Build
95+
frontendBuild = buildAbstraction {
96+
import-location = ./lambda-buffers-frontend/build.nix;
97+
additional = { lambda-buffers-compiler = ./lambda-buffers-compiler; };
8498
};
85-
frontendFlake = frontendBuild.hsNixProj.flake { };
99+
frontendFlake = flakeAbstraction frontendBuild;
86100

87101
# Utilities
88102
renameAttrs = rnFn: pkgs.lib.attrsets.mapAttrs' (n: value: { name = rnFn n; inherit value; });
@@ -92,7 +106,7 @@
92106
inherit pkgs;
93107

94108
# Standard flake attributes
95-
packages = { inherit (protosBuild) compilerHsPb; } // compilerFlake.packages // frontendFlake.packages;
109+
packages = { inherit (protosBuild) compilerHsPb; } // compilerFlake.packages // frontendFlake.packages // extrasFlake.packages;
96110

97111
devShells = rec {
98112
dev-pre-commit = preCommitDevShell;
@@ -101,11 +115,12 @@
101115
dev-protos = protosBuild.devShell;
102116
dev-compiler = compilerFlake.devShell;
103117
dev-frontend = frontendFlake.devShell;
118+
dev-common = extrasFlake.devShell;
104119
default = preCommitDevShell;
105120
};
106121

107122
# nix flake check --impure --keep-going --allow-import-from-derivation
108-
checks = { inherit pre-commit-check; } // devShells // packages // renameAttrs (n: "check-${n}") (frontendFlake.checks // compilerFlake.checks);
123+
checks = { inherit pre-commit-check; } // devShells // packages // renameAttrs (n: "check-${n}") (frontendFlake.checks // compilerFlake.checks // extrasFlake.checks);
109124

110125
}
111126
) // {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
module LambdaBuffers.Compiler.Cli.Compile (CompileOpts (..), compile) where
2+
3+
import Control.Lens (makeLenses)
4+
import Control.Lens.Getter ((^.))
5+
import Data.ByteString qualified as BS
6+
import Data.ProtoLens qualified as Pb
7+
import Data.ProtoLens.TextFormat qualified as PbText
8+
import Data.Text.Lazy qualified as Text
9+
import Data.Text.Lazy.IO qualified as Text
10+
import LambdaBuffers.Compiler.ProtoCompat (FromProtoErr (NamingError, ProtoError), IsMessage (fromProto, toProto))
11+
import LambdaBuffers.Compiler.ProtoCompat.Types qualified as ProtoCompat
12+
import Proto.Compiler (CompilerInput)
13+
import System.FilePath.Lens (extension)
14+
15+
data CompileOpts = CompileOpts
16+
{ _input :: FilePath
17+
, _output :: FilePath
18+
}
19+
deriving stock (Eq, Show)
20+
21+
makeLenses ''CompileOpts
22+
23+
-- | Compile LambdaBuffers modules
24+
compile :: CompileOpts -> IO ()
25+
compile opts = do
26+
compIn <- readCompilerInput (opts ^. input)
27+
case fromProto @CompilerInput @ProtoCompat.CompilerInput compIn of
28+
Left err -> case err of
29+
NamingError ne -> print $ "Encountered a naming error " <> show ne
30+
ProtoError pe -> print $ "Encountered a proto error " <> show pe
31+
Right compIn' -> do
32+
print @String "Successfully processed the CompilerInput"
33+
writeCompilerOutput (opts ^. output) (toProto compIn')
34+
35+
return ()
36+
37+
readCompilerInput :: FilePath -> IO CompilerInput
38+
readCompilerInput fp = do
39+
let ext = fp ^. extension
40+
case ext of
41+
".pb" -> do
42+
content <- BS.readFile fp
43+
return $ Pb.decodeMessageOrDie content
44+
".textproto" -> do
45+
content <- Text.readFile fp
46+
return $ PbText.readMessageOrDie content
47+
_ -> error $ "Unknown CompilerInput format " <> ext
48+
49+
-- FIXME(bladyjoker): Do this properly when you figure out what the CompilerOutput is.
50+
writeCompilerOutput :: FilePath -> CompilerInput -> IO ()
51+
writeCompilerOutput fp co = do
52+
let ext = fp ^. extension
53+
case ext of
54+
".pb" -> BS.writeFile fp (Pb.encodeMessage co)
55+
".textproto" -> Text.writeFile fp (Text.pack . show $ PbText.pprintMessage co)
56+
_ -> error $ "Unknown CompilerOutput format " <> ext
Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,64 @@
11
module Main (main) where
22

3-
import Control.Lens ((&), (.~))
4-
import Data.ProtoLens.Default (def)
5-
import Proto.Compiler (CompilerInput)
6-
import Proto.Compiler_Fields (modules)
3+
import Control.Applicative ((<**>))
4+
5+
import LambdaBuffers.Compiler.Cli.Compile (CompileOpts (CompileOpts), compile)
6+
import Options.Applicative (
7+
Parser,
8+
ParserInfo,
9+
command,
10+
customExecParser,
11+
fullDesc,
12+
help,
13+
helper,
14+
info,
15+
long,
16+
metavar,
17+
prefs,
18+
progDesc,
19+
short,
20+
showHelpOnEmpty,
21+
showHelpOnError,
22+
strOption,
23+
subparser,
24+
)
25+
26+
newtype Command
27+
= Compile CompileOpts
28+
29+
inputPathP :: Parser FilePath
30+
inputPathP =
31+
strOption
32+
( long "input-file"
33+
<> short 'i'
34+
<> metavar "FILEPATH"
35+
<> help "File to compile (lambdabuffers.compiler.CompilerInput in .textproto format)"
36+
)
37+
38+
outputPathP :: Parser FilePath
39+
outputPathP =
40+
strOption
41+
( long "output-file"
42+
<> short 'o'
43+
<> metavar "FILEPATH"
44+
<> help "File to write the output to (lambdabuffers.compiler.CompilerOutput in .textproto format)"
45+
)
46+
47+
compileOptsP :: Parser CompileOpts
48+
compileOptsP = CompileOpts <$> inputPathP <*> outputPathP
49+
50+
optionsP :: Parser Command
51+
optionsP =
52+
subparser $
53+
command
54+
"compile"
55+
(info (Compile <$> compileOptsP <* helper) (progDesc "Compile LambdaBuffers"))
56+
57+
parserInfo :: ParserInfo Command
58+
parserInfo = info (optionsP <**> helper) (fullDesc <> progDesc "LambdaBuffers Compiler command-line interface tool")
759

860
main :: IO ()
961
main = do
10-
putStrLn "Hello, Haskell!"
11-
print $ (def :: CompilerInput) & modules .~ []
62+
cmd <- customExecParser (prefs (showHelpOnEmpty <> showHelpOnError)) parserInfo
63+
case cmd of
64+
Compile opts -> compile opts

lambda-buffers-compiler/build.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ let
1717
inherit compiler-nix-name index-state;
1818

1919
extraHackage = [
20-
(builtins.toString compilerHsPb)
20+
"${compilerHsPb}"
2121
];
2222

2323
modules = [

lambda-buffers-compiler/lambda-buffers-compiler.cabal

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,21 @@ library
8484
build-depends:
8585
, base >=4.16
8686
, freer-simple >=1.2
87+
, generic-lens >=2.2
8788
, lambda-buffers-compiler-pb >=0.1.0.0
8889
, lens >=5.2
90+
, mtl >=2.2
91+
, parsec >=3.1
8992
, prettyprinter >=1.7
93+
, proto-lens >=0.7
9094
, text >=1.2
9195

9296
exposed-modules:
9397
LambdaBuffers.Compiler.KindCheck
9498
LambdaBuffers.Compiler.KindCheck.Inference
99+
LambdaBuffers.Compiler.NamingCheck
100+
LambdaBuffers.Compiler.ProtoCompat
101+
LambdaBuffers.Compiler.ProtoCompat.Types
95102

96103
hs-source-dirs: src
97104

@@ -100,11 +107,16 @@ executable lambda-buffers-compiler-cli
100107
main-is: Main.hs
101108
build-depends:
102109
, base >=4.16
110+
, bytestring >=0.11
111+
, lambda-buffers-compiler
103112
, lambda-buffers-compiler-pb >=0.1.0.0
104113
, lens >=5.2
114+
, optparse-applicative >=0.17
105115
, proto-lens >=0.7
116+
, text >=1.2
106117

107118
hs-source-dirs: app
119+
other-modules: LambdaBuffers.Compiler.Cli.Compile
108120

109121
test-suite tests
110122
import: common-language

lambda-buffers-compiler/src/LambdaBuffers/Compiler/KindCheck.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{-# LANGUAGE TemplateHaskell #-}
22

3-
{- | Note: At the moment the Kind Checker disregards multiple Modules for
4-
simplicity of testing and developing. This will be changed ASAP. :fixme:
3+
{- | FIXME(cstml): At the moment the Kind Checker disregards multiple Modules for
4+
simplicity of testing and developing. This will be changed ASAP.
55
-}
66
module LambdaBuffers.Compiler.KindCheck (
77
KindCheckFailure (..),
@@ -44,6 +44,7 @@ import Proto.Compiler (
4444
TyRef'TyRef (TyRef'ForeignTyRef, TyRef'LocalTyRef),
4545
)
4646
import Proto.Compiler_Fields as PF (
47+
argName,
4748
constrName,
4849
constructors,
4950
fieldTy,
@@ -61,7 +62,6 @@ import Proto.Compiler_Fields as PF (
6162
tyBody,
6263
tyFunc,
6364
tyName,
64-
tyVars,
6565
varName,
6666
)
6767

@@ -142,7 +142,7 @@ interpretKindCheck = interpret $
142142

143143
validateTyDef :: TyDef -> Eff KindCheckFailEff TypeDefinition
144144
validateTyDef tD = do
145-
let vars = tD ^.. tyAbs . tyVars . folded . varName . name . to unpack
145+
let vars = tD ^.. tyAbs . tyArgs . folded . argName . name . to unpack
146146
sop <- go (tD ^. tyAbs . tyBody . maybe'tyBody)
147147
pure $
148148
TypeDefinition
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
module LambdaBuffers.Compiler.NamingCheck (pModuleNamePart, pVarName, pTyName, pConstrName, pFieldName, pClassName, checkModuleName, checkTyName, checkVarName, checkConstrName, checkClassName, checkFieldName) where
2+
3+
import Control.Lens ((.~), (^.))
4+
import Control.Monad.Except (MonadError (throwError))
5+
import Data.Foldable (for_)
6+
import Data.Function ((&))
7+
import Data.Kind (Type)
8+
import Data.ProtoLens (Message (defMessage))
9+
import Data.ProtoLens.Field (HasField)
10+
import Data.String (IsString (fromString))
11+
import Data.Text (Text)
12+
import Proto.Compiler (ClassName, ConstrName, FieldName, Module, NamingError, NamingError'NameType (NamingError'NAME_TYPE_CLASS, NamingError'NAME_TYPE_CONSTR, NamingError'NAME_TYPE_FIELD, NamingError'NAME_TYPE_MODULE, NamingError'NAME_TYPE_TYPE, NamingError'NAME_TYPE_VAR), SourceInfo, TyName, VarName)
13+
import Proto.Compiler_Fields (moduleName, name, nameType, parts, sourceInfo)
14+
import Text.Parsec (ParsecT, Stream, alphaNum, label, lower, many, many1, runParserT)
15+
import Text.Parsec.Char (upper)
16+
17+
type Parser :: Type -> (Type -> Type) -> Type -> Type
18+
type Parser s m a = ParsecT s () m a
19+
20+
pUpperCamelCase :: Stream s m Char => Parser s m Text
21+
pUpperCamelCase = label' "UpperCamelCase" $ fromString <$> ((:) <$> upper <*> many alphaNum)
22+
23+
pLowerCamelCase :: Stream s m Char => Parser s m Text
24+
pLowerCamelCase = label' "lowerCamelCase" $ fromString <$> ((:) <$> lower <*> many alphaNum)
25+
26+
pModuleNamePart :: Stream s m Char => Parser s m Text
27+
pModuleNamePart = label' "module part name" pUpperCamelCase
28+
29+
pVarName :: Stream s m Char => Parser s m Text
30+
pVarName = label' "type variable name" $ fromString <$> many1 lower
31+
32+
pTyName :: Stream s m Char => Parser s m Text
33+
pTyName = label' "type name" pUpperCamelCase
34+
35+
pConstrName :: Stream s m Char => Parser s m Text
36+
pConstrName = label' "sum body constructor name" pUpperCamelCase
37+
38+
pFieldName :: Stream s m Char => Parser s m Text
39+
pFieldName = label' "record body field name" pLowerCamelCase
40+
41+
pClassName :: Stream s m Char => Parser s m Text
42+
pClassName = label' "type class name" pUpperCamelCase
43+
44+
label' :: String -> Parser s m a -> Parser s m a
45+
label' l m = label m l
46+
47+
validateP ::
48+
( MonadError NamingError m
49+
, HasField a "sourceInfo" SourceInfo
50+
, HasField a "name" Text
51+
) =>
52+
Parser Text m Text ->
53+
NamingError'NameType ->
54+
a ->
55+
m ()
56+
validateP p nt i = do
57+
resOrErr <- runParserT p () "" (i ^. name)
58+
case resOrErr of
59+
Left _ ->
60+
throwError $
61+
defMessage
62+
& nameType .~ nt
63+
& sourceInfo .~ (i ^. sourceInfo)
64+
Right _ -> return ()
65+
66+
checkModuleName :: MonadError NamingError m => Module -> m ()
67+
checkModuleName m = for_ (m ^. (moduleName . parts)) (validateP pModuleNamePart NamingError'NAME_TYPE_MODULE)
68+
69+
checkTyName :: MonadError NamingError m => TyName -> m ()
70+
checkTyName = validateP pTyName NamingError'NAME_TYPE_TYPE
71+
72+
checkVarName :: MonadError NamingError m => VarName -> m ()
73+
checkVarName = validateP pVarName NamingError'NAME_TYPE_VAR
74+
75+
checkConstrName :: MonadError NamingError m => ConstrName -> m ()
76+
checkConstrName = validateP pConstrName NamingError'NAME_TYPE_CONSTR
77+
78+
checkFieldName :: MonadError NamingError m => FieldName -> m ()
79+
checkFieldName = validateP pFieldName NamingError'NAME_TYPE_FIELD
80+
81+
checkClassName :: MonadError NamingError m => ClassName -> m ()
82+
checkClassName = validateP pClassName NamingError'NAME_TYPE_CLASS

0 commit comments

Comments
 (0)