Skip to content
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

Basic Geb integration #1748

Merged
merged 20 commits into from
Feb 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions app/Commands/Dev/Asm/Compile.hs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ runCommand opts = do
TargetWasm32Wasi -> Backend.TargetCWasm32Wasi
TargetNative64 -> Backend.TargetCNative64
TargetC -> Backend.TargetCWasm32Wasi
TargetGeb -> error "GEB target not supported for JuvixAsm"

inputCFile :: (Members '[App] r) => Path Abs File -> Sem r (Path Abs File)
inputCFile inputFileCompile = do
Expand Down
54 changes: 41 additions & 13 deletions app/Commands/Dev/Core/Compile.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,65 @@ import Data.Text.IO qualified as TIO
import Juvix.Compiler.Asm.Options qualified as Asm
import Juvix.Compiler.Backend qualified as Backend
import Juvix.Compiler.Backend.C qualified as C
import Juvix.Compiler.Backend.Geb qualified as Geb
import Juvix.Compiler.Core.Data.InfoTable qualified as Core
import Juvix.Compiler.Core.Translation.FromSource qualified as Core

data PipelineArg = PipelineArg
{ _pipelineArgOptions :: CoreCompileOptions,
_pipelineArgFile :: Path Abs File,
_pipelineArgInfoTable :: Core.InfoTable
}

makeLenses ''PipelineArg

runCommand :: forall r. (Members '[Embed IO, App] r) => CoreCompileOptions -> Sem r ()
runCommand opts = do
file <- getFile
s <- embed (readFile (toFilePath file))
tab <- getRight (mapLeft JuvixError (Core.runParserMain file Core.emptyInfoTable s))
C.MiniCResult {..} <- getRight (run (runError (coreToMiniC asmOpts tab :: Sem '[Error JuvixError] C.MiniCResult)))
buildDir <- askBuildDir
ensureDir buildDir
cFile <- inputCFile file
embed $ TIO.writeFile (toFilePath cFile) _resultCCode
Compile.runCommand opts {_compileInputFile = AppPath (Abs cFile) False}
case opts ^. compileTarget of
TargetGeb -> runGebPipeline (PipelineArg opts file tab)
TargetWasm32Wasi -> runCPipeline (PipelineArg opts file tab)
TargetNative64 -> runCPipeline (PipelineArg opts file tab)
TargetC -> runCPipeline (PipelineArg opts file tab)
where
getFile :: Sem r (Path Abs File)
getFile = someBaseToAbs' (opts ^. compileInputFile . pathPath)

runCPipeline ::
forall r.
(Members '[Embed IO, App] r) =>
PipelineArg ->
Sem r ()
runCPipeline PipelineArg {..} = do
C.MiniCResult {..} <- getRight (run (runError (coreToMiniC asmOpts _pipelineArgInfoTable :: Sem '[Error JuvixError] C.MiniCResult)))
cFile <- inputFile _pipelineArgFile ".c"
embed $ TIO.writeFile (toFilePath cFile) _resultCCode
Compile.runCommand _pipelineArgOptions {_compileInputFile = AppPath (Abs cFile) False}
where
asmOpts :: Asm.Options
asmOpts = Asm.makeOptions (asmTarget (opts ^. compileTarget)) (opts ^. compileDebug)
asmOpts = Asm.makeOptions (asmTarget (_pipelineArgOptions ^. compileTarget)) (_pipelineArgOptions ^. compileDebug)

asmTarget :: CompileTarget -> Backend.Target
asmTarget = \case
TargetWasm32Wasi -> Backend.TargetCWasm32Wasi
TargetNative64 -> Backend.TargetCNative64
TargetC -> Backend.TargetCWasm32Wasi
TargetGeb -> impossible

runGebPipeline ::
forall r.
(Members '[Embed IO, App] r) =>
PipelineArg ->
Sem r ()
runGebPipeline PipelineArg {..} = do
Geb.Result {..} <- getRight (run (runError (coreToGeb _pipelineArgInfoTable :: Sem '[Error JuvixError] Geb.Result)))
gebFile <- inputFile _pipelineArgFile ".geb"
embed $ TIO.writeFile (toFilePath gebFile) _resultCode

inputCFile :: (Members '[App] r) => Path Abs File -> Sem r (Path Abs File)
inputCFile inputFileCompile = do
inputFile :: (Members '[Embed IO, App] r) => Path Abs File -> String -> Sem r (Path Abs File)
inputFile inputFileCompile ext = do
buildDir <- askBuildDir
return (buildDir <//> outputMiniCFile)
where
outputMiniCFile :: Path Rel File
outputMiniCFile = replaceExtension' ".c" (filename inputFileCompile)
ensureDir buildDir
return (buildDir <//> replaceExtension' ext (filename inputFileCompile))
2 changes: 2 additions & 0 deletions app/Commands/Extra/Compile.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ runCompile inputFile o = do
TargetWasm32Wasi -> runError (clangWasmWasiCompile inputFile o)
TargetNative64 -> runError (clangNativeCompile inputFile o)
TargetC -> return $ Right ()
TargetGeb -> return $ Right ()

prepareRuntime :: forall r. (Members '[App, Embed IO] r) => Path Abs Dir -> CompileOptions -> Sem r ()
prepareRuntime buildDir o = do
Expand All @@ -40,6 +41,7 @@ prepareRuntime buildDir o = do
TargetNative64 | o ^. compileDebug -> writeRuntime nativeDebugRuntime
TargetNative64 -> writeRuntime nativeReleaseRuntime
TargetC -> return ()
TargetGeb -> return ()
where
wasiReleaseRuntime :: BS.ByteString
wasiReleaseRuntime = $(FE.makeRelativeToProject "runtime/_build.wasm32-wasi/libjuvix.a" >>= FE.embedFile)
Expand Down
6 changes: 5 additions & 1 deletion app/Commands/Extra/Compile/Options.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ data CompileTarget
= TargetWasm32Wasi
| TargetNative64
| TargetC
| TargetGeb
deriving stock (Show, Data)

data CompileOptions = CompileOptions
Expand Down Expand Up @@ -54,17 +55,20 @@ optCompileTarget =
<> metavar "TARGET"
<> value TargetNative64
<> showDefaultWith targetShow
<> help "select a target: wasm32-wasi, native, c"
<> help "select a target: wasm32-wasi, native, c, geb"
)
where
parseTarget :: String -> Either String CompileTarget
parseTarget = \case
"wasm32-wasi" -> Right TargetWasm32Wasi
"native" -> Right TargetNative64
"c" -> Right TargetC
"geb" -> Right TargetGeb
s -> Left $ "unrecognised target: " <> s

targetShow :: CompileTarget -> String
targetShow = \case
TargetWasm32Wasi -> "wasm32-wasi"
TargetNative64 -> "native"
TargetC -> "c"
TargetGeb -> "geb"
4 changes: 3 additions & 1 deletion cntlines.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
RUNTIME=`find runtime/src/ -name '*.c' -or -name '*.h' | xargs wc -l | tail -1 | tr -d ' toal'`

BACKENDC=`find src/Juvix/Compiler/Backend/C/ -name '*.hs' | xargs wc -l | tail -1 | tr -d ' toal'`
GEB=`find src/Juvix/Compiler/Backend/Geb/ -name '*.hs' | xargs wc -l | tail -1 | tr -d ' toal'`
REG=`find src/Juvix/Compiler/Reg/ -name '*.hs' -print | xargs wc -l | tail -1 | tr -d ' toal'`
ASM=`find src/Juvix/Compiler/Asm/ -name '*.hs' -print | xargs wc -l | tail -1 | tr -d ' toal'`
CORE=`find src/Juvix/Compiler/Core/ -name '*.hs' -print | xargs wc -l | tail -1 | tr -d ' toal'`
Expand All @@ -20,7 +21,7 @@ DATA=`find src/Juvix/Data/ -name '*.hs' | xargs wc -l | tail -1 | tr -d ' toal'`
PRELUDE=`find src/Juvix/Prelude/ -name '*.hs' | xargs wc -l | tail -1 | tr -d ' toal'`

FRONT=$((CONCRETE + ABSTRACT + INTERNAL + BUILTINS + PIPELINE))
BACK=$((BACKENDC + REG + ASM + CORE))
BACK=$((BACKENDC + GEB + REG + ASM + CORE))
OTHER=$((APP + HTML + EXTRA + DATA + PRELUDE))

echo "Front end: $FRONT LOC"
Expand All @@ -31,6 +32,7 @@ echo " Builtins: $BUILTINS LOC"
echo " Pipeline: $PIPELINE LOC"
echo "Middle and back end: $BACK LOC"
echo " C backend: $BACKENDC LOC"
echo " GEB backend: $GEB LOC"
echo " JuvixReg: $REG LOC"
echo " JuvixAsm: $ASM LOC"
echo " JuvixCore: $CORE LOC"
Expand Down
6 changes: 0 additions & 6 deletions src/Juvix/Compiler/Asm/Pretty/Base.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ doc opts =
class PrettyCode c where
ppCode :: (Member (Reader Options) r) => c -> Sem r (Doc Ann)

runPrettyCode :: (PrettyCode c) => Options -> c -> Doc Ann
runPrettyCode opts = run . runReader opts . ppCode

wrapCore ::
forall r' c.
(Member (Reader Options) r') =>
Expand Down Expand Up @@ -373,9 +370,6 @@ instance PrettyCode InfoTable where
{--------------------------------------------------------------------------------}
{- helper functions -}

parensIf :: Bool -> Doc Ann -> Doc Ann
parensIf t = if t then parens else id

braces' :: Doc Ann -> Doc Ann
braces' d = braces (line <> indent' d <> line)

Expand Down
4 changes: 4 additions & 0 deletions src/Juvix/Compiler/Backend/Geb.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Juvix.Compiler.Backend.Geb (module Juvix.Compiler.Backend.Geb.Language, module Juvix.Compiler.Backend.Geb.Translation) where

import Juvix.Compiler.Backend.Geb.Language
import Juvix.Compiler.Backend.Geb.Translation
10 changes: 10 additions & 0 deletions src/Juvix/Compiler/Backend/Geb/Extra.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module Juvix.Compiler.Backend.Geb.Extra where

import Juvix.Compiler.Backend.Geb.Language

-- | Destructs a product in a right-associative way, e.g., (a, (b, c)) is
-- destructed to [a, b, c]
destructProduct :: Object -> [Object]
destructProduct = \case
ObjectProduct Product {..} -> _productLeft : destructProduct _productRight
x -> [x]
137 changes: 137 additions & 0 deletions src/Juvix/Compiler/Backend/Geb/Language.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
module Juvix.Compiler.Backend.Geb.Language
( module Juvix.Compiler.Backend.Geb.Language,
module Juvix.Prelude,
)
where

import Juvix.Prelude hiding (First, Product)

{-
The following datatypes correspond to GEB types for terms
(https://github.com/anoma/geb/blob/main/src/specs/lambda.lisp) and types
(https://github.com/anoma/geb/blob/main/src/specs/geb.lisp).
-}

-- | Represents GEB's `case-on`. `_caseOn` is the value matched on of type
-- `Dom`, `_caseLeft` has type `_caseLeftType -> _caseCodomainType` and
-- `_caseRight` has type `_caseRightType -> _caseCodomainType`.
data Case = Case
{ _caseLeftType :: Object,
_caseRightType :: Object,
_caseCodomainType :: Object,
_caseOn :: Morphism,
_caseLeft :: Morphism,
_caseRight :: Morphism
}

data Pair = Pair
{ _pairLeftType :: Object,
_pairRightType :: Object,
_pairLeft :: Morphism,
_pairRight :: Morphism
}

data First = First
{ _firstLeftType :: Object,
_firstRightType :: Object,
_firstValue :: Morphism
}

data Second = Second
{ _secondLeftType :: Object,
_secondRightType :: Object,
_secondValue :: Morphism
}

data Lambda = Lambda
{ _lambdaVarType :: Object,
_lambdaBodyType :: Object,
_lambdaBody :: Morphism
}

janmasrovira marked this conversation as resolved.
Show resolved Hide resolved
data Application = Application
{ _applicationDomainType :: Object,
_applicationCodomainType :: Object,
_applicationLeft :: Morphism,
_applicationRight :: Morphism
}

newtype Var = Var {_varIndex :: Int}

-- | Corresponds to the GEB type for morphisms (terms): `stlc`
-- (https://github.com/anoma/geb/blob/main/src/specs/lambda.lisp).
data Morphism
= MorphismAbsurd Morphism
| MorphismUnit
| MorphismLeft Morphism
| MorphismRight Morphism
| MorphismCase Case
| MorphismPair Pair
| MorphismFirst First
| MorphismSecond Second
| MorphismLambda Lambda
| MorphismApplication Application
| MorphismVar Var

data Product = Product
{ _productLeft :: Object,
_productRight :: Object
}

data Coproduct = Coproduct
{ _coproductLeft :: Object,
_coproductRight :: Object
}

-- | Function type
data Hom = Hom
{ _homDomain :: Object,
_homCodomain :: Object
}

-- | Corresponds to the GEB type for types (objects of the category): `substobj`
-- (https://github.com/anoma/geb/blob/main/src/specs/geb.lisp).
data Object
= -- | empty type
ObjectInitial
| -- | unit type
ObjectTerminal
| ObjectProduct Product
| ObjectCoproduct Coproduct
| -- | function type
ObjectHom Hom

instance HasAtomicity Morphism where
atomicity = \case
MorphismAbsurd {} -> Aggregate appFixity
MorphismUnit -> Atom
MorphismLeft {} -> Aggregate appFixity
MorphismRight {} -> Aggregate appFixity
MorphismCase {} -> Aggregate appFixity
MorphismPair {} -> Aggregate appFixity
MorphismFirst {} -> Aggregate appFixity
MorphismSecond {} -> Aggregate appFixity
MorphismLambda {} -> Aggregate appFixity
MorphismApplication {} -> Aggregate appFixity
MorphismVar {} -> Aggregate appFixity

instance HasAtomicity Object where
atomicity = \case
ObjectInitial -> Atom
ObjectTerminal -> Atom
ObjectProduct {} -> Aggregate appFixity
ObjectCoproduct {} -> Aggregate appFixity
ObjectHom {} -> Aggregate appFixity

makeLenses ''Case
makeLenses ''Pair
makeLenses ''First
makeLenses ''Second
makeLenses ''Lambda
makeLenses ''Var
makeLenses ''Application
makeLenses ''Morphism
makeLenses ''Product
makeLenses ''Coproduct
makeLenses ''Hom
makeLenses ''Object
28 changes: 28 additions & 0 deletions src/Juvix/Compiler/Backend/Geb/Pretty.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module Juvix.Compiler.Backend.Geb.Pretty
( module Juvix.Compiler.Backend.Geb.Pretty,
module Juvix.Compiler.Backend.Geb.Pretty.Base,
module Juvix.Compiler.Backend.Geb.Pretty.Options,
module Juvix.Data.PPOutput,
)
where

import Juvix.Compiler.Backend.Geb.Pretty.Base
import Juvix.Compiler.Backend.Geb.Pretty.Options
import Juvix.Data.PPOutput
import Juvix.Prelude
import Prettyprinter.Render.Terminal qualified as Ansi

ppOutDefault :: (HasAtomicity c, PrettyCode c) => c -> AnsiText
ppOutDefault = AnsiText . PPOutput . doc defaultOptions

ppOut :: (CanonicalProjection a Options, HasAtomicity c, PrettyCode c) => a -> c -> AnsiText
ppOut o = AnsiText . PPOutput . doc (project o)

ppTrace' :: (CanonicalProjection a Options, HasAtomicity c, PrettyCode c) => a -> c -> Text
ppTrace' opts = Ansi.renderStrict . reAnnotateS stylize . layoutPretty defaultLayoutOptions . doc (project opts)

ppTrace :: (HasAtomicity c, PrettyCode c) => c -> Text
ppTrace = ppTrace' traceOptions

ppPrint :: (HasAtomicity c, PrettyCode c) => c -> Text
ppPrint = show . ppOutDefault
Loading