Skip to content

Frontend #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Jan 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c349bd2
Frontend scaffold and type expression parsed
bladyjoker Jan 6, 2023
892e8a3
Parse module name
bladyjoker Jan 7, 2023
f061665
Parse Sum body
bladyjoker Jan 7, 2023
3570085
Parsed type definition
bladyjoker Jan 7, 2023
c1a50a3
Parsed module
bladyjoker Jan 7, 2023
f866837
Whitespace nad newlines
bladyjoker Jan 8, 2023
692d746
Switched to using a Syntax DSL
bladyjoker Jan 9, 2023
87dce69
Cleanup
bladyjoker Jan 9, 2023
3834b53
Parsed module import statements
bladyjoker Jan 9, 2023
003a901
Module resolution first draft
bladyjoker Jan 9, 2023
4727561
Module scope imports
bladyjoker Jan 11, 2023
fd8bc43
Switched to using parametrized Syntax types
bladyjoker Jan 11, 2023
d8de131
Frontend CLI scaffold
bladyjoker Jan 12, 2023
d1fa860
lambda-buffers-frontend-cli compile -i resources/ -f Test.lbf
bladyjoker Jan 12, 2023
1f825ce
Andrea and Vlad told me how to get rid of instance def boilerplate!
bladyjoker Jan 12, 2023
80a1ba3
Added PPrint and sorted out error reporting
bladyjoker Jan 13, 2023
1e85f4a
Added good examples
bladyjoker Jan 13, 2023
a2e5b32
Fixed strict builds
bladyjoker Jan 13, 2023
82ec434
Fixed hoogle issues by removing additional
bladyjoker Jan 13, 2023
a8f2470
Minor cleanup
bladyjoker Jan 13, 2023
a2f94fd
Merge remote-tracking branch 'origin/main' into bladyjoker/frontend
bladyjoker Jan 13, 2023
a59dd1f
Fixed after merge issues
bladyjoker Jan 13, 2023
4a06b4e
Cosmetic on compiler
bladyjoker Jan 16, 2023
7655310
Scaffolded tests for the Frontend
bladyjoker Jan 16, 2023
2787388
Added Frontend error tests
bladyjoker Jan 16, 2023
af67d90
Added simple good unit test
bladyjoker Jan 16, 2023
c5b8120
Implemented pretty printing and the `lambda-buffers-frontend-cli form…
bladyjoker Jan 16, 2023
9f4b2cb
Applied review suggestions
bladyjoker Jan 16, 2023
b9baec0
Merge remote-tracking branch 'origin/main' into bladyjoker/frontend
bladyjoker Jan 16, 2023
d646a0e
Moved Frontend/FrontM.hs to Frontend.hs
bladyjoker Jan 16, 2023
e048d95
Added formatting unit test
bladyjoker Jan 16, 2023
c2145c3
Added documentation, FIXMEs and TODOs
bladyjoker Jan 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,14 @@
inherit (protosBuild) compilerHsPb;
inherit (pre-commit-check) shellHook;
};
compilerFlake = compilerBuild.compilerHsNixProj.flake { };
compilerFlake = compilerBuild.hsNixProj.flake { };

frontendBuild = import ./lambda-buffers-frontend/build.nix {
inherit pkgs compiler-nix-name index-state haskell-nix mlabs-tooling commonTools;
inherit (protosBuild) compilerHsPb;
inherit (pre-commit-check) shellHook;
};
frontendFlake = frontendBuild.hsNixProj.flake { };

# Utilities
# INFO: Will need this; renameAttrs = rnFn: pkgs.lib.attrsets.mapAttrs' (n: value: { name = rnFn n; inherit value; });
Expand All @@ -85,14 +92,15 @@
inherit pkgs;

# Standard flake attributes
packages = { inherit (protosBuild) compilerHsPb; } // compilerFlake.packages;
packages = { inherit (protosBuild) compilerHsPb; } // compilerFlake.packages // frontendFlake.packages;

devShells = rec {
dev-pre-commit = preCommitDevShell;
dev-experimental = experimentalDevShell;
dev-docs = docsDevShell;
dev-protos = protosBuild.devShell;
dev-compiler = compilerFlake.devShell;
dev-frontend = frontendFlake.devShell;
default = preCommitDevShell;
};

Expand Down
8 changes: 2 additions & 6 deletions lambda-buffers-compiler/build.nix
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ let
allComponent.doHaddock = true;

# Enable strict compilation
allComponent.configureFlags = [ "-f-dev" ];
lambda-buffers-compiler.configureFlags = [ "-f-dev" ];
};
})
];
Expand All @@ -40,10 +40,6 @@ let

nativeBuildInputs = builtins.attrValues commonTools;

additional = ps: [
ps.lambda-buffers-compiler-pb
];

tools = {
cabal = { };
haskell-language-server = { };
Expand All @@ -59,7 +55,7 @@ let
};
in
{
compilerHsNixProj = haskell-nix.cabalProject' [
hsNixProj = haskell-nix.cabalProject' [
mlabs-tooling.lib.mkHackageMod
project
];
Expand Down
25 changes: 5 additions & 20 deletions lambda-buffers-compiler/lambda-buffers-compiler.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -79,34 +79,24 @@ common common-language

default-language: Haskell2010

common common-dependencies
build-depends:
, base >=4.16
, containers >=0.6
, lens >=5.2
, proto-lens >=0.7
, text >=1.2
, transformers >=0.5

library
import: common-language
import: common-dependencies
build-depends:
, containers >=0.6
, base >=4.16
, freer-simple >=1.2
, lambda-buffers-compiler-pb >=0.1.0.0
, mtl >=2.2
, lens >=5.2
, prettyprinter >=1.7
, text >=1.2

exposed-modules:
LambdaBuffers.Compiler.KindCheck
LambdaBuffers.Compiler.KindCheck.Inference

hs-source-dirs: src

executable lambda-buffers-compiler
executable lambda-buffers-compiler-cli
import: common-language
import: common-dependencies
main-is: Main.hs
build-depends:
, base >=4.16
Expand All @@ -118,18 +108,13 @@ executable lambda-buffers-compiler

test-suite tests
import: common-language
import: common-dependencies
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: Test.hs
build-depends:
, hedgehog >=1
, base >=4.16
, lambda-buffers-compiler
, QuickCheck >=2
, tasty >=1.4
, tasty-expected-failure >=0.12
, tasty-hedgehog >=1.4
, tasty-hunit >=0.10
, tasty-quickcheck >=0.10

other-modules: Test.KindCheck
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Control.Lens (folded, makeLenses, to, (&), (.~), (^.), (^..))
import Control.Monad.Freer (Eff, interpret, run)
import Control.Monad.Freer.Error (Error, runError, throwError)
import Control.Monad.Freer.TH (makeEffect)
import Data.Text (Text, unpack)
import Data.Text (Text, intercalate, unpack)
import LambdaBuffers.Compiler.KindCheck.Inference (
Context,
InferErr,
Expand All @@ -32,7 +32,7 @@ import Control.Monad (void)
import Data.Traversable (for)
import Proto.Compiler (
Product'NTuple,
Product'Product (Product'Empty', Product'Ntuple, Product'Record'),
Product'Product (Product'Ntuple, Product'Record'),
Product'Record,
Sum,
Ty,
Expand All @@ -54,6 +54,7 @@ import Proto.Compiler_Fields as PF (
maybe'tyRef,
moduleName,
name,
parts,
product,
tyAbs,
tyArgs,
Expand Down Expand Up @@ -171,7 +172,6 @@ sumToType sumT = do
for
products
$ \case
Just (Product'Empty' _) -> pure $ Var "()"
Just (Product'Ntuple nt) -> nTupleToType nt
Just (Product'Record' re) -> recordToType re
Nothing -> throwError $ InvalidProto "Every constructor should have a product defining it"
Expand Down Expand Up @@ -236,5 +236,5 @@ tyRefToType :: TyRef -> Eff KindCheckFailEff Type
tyRefToType tR = do
case tR ^. maybe'tyRef of
Just (TyRef'LocalTyRef t) -> pure $ Var $ t ^. tyName . name . to unpack
Just (TyRef'ForeignTyRef t) -> pure $ Var $ (t ^. moduleName . name . to unpack) <> "." <> (t ^. tyName . name . to unpack)
Just (TyRef'ForeignTyRef t) -> pure $ Var $ (t ^. moduleName . parts . to (\ps -> unpack $ intercalate "." [p ^. name | p <- ps])) <> "." <> (t ^. tyName . name . to unpack)
Nothing -> throwError $ InvalidProto "TyRef Cannot be empty"
6 changes: 2 additions & 4 deletions lambda-buffers-compiler/test/Test.hs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
{-# LANGUAGE ImportQualifiedPost #-}

module Main (main) where

import Test.KindCheck qualified as KC
import Test.Tasty
import Test.Tasty (defaultMain, testGroup)

main :: IO ()
main = defaultMain $ testGroup "All Tests" [KC.test]
main = defaultMain $ testGroup "Compiler tests" [KC.test]
40 changes: 28 additions & 12 deletions lambda-buffers-compiler/test/Test/KindCheck.hs
Original file line number Diff line number Diff line change
@@ -1,36 +1,48 @@
{-# OPTIONS_GHC -Wno-missing-signatures #-}

module Test.KindCheck (test) where

import LambdaBuffers.Compiler.KindCheck
import LambdaBuffers.Compiler.KindCheck.Inference
import Test.Tasty
import Test.Tasty.HUnit
import LambdaBuffers.Compiler.KindCheck (
KindCheckFailure (InferenceFailed),
TypeDefinition (TypeDefinition, _td'name, _td'sop, _td'variables),
kindCheckType,
runKindCheckEff,
)
import LambdaBuffers.Compiler.KindCheck.Inference (
InferErr (ImpossibleUnificationErr),
Kind (Type, (:->:)),
Type (Abs, App, Var),
)
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit (testCase, (@?=))

test :: TestTree
test = testGroup "KindChecker Tests" [t1, t2, t3, t4, t5]
test = testGroup "KindChecker tests" [t1, t2, t3, t4, t5]

runKC :: [TypeDefinition] -> Either KindCheckFailure [Kind]
runKC = runKindCheckEff . kindCheckType

t1 :: TestTree
t1 =
testCase "No Definition, No Kinds." $
testCase "No Definition, No Kinds" $
runKC [] @?= Right []

t2 :: TestTree
t2 =
testCase "Maybe has the correct Kind." $
testCase "Maybe has the correct Kind" $
runKC [tdMaybe] @?= Right [Type :->: Type]

t3 :: TestTree
t3 =
testCase "Maybe works correctly when used as a type." $
testCase "Maybe works correctly when used as a type" $
runKC [tdT1, tdMaybe] @?= Right [Type :->: Type, Type :->: Type]

t4 :: TestTree
t4 =
testCase "Maybe and a term containing a maybe work correctly." $
testCase "Maybe and a term containing a maybe work correctly" $
runKC [tdT1, tdMaybe, tdT2] @?= Right [Type :->: Type, Type :->: Type, Type :->: Type]

t5 :: TestTree
t5 =
testCase "Bad Type is caught and reported." $
testCase "Bad Type is caught and reported" $
runKC [tdMaybe, tdBT0]
@?= Left
( InferenceFailed
Expand All @@ -46,6 +58,7 @@ t5 =
--------------------------------------------------------------------------------
-- Manual type definitions.

tdMaybe :: TypeDefinition
tdMaybe =
TypeDefinition
{ _td'name = "Maybe"
Expand All @@ -58,6 +71,7 @@ tdMaybe =
}

-- T1 ~ T a = T Maybe (Maybe a)
tdT1 :: TypeDefinition
tdT1 =
TypeDefinition
{ _td'name = "T"
Expand All @@ -66,6 +80,7 @@ tdT1 =
}

-- T2 ~ T a = T Maybe (Maybe a)
tdT2 :: TypeDefinition
tdT2 =
TypeDefinition
{ _td'name = "T2"
Expand All @@ -74,6 +89,7 @@ tdT2 =
}

-- T2 ~ T = T Maybe Maybe
tdBT0 :: TypeDefinition
tdBT0 =
TypeDefinition
{ _td'name = "T"
Expand Down
1 change: 1 addition & 0 deletions lambda-buffers-frontend/.envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use flake ..#dev-frontend
26 changes: 26 additions & 0 deletions lambda-buffers-frontend/app/LambdaBuffers/Frontend/Cli/Compile.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module LambdaBuffers.Frontend.Cli.Compile (CompileOpts (..), compile) where

import Control.Lens (makeLenses, (^.))
import Data.Map qualified as Map
import LambdaBuffers.Frontend (runFrontend)
import LambdaBuffers.Frontend.PPrint ()
import Prettyprinter (Pretty (pretty))
import Proto.Compiler ()

data CompileOpts = CompileOpts
{ _importPaths :: [FilePath]
, _moduleFilepath :: FilePath
}
deriving stock (Eq, Show)

makeLenses ''CompileOpts

-- | Compile a filepath containing a LambdaBuffers module
compile :: CompileOpts -> IO ()
compile opts = do
errOrMod <- runFrontend (opts ^. importPaths) (opts ^. moduleFilepath)
case errOrMod of
Left err -> print err
Right mods -> do
putStrLn "OK"
putStrLn $ "Compiler closure contains the following modules: " <> (show . pretty . Map.elems $ mods)
29 changes: 29 additions & 0 deletions lambda-buffers-frontend/app/LambdaBuffers/Frontend/Cli/Format.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module LambdaBuffers.Frontend.Cli.Format (FormatOpts (..), format) where

import Control.Lens (makeLenses, (^.))
import Data.Text.IO qualified as Text
import LambdaBuffers.Frontend.PPrint ()
import LambdaBuffers.Frontend.Parsec qualified as Parsec
import Prettyprinter (Pretty (pretty))
import Proto.Compiler ()

data FormatOpts = FormatOpts
{ _moduleFilepath :: FilePath
, _inPlace :: Bool
}
deriving stock (Eq, Show)

makeLenses ''FormatOpts

-- | Format a LambdaBuffers file
format :: FormatOpts -> IO ()
format opts = do
modContent <- Text.readFile (opts ^. moduleFilepath)
modOrErr <- Parsec.runParser Parsec.parseModule (opts ^. moduleFilepath) modContent
case modOrErr of
Left err -> print err
Right m -> do
let formatted = show . pretty $ m
if opts ^. inPlace
then Prelude.writeFile (opts ^. moduleFilepath) formatted
else Prelude.putStrLn formatted
Loading