mirror of
https://github.com/anoma/juvix.git
synced 2024-10-05 20:47:36 +03:00
Rust backend (#2787)
* Implements code generation through Rust. * CLI: adds two `dev` compilation targets: 1. `rust` for generating Rust code 2. `native-rust` for generating a native executable via Rust * Adds end-to-end tests for compilation from Juvix to native executable via Rust. * A target for RISC0 needs to be added in a separate PR building on this one.
This commit is contained in:
parent
9faa88d4da
commit
55598e0f95
@ -4,8 +4,10 @@ import Commands.Base
|
||||
import Commands.Dev.DevCompile.Asm qualified as Asm
|
||||
import Commands.Dev.DevCompile.Casm qualified as Casm
|
||||
import Commands.Dev.DevCompile.Core qualified as Core
|
||||
import Commands.Dev.DevCompile.NativeRust qualified as NativeRust
|
||||
import Commands.Dev.DevCompile.Options
|
||||
import Commands.Dev.DevCompile.Reg qualified as Reg
|
||||
import Commands.Dev.DevCompile.Rust qualified as Rust
|
||||
import Commands.Dev.DevCompile.Tree qualified as Tree
|
||||
|
||||
runCommand :: (Members '[App, EmbedIO, TaggedLock] r) => DevCompileCommand -> Sem r ()
|
||||
@ -15,3 +17,5 @@ runCommand = \case
|
||||
Asm opts -> Asm.runCommand opts
|
||||
Tree opts -> Tree.runCommand opts
|
||||
Casm opts -> Casm.runCommand opts
|
||||
Rust opts -> Rust.runCommand opts
|
||||
NativeRust opts -> NativeRust.runCommand opts
|
||||
|
75
app/Commands/Dev/DevCompile/NativeRust.hs
Normal file
75
app/Commands/Dev/DevCompile/NativeRust.hs
Normal file
@ -0,0 +1,75 @@
|
||||
module Commands.Dev.DevCompile.NativeRust where
|
||||
|
||||
import Commands.Base
|
||||
import Commands.Dev.DevCompile.NativeRust.Options
|
||||
import Commands.Extra.Rust
|
||||
import Data.ByteString qualified as BS
|
||||
import Data.FileEmbed qualified as FE
|
||||
import Juvix.Compiler.Backend.Rust.Data.Result
|
||||
|
||||
runCommand ::
|
||||
(Members '[App, EmbedIO, TaggedLock] r) =>
|
||||
NativeRustOptions 'InputMain ->
|
||||
Sem r ()
|
||||
runCommand opts = do
|
||||
let opts' = opts ^. nativeRustCompileCommonOptions
|
||||
inputFile = opts' ^. compileInputFile
|
||||
moutputFile = opts' ^. compileOutputFile
|
||||
mainFile <- getMainFile inputFile
|
||||
Result {..} <- runPipeline opts inputFile upToRust
|
||||
rustFile <- inputRustFile mainFile
|
||||
writeFileEnsureLn rustFile _resultRustCode
|
||||
buildDir <- askBuildDir
|
||||
ensureDir buildDir
|
||||
prepareRuntime
|
||||
outputFile <- nativeOutputFile mainFile moutputFile
|
||||
let args =
|
||||
RustArgs
|
||||
{ _rustDebug = opts' ^. compileDebug,
|
||||
_rustInputFile = rustFile,
|
||||
_rustOutputFile = outputFile,
|
||||
_rustOptimizationLevel = fmap (min 3 . (+ 1)) (opts' ^. compileOptimizationLevel)
|
||||
}
|
||||
rustCompile args
|
||||
where
|
||||
prepareRuntime ::
|
||||
forall s.
|
||||
(Members '[App, EmbedIO] s) =>
|
||||
Sem s ()
|
||||
prepareRuntime = writeRuntime runtime
|
||||
where
|
||||
runtime :: BS.ByteString
|
||||
runtime
|
||||
| opts ^. nativeRustCompileCommonOptions . compileDebug = rustDebugRuntime
|
||||
| otherwise = rustReleaseRuntime
|
||||
where
|
||||
rustReleaseRuntime :: BS.ByteString
|
||||
rustReleaseRuntime = $(FE.makeRelativeToProject "runtime/rust/target/release/libjuvix.rlib" >>= FE.embedFile)
|
||||
|
||||
rustDebugRuntime :: BS.ByteString
|
||||
rustDebugRuntime = $(FE.makeRelativeToProject "runtime/rust/target/debug/libjuvix.rlib" >>= FE.embedFile)
|
||||
|
||||
inputRustFile :: (Members '[App, EmbedIO] r) => Path Abs File -> Sem r (Path Abs File)
|
||||
inputRustFile inputFileCompile = do
|
||||
buildDir <- askBuildDir
|
||||
ensureDir buildDir
|
||||
return (buildDir <//> replaceExtension' ".rs" (filename inputFileCompile))
|
||||
|
||||
nativeOutputFile :: forall r. (Member App r) => Path Abs File -> Maybe (AppPath File) -> Sem r (Path Abs File)
|
||||
nativeOutputFile inputFile moutputFile =
|
||||
case moutputFile of
|
||||
Just f -> fromAppFile f
|
||||
Nothing -> do
|
||||
invokeDir <- askInvokeDir
|
||||
let baseOutputFile = invokeDir <//> filename inputFile
|
||||
return $ removeExtension' baseOutputFile
|
||||
|
||||
writeRuntime ::
|
||||
forall r.
|
||||
(Members '[App, EmbedIO] r) =>
|
||||
BS.ByteString ->
|
||||
Sem r ()
|
||||
writeRuntime runtime = do
|
||||
buildDir <- askBuildDir
|
||||
liftIO $
|
||||
BS.writeFile (toFilePath (buildDir <//> $(mkRelFile "libjuvix.rlib"))) runtime
|
28
app/Commands/Dev/DevCompile/NativeRust/Options.hs
Normal file
28
app/Commands/Dev/DevCompile/NativeRust/Options.hs
Normal file
@ -0,0 +1,28 @@
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
|
||||
module Commands.Dev.DevCompile.NativeRust.Options
|
||||
( module Commands.Dev.DevCompile.NativeRust.Options,
|
||||
module Commands.Compile.CommonOptions,
|
||||
)
|
||||
where
|
||||
|
||||
import Commands.Compile.CommonOptions
|
||||
import CommonOptions
|
||||
|
||||
data NativeRustOptions (k :: InputKind) = NativeRustOptions
|
||||
{ _nativeRustCompileCommonOptions :: CompileCommonOptions k
|
||||
}
|
||||
|
||||
deriving stock instance (Typeable k, Data (InputFileType k)) => Data (NativeRustOptions k)
|
||||
|
||||
makeLenses ''NativeRustOptions
|
||||
|
||||
parseNativeRust :: (SingI k) => Parser (NativeRustOptions k)
|
||||
parseNativeRust = do
|
||||
_nativeRustCompileCommonOptions <- parseCompileCommonOptions
|
||||
pure NativeRustOptions {..}
|
||||
|
||||
instance EntryPointOptions (NativeRustOptions k) where
|
||||
applyOptions opts =
|
||||
set entryPointTarget (Just TargetRust)
|
||||
. applyOptions (opts ^. nativeRustCompileCommonOptions)
|
@ -3,7 +3,9 @@ module Commands.Dev.DevCompile.Options where
|
||||
import Commands.Dev.DevCompile.Asm.Options
|
||||
import Commands.Dev.DevCompile.Casm.Options
|
||||
import Commands.Dev.DevCompile.Core.Options
|
||||
import Commands.Dev.DevCompile.NativeRust.Options
|
||||
import Commands.Dev.DevCompile.Reg.Options
|
||||
import Commands.Dev.DevCompile.Rust.Options
|
||||
import Commands.Dev.DevCompile.Tree.Options
|
||||
import CommonOptions
|
||||
|
||||
@ -13,6 +15,8 @@ data DevCompileCommand
|
||||
| Reg (RegOptions 'InputMain)
|
||||
| Tree (TreeOptions 'InputMain)
|
||||
| Casm (CasmOptions 'InputMain)
|
||||
| Rust (RustOptions 'InputMain)
|
||||
| NativeRust (NativeRustOptions 'InputMain)
|
||||
deriving stock (Data)
|
||||
|
||||
parseDevCompileCommand :: Parser DevCompileCommand
|
||||
@ -23,7 +27,9 @@ parseDevCompileCommand =
|
||||
commandReg,
|
||||
commandTree,
|
||||
commandCasm,
|
||||
commandAsm
|
||||
commandAsm,
|
||||
commandRust,
|
||||
commandNativeRust
|
||||
]
|
||||
)
|
||||
|
||||
@ -61,3 +67,17 @@ commandAsm =
|
||||
info
|
||||
(Asm <$> parseAsm)
|
||||
(progDesc "Compile to Juvix ASM")
|
||||
|
||||
commandRust :: Mod CommandFields DevCompileCommand
|
||||
commandRust =
|
||||
command "rust" $
|
||||
info
|
||||
(Rust <$> parseRust)
|
||||
(progDesc "Compile to Rust")
|
||||
|
||||
commandNativeRust :: Mod CommandFields DevCompileCommand
|
||||
commandNativeRust =
|
||||
command "native-rust" $
|
||||
info
|
||||
(NativeRust <$> parseNativeRust)
|
||||
(progDesc "Compile to native executable through Rust")
|
||||
|
17
app/Commands/Dev/DevCompile/Rust.hs
Normal file
17
app/Commands/Dev/DevCompile/Rust.hs
Normal file
@ -0,0 +1,17 @@
|
||||
module Commands.Dev.DevCompile.Rust where
|
||||
|
||||
import Commands.Base
|
||||
import Commands.Dev.DevCompile.Rust.Options
|
||||
import Commands.Extra.NewCompile
|
||||
import Juvix.Compiler.Backend.Rust.Data.Result
|
||||
|
||||
runCommand ::
|
||||
(Members '[App, EmbedIO, TaggedLock] r) =>
|
||||
RustOptions 'InputMain ->
|
||||
Sem r ()
|
||||
runCommand opts = do
|
||||
let inputFile = opts ^. rustCompileCommonOptions . compileInputFile
|
||||
moutputFile = opts ^. rustCompileCommonOptions . compileOutputFile
|
||||
outFile :: Path Abs File <- getOutputFile FileExtRust inputFile moutputFile
|
||||
Result {..} <- runPipeline opts inputFile upToRust
|
||||
writeFileEnsureLn outFile _resultRustCode
|
28
app/Commands/Dev/DevCompile/Rust/Options.hs
Normal file
28
app/Commands/Dev/DevCompile/Rust/Options.hs
Normal file
@ -0,0 +1,28 @@
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
|
||||
module Commands.Dev.DevCompile.Rust.Options
|
||||
( module Commands.Dev.DevCompile.Rust.Options,
|
||||
module Commands.Compile.CommonOptions,
|
||||
)
|
||||
where
|
||||
|
||||
import Commands.Compile.CommonOptions
|
||||
import CommonOptions
|
||||
|
||||
data RustOptions (k :: InputKind) = RustOptions
|
||||
{ _rustCompileCommonOptions :: CompileCommonOptions k
|
||||
}
|
||||
|
||||
deriving stock instance (Typeable k, Data (InputFileType k)) => Data (RustOptions k)
|
||||
|
||||
makeLenses ''RustOptions
|
||||
|
||||
parseRust :: (SingI k) => Parser (RustOptions k)
|
||||
parseRust = do
|
||||
_rustCompileCommonOptions <- parseCompileCommonOptions
|
||||
pure RustOptions {..}
|
||||
|
||||
instance EntryPointOptions (RustOptions k) where
|
||||
applyOptions opts =
|
||||
set entryPointTarget (Just TargetRust)
|
||||
. applyOptions (opts ^. rustCompileCommonOptions)
|
87
app/Commands/Extra/Rust.hs
Normal file
87
app/Commands/Extra/Rust.hs
Normal file
@ -0,0 +1,87 @@
|
||||
module Commands.Extra.Rust where
|
||||
|
||||
import Commands.Base
|
||||
import System.Process qualified as P
|
||||
|
||||
data RustArgs = RustArgs
|
||||
{ _rustDebug :: Bool,
|
||||
_rustInputFile :: Path Abs File,
|
||||
_rustOutputFile :: Path Abs File,
|
||||
_rustOptimizationLevel :: Maybe Int
|
||||
}
|
||||
|
||||
makeLenses ''RustArgs
|
||||
|
||||
rustCompile ::
|
||||
forall r.
|
||||
(Members '[App, EmbedIO] r) =>
|
||||
RustArgs ->
|
||||
Sem r ()
|
||||
rustCompile args = do
|
||||
getRustcCliArgs args >>= runRustc
|
||||
|
||||
getRustcCliArgs :: (Members '[App, EmbedIO] r) => RustArgs -> Sem r [String]
|
||||
getRustcCliArgs args = do
|
||||
buildDir <- askBuildDir
|
||||
return (nativeArgs buildDir args)
|
||||
|
||||
nativeArgs :: Path Abs Dir -> RustArgs -> [String]
|
||||
nativeArgs buildDir args@RustArgs {..} =
|
||||
commonArgs buildDir args ++ extraArgs
|
||||
where
|
||||
extraArgs :: [String]
|
||||
extraArgs = run . execAccumList $ do
|
||||
addOptimizationOption args
|
||||
addArg (toFilePath _rustInputFile)
|
||||
|
||||
addOptimizationOption :: (Member (Accum String) r) => RustArgs -> Sem r ()
|
||||
addOptimizationOption args = do
|
||||
addArg "-C"
|
||||
addArg $ "opt-level=" <> show (maybe defaultOptLevel (max 1) (args ^. rustOptimizationLevel))
|
||||
where
|
||||
defaultOptLevel :: Int
|
||||
defaultOptLevel
|
||||
| args ^. rustDebug = debugRustOptimizationLevel
|
||||
| otherwise = defaultRustOptimizationLevel
|
||||
|
||||
debugRustOptimizationLevel :: Int
|
||||
debugRustOptimizationLevel = 1
|
||||
|
||||
defaultRustOptimizationLevel :: Int
|
||||
defaultRustOptimizationLevel = 3
|
||||
|
||||
addArg :: (Member (Accum String) r) => String -> Sem r ()
|
||||
addArg = accum
|
||||
|
||||
commonArgs :: Path Abs Dir -> RustArgs -> [String]
|
||||
commonArgs buildDir RustArgs {..} = run . execAccumList $ do
|
||||
when _rustDebug $ do
|
||||
addArg "-g"
|
||||
addArg "-C"
|
||||
addArg "debug-assertions=true"
|
||||
addArg "-C"
|
||||
addArg "overflow-checks=true"
|
||||
addArg "-o"
|
||||
addArg (toFilePath _rustOutputFile)
|
||||
addArg ("-L")
|
||||
addArg (toFilePath buildDir)
|
||||
|
||||
runRustc ::
|
||||
forall r.
|
||||
(Members '[App, EmbedIO] r) =>
|
||||
[String] ->
|
||||
Sem r ()
|
||||
runRustc args = do
|
||||
cp <- rustcBinPath
|
||||
(exitCode, _, err) <- liftIO (P.readProcessWithExitCode cp args "")
|
||||
case exitCode of
|
||||
ExitSuccess -> return ()
|
||||
_ -> exitFailMsg (pack err)
|
||||
where
|
||||
rustcBinPath :: Sem r String
|
||||
rustcBinPath = do
|
||||
p <- findExecutable $(mkRelFile "rustc")
|
||||
maybe (exitFailMsg rustcNotFoundErr) (return . toFilePath) p
|
||||
|
||||
rustcNotFoundErr :: Text
|
||||
rustcNotFoundErr = "Error: The rustc executable was not found. Please install the Rust compiler"
|
@ -17,6 +17,7 @@ RUNTIME_CASM=$(count_ext '*.casm' runtime/casm)
|
||||
RUNTIME=$((RUNTIME_C+RUNTIME_RUST+RUNTIME_VAMPIR+RUNTIME_JVT+RUNTIME_CASM))
|
||||
|
||||
BACKENDC=$(count src/Juvix/Compiler/Backend/C/)
|
||||
BACKENDRUST=$(count src/Juvix/Compiler/Backend/Rust/)
|
||||
CAIRO=$(count src/Juvix/Compiler/Backend/Cairo/)
|
||||
GEB=$(count src/Juvix/Compiler/Backend/Geb/)
|
||||
VAMPIR=$(count src/Juvix/Compiler/Backend/VampIR/)
|
||||
@ -40,7 +41,7 @@ PRELUDE=$(count src/Juvix/Prelude/)
|
||||
STORE=$(count src/Juvix/Compiler/Store/)
|
||||
|
||||
FRONT=$((CONCRETE + INTERNAL + BUILTINS + PIPELINE))
|
||||
BACK=$((BACKENDC + GEB + VAMPIR + NOCK + REG + ASM + TREE + CORE + CASM + CAIRO))
|
||||
BACK=$((BACKENDC + BACKENDRUST + GEB + VAMPIR + NOCK + REG + ASM + TREE + CORE + CASM + CAIRO))
|
||||
OTHER=$((APP + STORE + HTML + EXTRA + DATA + PRELUDE))
|
||||
TESTS=$(count test/)
|
||||
|
||||
@ -55,6 +56,7 @@ echo "Middle and back end: $BACK LOC"
|
||||
echo " VampIR backend: $VAMPIR LOC"
|
||||
echo " GEB backend: $GEB LOC"
|
||||
echo " C backend: $BACKENDC LOC"
|
||||
echo " Rust backend: $BACKENDRUST LOC"
|
||||
echo " Cairo backend: $((CASM + CAIRO)) LOC"
|
||||
echo " Nockma backend: $NOCK LOC"
|
||||
echo " JuvixReg: $REG LOC"
|
||||
|
@ -38,6 +38,7 @@ extra-source-files:
|
||||
- include/package-base/**/*.juvix
|
||||
- runtime/c/include/**/*.h
|
||||
- runtime/c/**/*.a
|
||||
- runtime/rust/target/**/*.rlib
|
||||
- runtime/tree/*.jvt
|
||||
- runtime/vampir/*.pir
|
||||
- runtime/casm/*.casm
|
||||
|
@ -10,7 +10,7 @@ juvix_c:
|
||||
|
||||
.PHONY: juvix_rust
|
||||
juvix_rust:
|
||||
cd rust && cargo build --release
|
||||
cd rust && cargo build && cargo build --release
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
|
@ -29,11 +29,11 @@ impl Memory {
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! tapply {
|
||||
($lab:lifetime, $program:ident, $mem:ident, $fid:ident, $args:ident, $cl0:expr, $cargs0:expr) => {
|
||||
($lab:lifetime, $program:ident, $mem:ident, $fid:ident, $args:ident, $cl0:expr, $cargs0:expr) => {{
|
||||
let mut cl = $cl0;
|
||||
let mut cargs = $cargs0;
|
||||
loop {
|
||||
match $mem.apply( cl, &cargs) {
|
||||
match $mem.apply(cl, &cargs) {
|
||||
apply::AppResult::Call(fid1, args1) => {
|
||||
$fid = fid1;
|
||||
$args = args1;
|
||||
@ -46,7 +46,7 @@ macro_rules! tapply {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
@ -30,8 +30,8 @@ impl Memory {
|
||||
p
|
||||
}
|
||||
|
||||
// Assigns stored closure args plus the provided closure args (`cargs`) to the
|
||||
// argument space (`args`). Returns the function id to call.
|
||||
// Returns the function id to call and the full arguments for closure call:
|
||||
// stored closure args plus the provided closure args (`cargs`).
|
||||
pub fn call_closure(self: &Memory, cl: Word, cargs: &[Word]) -> (Word, Vec<Word>) {
|
||||
let mut args = Vec::from(self.get_closure_args(cl));
|
||||
args.extend(cargs);
|
||||
|
@ -12,6 +12,11 @@ pub type SmallInt = i32;
|
||||
pub const INITIAL_STACK_CAPACITY: usize = 10 * 1024;
|
||||
pub const INITIAL_MEMORY_CAPACITY: usize = 10 * 1024;
|
||||
|
||||
pub const BOOL_FALSE: Word = 0;
|
||||
pub const BOOL_TRUE: Word = 1;
|
||||
pub const OBJ_UNIT: Word = 0;
|
||||
pub const OBJ_VOID: Word = 0;
|
||||
|
||||
pub fn word_to_usize(s: Word) -> usize {
|
||||
s as usize
|
||||
}
|
||||
|
@ -4,6 +4,6 @@ use super::defs::*;
|
||||
|
||||
// Check for equality. The implementation is incorrect for complex objects, but
|
||||
// complex objects are not compared in Juvix with built-in equality for now.
|
||||
pub fn juvix_equal(x: Word, y: Word) -> bool {
|
||||
x == y
|
||||
pub fn juvix_equal(x: Word, y: Word) -> Word {
|
||||
bool_to_word(x == y)
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ mod tests {
|
||||
continue;
|
||||
}
|
||||
FUN_ITFIB_GO => {
|
||||
if juvix_equal(args[0], make_smallint(0)) {
|
||||
if word_to_bool(juvix_equal(args[0], make_smallint(0))) {
|
||||
break args[1];
|
||||
} else {
|
||||
args = vec![
|
||||
@ -122,19 +122,19 @@ mod tests {
|
||||
vec![id, id, id, id, id, id, id, id, id, id, id, make_smallint(1)]
|
||||
);
|
||||
let tmp1 = smallint_add(x, y);
|
||||
break smallint_add(tmp1, z);
|
||||
return smallint_add(tmp1, z);
|
||||
}
|
||||
FUN_S => {
|
||||
let xz = apply!(program_sk, mem, args[0], vec![args[2]]);
|
||||
let yz = apply!(program_sk, mem, args[1], vec![args[2]]);
|
||||
tapply!('program, program_sk, mem, fid, args, xz, vec![yz]);
|
||||
tapply!('program, program_sk, mem, fid, args, xz, vec![yz])
|
||||
}
|
||||
FUN_K => {
|
||||
break args[0];
|
||||
return args[0];
|
||||
}
|
||||
FUN_I => {
|
||||
let k = mem.alloc_closure(FUN_K, &[], 2);
|
||||
break mem.alloc_closure(FUN_S, &[k, k], 1);
|
||||
return mem.alloc_closure(FUN_S, &[k, k], 1);
|
||||
}
|
||||
_ => panic!("unknown function id"),
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ data Target
|
||||
| TargetAsm
|
||||
| TargetReg
|
||||
| TargetTree
|
||||
| TargetRust
|
||||
| TargetAnoma
|
||||
| TargetCairo
|
||||
deriving stock (Data, Eq, Show)
|
||||
@ -110,6 +111,21 @@ getLimits tgt debug = case tgt of
|
||||
_limitsBuiltinUIDsNum = 8,
|
||||
_limitsSpecialisedApply = 3
|
||||
}
|
||||
TargetRust ->
|
||||
Limits
|
||||
{ _limitsMaxConstrs = fromIntegral (maxBound :: Int32),
|
||||
_limitsMaxConstrArgs = fromIntegral (maxBound :: Int32),
|
||||
_limitsMaxFunctionArgs = fromIntegral (maxBound :: Int32),
|
||||
_limitsMaxLocalVars = 2048,
|
||||
_limitsMaxClosureSize = fromIntegral (maxBound :: Int32),
|
||||
_limitsClosureHeadSize = 3,
|
||||
_limitsMaxStringSize = 0,
|
||||
_limitsMaxStackDelta = 0,
|
||||
_limitsMaxFunctionAlloc = 0,
|
||||
_limitsDispatchStackSize = 0,
|
||||
_limitsBuiltinUIDsNum = 0,
|
||||
_limitsSpecialisedApply = 0
|
||||
}
|
||||
|
||||
defaultLimits :: Limits
|
||||
defaultLimits =
|
||||
|
9
src/Juvix/Compiler/Backend/Rust/Data/Result.hs
Normal file
9
src/Juvix/Compiler/Backend/Rust/Data/Result.hs
Normal file
@ -0,0 +1,9 @@
|
||||
module Juvix.Compiler.Backend.Rust.Data.Result where
|
||||
|
||||
import Juvix.Prelude
|
||||
|
||||
newtype Result = Result
|
||||
{ _resultRustCode :: Text
|
||||
}
|
||||
|
||||
makeLenses ''Result
|
135
src/Juvix/Compiler/Backend/Rust/Language.hs
Normal file
135
src/Juvix/Compiler/Backend/Rust/Language.hs
Normal file
@ -0,0 +1,135 @@
|
||||
module Juvix.Compiler.Backend.Rust.Language where
|
||||
|
||||
import Juvix.Prelude
|
||||
|
||||
data Program = Program
|
||||
{ _programFunctions :: [Function]
|
||||
}
|
||||
|
||||
data Type
|
||||
= Word
|
||||
| VecOfWord
|
||||
| Memory
|
||||
|
||||
data IsMut
|
||||
= Mut
|
||||
| NotMut
|
||||
|
||||
data FunctionArgument = FunctionArgument
|
||||
{ _functionArgumentMutable :: IsMut,
|
||||
_functionArgumentName :: Text,
|
||||
_functionArgumentType :: Type
|
||||
}
|
||||
|
||||
data Function = Function
|
||||
{ _functionName :: Text,
|
||||
_functionArguments :: [FunctionArgument],
|
||||
_functionReturnType :: Maybe Type,
|
||||
_functionBody :: [Statement],
|
||||
_functionAttributes :: Maybe Text
|
||||
}
|
||||
|
||||
data Statement
|
||||
= StatementLet Let
|
||||
| StatementConst ConstDecl
|
||||
| StatementAssignment Assignment
|
||||
| StatementIf If
|
||||
| StatementMatch Match
|
||||
| StatementLoop Loop
|
||||
| StatementContinue
|
||||
| StatementReturn Return
|
||||
| StatementExpression Expression
|
||||
|
||||
data Let = Let
|
||||
{ _letVariable :: Text,
|
||||
_letType :: Maybe Type,
|
||||
_letMutable :: IsMut,
|
||||
_letInitializer :: Maybe Expression
|
||||
}
|
||||
|
||||
data ConstDecl = ConstDecl
|
||||
{ _constVariable :: Text,
|
||||
_constType :: Type,
|
||||
_constValue :: Expression
|
||||
}
|
||||
|
||||
data Assignment = Assignment
|
||||
{ _assignmentVariable :: Text,
|
||||
_assignmentValue :: Expression
|
||||
}
|
||||
|
||||
data If = If
|
||||
{ _ifValue :: Expression,
|
||||
_ifBranchTrue :: [Statement],
|
||||
_ifBranchFalse :: [Statement]
|
||||
}
|
||||
|
||||
data MatchBranch = MatchBranch
|
||||
{ -- Nothing indicates the wildcard
|
||||
_matchBranchPattern :: Maybe Expression,
|
||||
_matchBranchBody :: [Statement]
|
||||
}
|
||||
|
||||
data Match = Match
|
||||
{ _matchValue :: Expression,
|
||||
_matchBranches :: [MatchBranch]
|
||||
}
|
||||
|
||||
data Loop = Loop
|
||||
{ _loopLabel :: Maybe Text,
|
||||
_loopBody :: [Statement]
|
||||
}
|
||||
|
||||
data Return = Return
|
||||
{ _returnValue :: Maybe Expression
|
||||
}
|
||||
|
||||
data Expression
|
||||
= ExprVar Var
|
||||
| ExprCall Call
|
||||
| ExprVec Vec
|
||||
| ExprArray Array
|
||||
| ExprLiteral Literal
|
||||
| ExprBlock Block
|
||||
| ExprVerbatim Text
|
||||
|
||||
data Var = Var
|
||||
{ _varName :: Text
|
||||
}
|
||||
|
||||
data Call = Call
|
||||
{ _callFunction :: Text,
|
||||
_callArgs :: [Expression]
|
||||
}
|
||||
|
||||
data Vec = Vec
|
||||
{ _vecArgs :: [Expression]
|
||||
}
|
||||
|
||||
data Array = Array
|
||||
{ _arrayArgs :: [Expression]
|
||||
}
|
||||
|
||||
data Block = Block
|
||||
{ _blockBody :: [Statement]
|
||||
}
|
||||
|
||||
data Literal
|
||||
= LitInteger Integer
|
||||
| LitString Text
|
||||
|
||||
makeLenses ''FunctionArgument
|
||||
makeLenses ''Function
|
||||
makeLenses ''Let
|
||||
makeLenses ''ConstDecl
|
||||
makeLenses ''Assignment
|
||||
makeLenses ''MatchBranch
|
||||
makeLenses ''Match
|
||||
makeLenses ''Loop
|
||||
makeLenses ''Return
|
||||
makeLenses ''Var
|
||||
makeLenses ''Call
|
||||
makeLenses ''Vec
|
||||
makeLenses ''Array
|
||||
makeLenses ''Block
|
||||
makeLenses ''Program
|
28
src/Juvix/Compiler/Backend/Rust/Pretty.hs
Normal file
28
src/Juvix/Compiler/Backend/Rust/Pretty.hs
Normal file
@ -0,0 +1,28 @@
|
||||
module Juvix.Compiler.Backend.Rust.Pretty
|
||||
( module Juvix.Compiler.Backend.Rust.Pretty,
|
||||
module Juvix.Compiler.Backend.Rust.Pretty.Base,
|
||||
module Juvix.Compiler.Backend.Rust.Pretty.Options,
|
||||
module Juvix.Data.PPOutput,
|
||||
)
|
||||
where
|
||||
|
||||
import Juvix.Compiler.Backend.Rust.Pretty.Base
|
||||
import Juvix.Compiler.Backend.Rust.Pretty.Options
|
||||
import Juvix.Data.PPOutput
|
||||
import Juvix.Prelude
|
||||
import Prettyprinter.Render.Terminal qualified as Ansi
|
||||
|
||||
ppOutDefault :: (PrettyCode c) => c -> AnsiText
|
||||
ppOutDefault = mkAnsiText . PPOutput . doc defaultOptions
|
||||
|
||||
ppOut :: (CanonicalProjection a Options, PrettyCode c) => a -> c -> AnsiText
|
||||
ppOut o = mkAnsiText . PPOutput . doc (project o)
|
||||
|
||||
ppTrace' :: (CanonicalProjection a Options, PrettyCode c) => a -> c -> Text
|
||||
ppTrace' opts = Ansi.renderStrict . reAnnotateS stylize . layoutPretty defaultLayoutOptions . doc (project opts)
|
||||
|
||||
ppTrace :: (PrettyCode c) => c -> Text
|
||||
ppTrace = ppTrace' traceOptions
|
||||
|
||||
ppPrint :: (PrettyCode c) => c -> Text
|
||||
ppPrint = show . ppOutDefault
|
190
src/Juvix/Compiler/Backend/Rust/Pretty/Base.hs
Normal file
190
src/Juvix/Compiler/Backend/Rust/Pretty/Base.hs
Normal file
@ -0,0 +1,190 @@
|
||||
module Juvix.Compiler.Backend.Rust.Pretty.Base where
|
||||
|
||||
import Juvix.Compiler.Backend.Rust.Language
|
||||
import Juvix.Compiler.Backend.Rust.Pretty.Keywords
|
||||
import Juvix.Compiler.Backend.Rust.Pretty.Options
|
||||
import Juvix.Data.CodeAnn
|
||||
import Juvix.Prelude
|
||||
|
||||
class PrettyCode c where
|
||||
ppCode :: (Member (Reader Options) r) => c -> Sem r (Doc Ann)
|
||||
|
||||
doc :: (PrettyCode c) => Options -> c -> Doc Ann
|
||||
doc opts x =
|
||||
run $
|
||||
runReader opts $
|
||||
ppCode x
|
||||
|
||||
ampersand :: Doc Ann
|
||||
ampersand = "&"
|
||||
|
||||
hashsym :: Doc Ann
|
||||
hashsym = "#"
|
||||
|
||||
ppName :: NameKind -> Text -> Sem r (Doc Ann)
|
||||
ppName k n = return $ annotate (AnnKind k) (pretty n)
|
||||
|
||||
ppMut :: IsMut -> Sem r (Maybe (Doc Ann))
|
||||
ppMut = \case
|
||||
Mut -> return $ Just kwMut
|
||||
NotMut -> return Nothing
|
||||
|
||||
ppAttrs :: Maybe Text -> Sem r (Doc Ann)
|
||||
ppAttrs = \case
|
||||
Just attrs -> return $ hashsym <> brackets (pretty attrs) <> line
|
||||
Nothing -> return mempty
|
||||
|
||||
ppBlock :: (Member (Reader Options) r) => [Statement] -> Sem r (Doc Ann)
|
||||
ppBlock stmts = do
|
||||
stmts' <- mapM ppCode stmts
|
||||
let stmts'' = punctuate semi stmts'
|
||||
return $ oneLineOrNextBraces (vsep stmts'')
|
||||
|
||||
instance PrettyCode Type where
|
||||
ppCode = \case
|
||||
Word -> return kwWord
|
||||
VecOfWord -> return $ kwVector <> angles kwWord
|
||||
Memory -> return $ ampersand <> kwMut <+> kwMemory
|
||||
|
||||
instance PrettyCode FunctionArgument where
|
||||
ppCode FunctionArgument {..} = do
|
||||
ty <- ppCode _functionArgumentType
|
||||
n <- ppName KNameLocal _functionArgumentName
|
||||
mut <- ppMut _functionArgumentMutable
|
||||
return $ mut <?+> n <> colon <+> ty
|
||||
|
||||
instance PrettyCode Function where
|
||||
ppCode Function {..} = do
|
||||
attrs <- ppAttrs _functionAttributes
|
||||
name <- ppName KNameFunction _functionName
|
||||
args <- mapM ppCode _functionArguments
|
||||
rty <- maybe (return Nothing) (ppCode >=> return . Just . ("->" <+>)) _functionReturnType
|
||||
body <- ppBlock _functionBody
|
||||
let args' = punctuate comma args
|
||||
return $ attrs <> kwFn <+> name <> parens (hsep args') <+> rty <?+> body <> line
|
||||
|
||||
instance PrettyCode Statement where
|
||||
ppCode = \case
|
||||
StatementLet x -> ppCode x
|
||||
StatementConst x -> ppCode x
|
||||
StatementAssignment x -> ppCode x
|
||||
StatementIf x -> ppCode x
|
||||
StatementMatch x -> ppCode x
|
||||
StatementLoop x -> ppCode x
|
||||
StatementContinue -> return kwContinue
|
||||
StatementReturn x -> ppCode x
|
||||
StatementExpression x -> ppCode x
|
||||
|
||||
instance PrettyCode Let where
|
||||
ppCode Let {..} = do
|
||||
name <- ppName KNameLocal _letVariable
|
||||
ty <- maybe (return Nothing) (ppCode >=> return . Just) _letType
|
||||
mut <- ppMut _letMutable
|
||||
ini <- maybe (return Nothing) (ppCode >=> return . Just) _letInitializer
|
||||
let ini' = fmap ("=" <+>) ini
|
||||
ty' = fmap (colon <+>) ty
|
||||
return $ kwLet <+> mut <?+> (name <>? ty' <+?> ini')
|
||||
|
||||
instance PrettyCode ConstDecl where
|
||||
ppCode ConstDecl {..} = do
|
||||
name <- ppName KNameLocal _constVariable
|
||||
ty <- ppCode _constType
|
||||
val <- ppCode _constValue
|
||||
return $ kwConst <+> name <> colon <+> ty <+> "=" <+> val
|
||||
|
||||
instance PrettyCode Assignment where
|
||||
ppCode Assignment {..} = do
|
||||
name <- ppName KNameLocal _assignmentVariable
|
||||
val <- ppCode _assignmentValue
|
||||
return $ name <+> "=" <+> val
|
||||
|
||||
instance PrettyCode If where
|
||||
ppCode If {..} = do
|
||||
val <- ppCode _ifValue
|
||||
br1 <- ppBlock _ifBranchTrue
|
||||
br2 <- ppBlock _ifBranchFalse
|
||||
return $ kwIf <+> val <+> br1 <+> kwElse <+> br2
|
||||
|
||||
instance PrettyCode MatchBranch where
|
||||
ppCode MatchBranch {..} = do
|
||||
pat <- case _matchBranchPattern of
|
||||
Just p -> ppCode p
|
||||
Nothing -> return "_"
|
||||
body <- ppBlock _matchBranchBody
|
||||
return $ pat <+> "=>" <+> body
|
||||
|
||||
instance PrettyCode Match where
|
||||
ppCode Match {..} = do
|
||||
val <- ppCode _matchValue
|
||||
brs <- mapM ppCode _matchBranches
|
||||
return $ kwMatch <+> val <+> oneLineOrNextBraces (vsep brs)
|
||||
|
||||
instance PrettyCode Loop where
|
||||
ppCode Loop {..} = do
|
||||
let lab = fmap ((<> colon) . pretty) _loopLabel
|
||||
body <- ppBlock _loopBody
|
||||
return $ lab <?+> kwLoop <+> body
|
||||
|
||||
instance PrettyCode Return where
|
||||
ppCode Return {..} = do
|
||||
val <- maybe (return Nothing) (ppCode >=> return . Just) _returnValue
|
||||
return $ kwReturn <+?> val
|
||||
|
||||
instance PrettyCode Expression where
|
||||
ppCode = \case
|
||||
ExprVar x -> ppCode x
|
||||
ExprCall x -> ppCode x
|
||||
ExprVec x -> ppCode x
|
||||
ExprArray x -> ppCode x
|
||||
ExprLiteral x -> ppCode x
|
||||
ExprBlock x -> ppCode x
|
||||
ExprVerbatim x -> return $ pretty x
|
||||
|
||||
instance PrettyCode Var where
|
||||
ppCode Var {..} = ppName KNameLocal _varName
|
||||
|
||||
instance PrettyCode Call where
|
||||
ppCode Call {..} = do
|
||||
name <- ppName KNameFunction _callFunction
|
||||
args <- mapM ppCode _callArgs
|
||||
return $ name <> parens (hsep (punctuate comma args))
|
||||
|
||||
instance PrettyCode Vec where
|
||||
ppCode Vec {..} = do
|
||||
args <- mapM ppCode _vecArgs
|
||||
return $ kwVec <> brackets (hsep (punctuate comma args))
|
||||
|
||||
instance PrettyCode Array where
|
||||
ppCode Array {..} = do
|
||||
args <- mapM ppCode _arrayArgs
|
||||
return $ ampersand <> brackets (hsep (punctuate comma args))
|
||||
|
||||
instance PrettyCode Literal where
|
||||
ppCode = \case
|
||||
LitInteger i -> return $ annotate AnnLiteralInteger (pretty i)
|
||||
LitString s -> return $ annotate AnnLiteralString (show s)
|
||||
|
||||
instance PrettyCode Block where
|
||||
ppCode Block {..} = ppBlock _blockBody
|
||||
|
||||
instance PrettyCode Program where
|
||||
ppCode Program {..} = do
|
||||
funs <- mapM ppCode _programFunctions
|
||||
return $ pretty prelude <> line <> vsep funs
|
||||
where
|
||||
prelude :: Text
|
||||
prelude =
|
||||
"extern crate juvix;\n\
|
||||
\\n\
|
||||
\#[allow(unused_imports)]\n\
|
||||
\use juvix::defs::*;\n\
|
||||
\#[allow(unused_imports)]\n\
|
||||
\use juvix::apply;\n\
|
||||
\#[allow(unused_imports)]\n\
|
||||
\use juvix::tapply;\n\
|
||||
\#[allow(unused_imports)]\n\
|
||||
\use juvix::equality::*;\n\
|
||||
\#[allow(unused_imports)]\n\
|
||||
\use juvix::integer::*;\n\
|
||||
\#[allow(unused_imports)]\n\
|
||||
\use juvix::memory::*;\n"
|
43
src/Juvix/Compiler/Backend/Rust/Pretty/Keywords.hs
Normal file
43
src/Juvix/Compiler/Backend/Rust/Pretty/Keywords.hs
Normal file
@ -0,0 +1,43 @@
|
||||
module Juvix.Compiler.Backend.Rust.Pretty.Keywords where
|
||||
|
||||
import Juvix.Data.CodeAnn
|
||||
import Juvix.Extra.Strings qualified as Str
|
||||
|
||||
kwFn :: Doc Ann
|
||||
kwFn = keyword Str.rustFn
|
||||
|
||||
kwIf :: Doc Ann
|
||||
kwIf = keyword Str.rustIf
|
||||
|
||||
kwElse :: Doc Ann
|
||||
kwElse = keyword Str.rustElse
|
||||
|
||||
kwMatch :: Doc Ann
|
||||
kwMatch = keyword Str.rustMatch
|
||||
|
||||
kwLoop :: Doc Ann
|
||||
kwLoop = keyword Str.rustLoop
|
||||
|
||||
kwConst :: Doc Ann
|
||||
kwConst = keyword Str.rustConst
|
||||
|
||||
kwMut :: Doc Ann
|
||||
kwMut = keyword Str.rustMut
|
||||
|
||||
kwVec :: Doc Ann
|
||||
kwVec = keyword Str.rustVec
|
||||
|
||||
kwVector :: Doc Ann
|
||||
kwVector = keyword Str.rustVector
|
||||
|
||||
kwWord :: Doc Ann
|
||||
kwWord = keyword Str.rustWord
|
||||
|
||||
kwMemory :: Doc Ann
|
||||
kwMemory = keyword Str.rustMemory
|
||||
|
||||
kwContinue :: Doc Ann
|
||||
kwContinue = keyword Str.rustContinue
|
||||
|
||||
kwReturn :: Doc Ann
|
||||
kwReturn = keyword Str.rustReturn
|
21
src/Juvix/Compiler/Backend/Rust/Pretty/Options.hs
Normal file
21
src/Juvix/Compiler/Backend/Rust/Pretty/Options.hs
Normal file
@ -0,0 +1,21 @@
|
||||
module Juvix.Compiler.Backend.Rust.Pretty.Options where
|
||||
|
||||
import Juvix.Prelude
|
||||
|
||||
-- no fields for now, but make it easier to add options in the future I don't
|
||||
-- remove this datatype entirely
|
||||
data Options = Options
|
||||
|
||||
makeLenses ''Options
|
||||
|
||||
defaultOptions :: Options
|
||||
defaultOptions = Options
|
||||
|
||||
traceOptions :: Options
|
||||
traceOptions = defaultOptions
|
||||
|
||||
fromGenericOptions :: GenericOptions -> Options
|
||||
fromGenericOptions _ = defaultOptions
|
||||
|
||||
instance CanonicalProjection GenericOptions Options where
|
||||
project = fromGenericOptions
|
396
src/Juvix/Compiler/Backend/Rust/Translation/FromReg.hs
Normal file
396
src/Juvix/Compiler/Backend/Rust/Translation/FromReg.hs
Normal file
@ -0,0 +1,396 @@
|
||||
module Juvix.Compiler.Backend.Rust.Translation.FromReg
|
||||
( module Juvix.Compiler.Backend.Rust.Translation.FromReg,
|
||||
module Juvix.Compiler.Backend.Rust.Data.Result,
|
||||
)
|
||||
where
|
||||
|
||||
import Data.HashMap.Strict qualified as HashMap
|
||||
import Juvix.Compiler.Backend
|
||||
import Juvix.Compiler.Backend.Rust.Data.Result
|
||||
import Juvix.Compiler.Backend.Rust.Data.Result as Rust
|
||||
import Juvix.Compiler.Backend.Rust.Language as Rust
|
||||
import Juvix.Compiler.Backend.Rust.Pretty as Rust
|
||||
import Juvix.Compiler.Backend.Rust.Translation.FromReg.Base
|
||||
import Juvix.Compiler.Reg.Data.InfoTable qualified as Reg
|
||||
import Juvix.Compiler.Reg.Extra.Info qualified as Reg
|
||||
import Juvix.Compiler.Reg.Language qualified as Reg
|
||||
import Juvix.Prelude
|
||||
|
||||
fromReg :: Limits -> Reg.InfoTable -> Rust.Result
|
||||
fromReg lims tab =
|
||||
Rust.Result $ Rust.ppPrint $ Program [programFunction, mainFunction]
|
||||
where
|
||||
info :: Reg.ExtraInfo
|
||||
info = Reg.computeExtraInfo lims tab
|
||||
|
||||
mainFunid :: Int
|
||||
mainFunid = getFUID info $ fromJust $ tab ^. Reg.infoMainFunction
|
||||
|
||||
mainFunction :: Function
|
||||
mainFunction =
|
||||
Function
|
||||
{ _functionName = "main",
|
||||
_functionAttributes = Nothing,
|
||||
_functionArguments = [],
|
||||
_functionReturnType = Nothing,
|
||||
_functionBody =
|
||||
[ stmtLet NotMut "result" (mkCall "program" [ExprVerbatim "&mut Memory::new()", mkInteger mainFunid, mkVec []]),
|
||||
StatementExpression (mkCall "println!" [mkString "{}", mkVar "result"]),
|
||||
StatementReturn (Return Nothing)
|
||||
]
|
||||
}
|
||||
|
||||
programFunction :: Function
|
||||
programFunction =
|
||||
Function
|
||||
{ _functionName = "program",
|
||||
_functionAttributes = Just "allow(unused_mut, unused)",
|
||||
_functionArguments =
|
||||
[ FunctionArgument NotMut "mem" Memory,
|
||||
FunctionArgument Mut "funid" Word,
|
||||
FunctionArgument Mut "args" VecOfWord
|
||||
],
|
||||
_functionReturnType = Just Word,
|
||||
_functionBody = programBody
|
||||
}
|
||||
|
||||
programBody :: [Statement]
|
||||
programBody = funConstDecls ++ juvixFunctions
|
||||
|
||||
funConstDecls :: [Statement]
|
||||
funConstDecls = map mkFunConstDecl funs
|
||||
where
|
||||
mkFunConstDecl :: Reg.FunctionInfo -> Statement
|
||||
mkFunConstDecl funInfo =
|
||||
StatementConst $
|
||||
ConstDecl
|
||||
{ _constVariable = getFunctionIdent info (funInfo ^. Reg.functionSymbol),
|
||||
_constType = Word,
|
||||
_constValue = mkInteger (getFUID info (funInfo ^. Reg.functionSymbol))
|
||||
}
|
||||
|
||||
juvixFunctions :: [Statement]
|
||||
juvixFunctions =
|
||||
[ StatementLoop $
|
||||
Loop
|
||||
{ _loopLabel = Just "'program",
|
||||
_loopBody =
|
||||
[ StatementMatch $
|
||||
Match
|
||||
{ _matchValue = mkVar "funid",
|
||||
_matchBranches = map (fromRegFunction info) funs ++ [errBranch]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
where
|
||||
errBranch =
|
||||
MatchBranch
|
||||
{ _matchBranchPattern = Nothing,
|
||||
_matchBranchBody = [StatementExpression $ mkCall "panic!" [mkString "unknown function"]]
|
||||
}
|
||||
|
||||
funs :: [Reg.FunctionInfo]
|
||||
funs = HashMap.elems (tab ^. Reg.infoFunctions)
|
||||
|
||||
fromRegFunction :: Reg.ExtraInfo -> Reg.FunctionInfo -> MatchBranch
|
||||
fromRegFunction info funInfo =
|
||||
MatchBranch
|
||||
{ _matchBranchPattern = Just $ mkVar $ getFunctionIdent info (funInfo ^. Reg.functionSymbol),
|
||||
_matchBranchBody = varDecls ++ fromRegCode info (funInfo ^. Reg.functionCode)
|
||||
}
|
||||
where
|
||||
varsNum :: Int
|
||||
varsNum = getLocalVarsNum info (funInfo ^. Reg.functionSymbol)
|
||||
|
||||
varDecls :: [Statement]
|
||||
varDecls = map (\n -> stmtDecl Mut ("var_" <> show n) Word) [0 .. varsNum - 1]
|
||||
|
||||
fromRegCode :: Reg.ExtraInfo -> Reg.Code -> [Statement]
|
||||
fromRegCode info = concatMap (fromRegInstr info)
|
||||
|
||||
fromRegInstr :: Reg.ExtraInfo -> Reg.Instruction -> [Statement]
|
||||
fromRegInstr info = \case
|
||||
Reg.Nop ->
|
||||
[]
|
||||
Reg.Binop x ->
|
||||
[fromBinaryOp x]
|
||||
Reg.Unop x ->
|
||||
[fromUnaryOp x]
|
||||
Reg.Cairo {} ->
|
||||
unsupported "Cairo builtin"
|
||||
Reg.Assign Reg.InstrAssign {..} ->
|
||||
stmtsAssign (mkVarRef _instrAssignResult) (fromValue _instrAssignValue)
|
||||
Reg.Trace {} ->
|
||||
unsupported "trace"
|
||||
Reg.Dump ->
|
||||
unsupported "dump"
|
||||
Reg.Failure {} ->
|
||||
unsupported "fail"
|
||||
Reg.Prealloc {} ->
|
||||
[]
|
||||
Reg.Alloc x ->
|
||||
fromAlloc x
|
||||
Reg.AllocClosure x ->
|
||||
fromAllocClosure x
|
||||
Reg.ExtendClosure x ->
|
||||
fromExtendClosure x
|
||||
Reg.TailCall x ->
|
||||
fromTailCall x
|
||||
Reg.Call x ->
|
||||
fromCall x
|
||||
Reg.TailCallClosures x ->
|
||||
fromTailCallClosures x
|
||||
Reg.CallClosures x ->
|
||||
fromCallClosures x
|
||||
Reg.Return x ->
|
||||
fromReturn x
|
||||
Reg.Branch x ->
|
||||
fromBranch x
|
||||
Reg.Case x ->
|
||||
fromCase x
|
||||
Reg.Block Reg.InstrBlock {..} ->
|
||||
fromRegCode info _instrBlockCode
|
||||
where
|
||||
unsupported :: Text -> a
|
||||
unsupported x = error ("unsupported: " <> x)
|
||||
|
||||
fromBinaryOp :: Reg.InstrBinop -> Statement
|
||||
fromBinaryOp Reg.InstrBinop {..} =
|
||||
stmtAssign
|
||||
(mkVarRef _instrBinopResult)
|
||||
( mkCall
|
||||
(getBinaryOpName _instrBinopOpcode)
|
||||
[fromValue _instrBinopArg1, fromValue _instrBinopArg2]
|
||||
)
|
||||
|
||||
getBinaryOpName :: Reg.BinaryOp -> Text
|
||||
getBinaryOpName = \case
|
||||
Reg.OpIntAdd -> "smallint_add"
|
||||
Reg.OpIntSub -> "smallint_sub"
|
||||
Reg.OpIntMul -> "smallint_mul"
|
||||
Reg.OpIntDiv -> "smallint_div"
|
||||
Reg.OpIntMod -> "smallint_mod"
|
||||
Reg.OpIntLt -> "smallint_lt"
|
||||
Reg.OpIntLe -> "smallint_le"
|
||||
Reg.OpEq -> "juvix_equal"
|
||||
Reg.OpStrConcat -> unsupported "strings"
|
||||
Reg.OpFieldAdd -> unsupported "field type"
|
||||
Reg.OpFieldSub -> unsupported "field type"
|
||||
Reg.OpFieldMul -> unsupported "field type"
|
||||
Reg.OpFieldDiv -> unsupported "field type"
|
||||
|
||||
fromUnaryOp :: Reg.InstrUnop -> Statement
|
||||
fromUnaryOp Reg.InstrUnop {..} = case _instrUnopOpcode of
|
||||
Reg.OpShow -> unsupported "strings"
|
||||
Reg.OpStrToInt -> unsupported "strings"
|
||||
Reg.OpArgsNum ->
|
||||
stmtAssign
|
||||
(mkVarRef _instrUnopResult)
|
||||
(mkCall "mem.get_closure_largs" [fromValue _instrUnopArg])
|
||||
Reg.OpFieldToInt -> unsupported "field type"
|
||||
Reg.OpIntToField -> unsupported "field type"
|
||||
|
||||
mkVarRef :: Reg.VarRef -> Text
|
||||
mkVarRef Reg.VarRef {..} = case _varRefGroup of
|
||||
Reg.VarGroupArgs -> "args[" <> show _varRefIndex <> "]"
|
||||
Reg.VarGroupLocal -> "var_" <> show _varRefIndex
|
||||
|
||||
fromVarRef :: Reg.VarRef -> Expression
|
||||
fromVarRef = mkVar . mkVarRef
|
||||
|
||||
fromValue :: Reg.Value -> Expression
|
||||
fromValue = \case
|
||||
Reg.ValConst c -> fromConst c
|
||||
Reg.CRef Reg.ConstrField {..} ->
|
||||
case _constrFieldMemRep of
|
||||
Reg.MemRepConstr ->
|
||||
mkCall
|
||||
"mem.get_constr_arg"
|
||||
[fromVarRef _constrFieldRef, mkInteger _constrFieldIndex]
|
||||
Reg.MemRepTag ->
|
||||
unsupported "MemRepTag"
|
||||
Reg.MemRepTuple ->
|
||||
unsupported "MemRepTuple"
|
||||
Reg.MemRepUnit ->
|
||||
unsupported "MemRepUnit"
|
||||
Reg.MemRepUnpacked {} ->
|
||||
fromVarRef _constrFieldRef
|
||||
Reg.VRef x -> fromVarRef x
|
||||
|
||||
fromConst :: Reg.Constant -> Expression
|
||||
fromConst = \case
|
||||
Reg.ConstInt x -> mkCall "make_smallint" [mkInteger x]
|
||||
Reg.ConstField {} -> impossible
|
||||
Reg.ConstBool True -> mkVar "BOOL_TRUE"
|
||||
Reg.ConstBool False -> mkVar "BOOL_FALSE"
|
||||
Reg.ConstString {} -> unsupported "strings"
|
||||
Reg.ConstUnit -> mkVar "OBJ_UNIT"
|
||||
Reg.ConstVoid -> mkVar "OBJ_VOID"
|
||||
|
||||
fromAlloc :: Reg.InstrAlloc -> [Statement]
|
||||
fromAlloc Reg.InstrAlloc {..} =
|
||||
case _instrAllocMemRep of
|
||||
Reg.MemRepConstr ->
|
||||
stmtsAssign
|
||||
(mkVarRef _instrAllocResult)
|
||||
( mkCall
|
||||
"mem.alloc_constr"
|
||||
[ mkInteger (getUID info _instrAllocTag),
|
||||
mkArray (map fromValue _instrAllocArgs)
|
||||
]
|
||||
)
|
||||
Reg.MemRepTag ->
|
||||
unsupported "MemRepTag"
|
||||
Reg.MemRepTuple ->
|
||||
unsupported "MemRepTuple"
|
||||
Reg.MemRepUnit ->
|
||||
unsupported "MemRepUnit"
|
||||
Reg.MemRepUnpacked {} ->
|
||||
unsupported "MemRepUnpacked"
|
||||
|
||||
fromAllocClosure :: Reg.InstrAllocClosure -> [Statement]
|
||||
fromAllocClosure Reg.InstrAllocClosure {..} =
|
||||
stmtsAssign
|
||||
(mkVarRef _instrAllocClosureResult)
|
||||
( mkCall
|
||||
"mem.alloc_closure"
|
||||
[ mkVar (getFunctionIdent info _instrAllocClosureSymbol),
|
||||
mkArray (map fromValue _instrAllocClosureArgs),
|
||||
mkInteger (_instrAllocClosureExpectedArgsNum - length _instrAllocClosureArgs)
|
||||
]
|
||||
)
|
||||
|
||||
fromExtendClosure :: Reg.InstrExtendClosure -> [Statement]
|
||||
fromExtendClosure Reg.InstrExtendClosure {..} =
|
||||
stmtsAssign
|
||||
(mkVarRef _instrExtendClosureResult)
|
||||
( mkCall
|
||||
"mem.extend_closure"
|
||||
[ fromVarRef _instrExtendClosureValue,
|
||||
mkArray (map fromValue _instrExtendClosureArgs)
|
||||
]
|
||||
)
|
||||
|
||||
fromCall :: Reg.InstrCall -> [Statement]
|
||||
fromCall Reg.InstrCall {..} =
|
||||
case _instrCallType of
|
||||
Reg.CallFun sym ->
|
||||
stmtsAssign
|
||||
(mkVarRef _instrCallResult)
|
||||
( mkCall
|
||||
"program"
|
||||
[mkVar "mem", mkVar (getFunctionIdent info sym), mkVec (map fromValue _instrCallArgs)]
|
||||
)
|
||||
Reg.CallClosure vr ->
|
||||
stmtsBlock
|
||||
[ stmtLet Mut "cargs" (mkVec (map fromValue _instrCallArgs)),
|
||||
stmtLet NotMut "(cfunid, args)" (mkCall "mem.call_closure" [fromVarRef vr, mkVar "&cargs"]),
|
||||
stmtAssign
|
||||
(mkVarRef _instrCallResult)
|
||||
( mkCall
|
||||
"program"
|
||||
[mkVar "mem", mkVar "cfunid", mkVar "args"]
|
||||
)
|
||||
]
|
||||
|
||||
fromTailCall :: Reg.InstrTailCall -> [Statement]
|
||||
fromTailCall Reg.InstrTailCall {..} =
|
||||
case _instrTailCallType of
|
||||
Reg.CallFun sym ->
|
||||
[ stmtAssign "args" (mkVec (map fromValue _instrTailCallArgs)),
|
||||
stmtAssign "funid" (mkVar (getFunctionIdent info sym)),
|
||||
StatementContinue
|
||||
]
|
||||
Reg.CallClosure vr ->
|
||||
[ stmtAssign
|
||||
"funid"
|
||||
( mkCall
|
||||
"mem.call_closure"
|
||||
[fromVarRef vr, mkArray ((map fromValue _instrTailCallArgs))]
|
||||
),
|
||||
StatementContinue
|
||||
]
|
||||
|
||||
fromCallClosures :: Reg.InstrCallClosures -> [Statement]
|
||||
fromCallClosures Reg.InstrCallClosures {..} =
|
||||
stmtsAssign
|
||||
(mkVarRef _instrCallClosuresResult)
|
||||
( mkCall
|
||||
"apply!"
|
||||
[ mkVar "program",
|
||||
mkVar "mem",
|
||||
fromVarRef _instrCallClosuresValue,
|
||||
mkVec (map fromValue _instrCallClosuresArgs)
|
||||
]
|
||||
)
|
||||
|
||||
fromTailCallClosures :: Reg.InstrTailCallClosures -> [Statement]
|
||||
fromTailCallClosures Reg.InstrTailCallClosures {..} =
|
||||
[ StatementExpression $
|
||||
mkCall
|
||||
"tapply!"
|
||||
[ mkVar "'program",
|
||||
mkVar "program",
|
||||
mkVar "mem",
|
||||
mkVar "funid",
|
||||
mkVar "args",
|
||||
fromVarRef _instrTailCallClosuresValue,
|
||||
mkVec (map fromValue _instrTailCallClosuresArgs)
|
||||
]
|
||||
]
|
||||
|
||||
fromBranch :: Reg.InstrBranch -> [Statement]
|
||||
fromBranch Reg.InstrBranch {..} =
|
||||
stmtsIf (mkCall "word_to_bool" [fromValue _instrBranchValue]) br1 br2
|
||||
where
|
||||
br1 = fromRegCode info _instrBranchTrue
|
||||
br2 = fromRegCode info _instrBranchFalse
|
||||
|
||||
fromCase :: Reg.InstrCase -> [Statement]
|
||||
fromCase Reg.InstrCase {..} = do
|
||||
case _instrCaseIndRep of
|
||||
Reg.IndRepStandard ->
|
||||
[ StatementMatch $
|
||||
Match
|
||||
{ _matchValue = mkCall "mem.get_constr_tag" [fromValue _instrCaseValue],
|
||||
_matchBranches = brs'
|
||||
}
|
||||
]
|
||||
Reg.IndRepEnum ->
|
||||
error "unsupported constructor representation"
|
||||
Reg.IndRepEnumRecord ->
|
||||
error "unsupported constructor representation"
|
||||
Reg.IndRepEnumMaybe {} ->
|
||||
error "unsupported constructor representation"
|
||||
Reg.IndRepRecord ->
|
||||
error "unsupported constructor representation"
|
||||
Reg.IndRepUnit ->
|
||||
error "unsupported constructor representation"
|
||||
Reg.IndRepNewtype {} ->
|
||||
error "unsupported constructor representation"
|
||||
Reg.IndRepMixed ->
|
||||
error "unsupported constructor representation"
|
||||
where
|
||||
brs = map fromCaseBranch _instrCaseBranches
|
||||
def = case _instrCaseDefault of
|
||||
Nothing -> Nothing
|
||||
Just c -> Just $ fromRegCode info c
|
||||
brs' =
|
||||
brs
|
||||
++ [ MatchBranch
|
||||
{ _matchBranchPattern = Nothing,
|
||||
_matchBranchBody = fromMaybe [StatementExpression $ mkCall "panic!" [mkString "match failure"]] def
|
||||
}
|
||||
]
|
||||
|
||||
fromCaseBranch :: Reg.CaseBranch -> MatchBranch
|
||||
fromCaseBranch Reg.CaseBranch {..} =
|
||||
MatchBranch
|
||||
{ _matchBranchPattern = Just $ mkInteger (getUID info _caseBranchTag),
|
||||
_matchBranchBody = fromRegCode info _caseBranchCode
|
||||
}
|
||||
|
||||
fromReturn :: Reg.InstrReturn -> [Statement]
|
||||
fromReturn Reg.InstrReturn {..} =
|
||||
[StatementReturn $ Return $ Just $ fromValue _instrReturnValue]
|
100
src/Juvix/Compiler/Backend/Rust/Translation/FromReg/Base.hs
Normal file
100
src/Juvix/Compiler/Backend/Rust/Translation/FromReg/Base.hs
Normal file
@ -0,0 +1,100 @@
|
||||
module Juvix.Compiler.Backend.Rust.Translation.FromReg.Base where
|
||||
|
||||
import Data.HashMap.Strict qualified as HashMap
|
||||
import Data.Text qualified as T
|
||||
import Juvix.Compiler.Backend.Rust.Language
|
||||
import Juvix.Compiler.Reg.Data.InfoTable qualified as Reg
|
||||
import Juvix.Compiler.Reg.Extra.Info qualified as Reg
|
||||
import Juvix.Compiler.Reg.Language qualified as Reg
|
||||
import Juvix.Prelude
|
||||
|
||||
mkRustIdent :: Text -> Text
|
||||
mkRustIdent ident = T.filter isValidIdentChar ident
|
||||
|
||||
getFunctionName :: Reg.ExtraInfo -> Reg.Symbol -> Text
|
||||
getFunctionName info sym = ((info ^. Reg.extraInfoTable . Reg.infoFunctions) HashMap.! sym) ^. Reg.functionName
|
||||
|
||||
getBuiltinUID :: Reg.BuiltinDataTag -> Int
|
||||
getBuiltinUID = \case
|
||||
Reg.TagFalse -> impossible
|
||||
Reg.TagTrue -> impossible
|
||||
Reg.TagReturn -> impossible
|
||||
Reg.TagBind -> impossible
|
||||
Reg.TagWrite -> impossible
|
||||
Reg.TagReadLn -> impossible
|
||||
|
||||
getUID :: Reg.ExtraInfo -> Reg.Tag -> Int
|
||||
getUID info tag = case tag of
|
||||
Reg.BuiltinTag builtin -> getBuiltinUID builtin
|
||||
Reg.UserTag {} -> fromJust $ HashMap.lookup tag (info ^. Reg.extraInfoCIDs)
|
||||
|
||||
getFUID :: Reg.ExtraInfo -> Reg.Symbol -> Int
|
||||
getFUID info sym = fromJust $ HashMap.lookup sym (info ^. Reg.extraInfoFUIDs)
|
||||
|
||||
getStringId :: Reg.ExtraInfo -> Text -> Int
|
||||
getStringId info txt = fromJust $ HashMap.lookup txt (info ^. Reg.extraInfoStringMap)
|
||||
|
||||
getMaxStackHeight :: Reg.ExtraInfo -> Reg.Symbol -> Int
|
||||
getMaxStackHeight info sym = fromJust $ HashMap.lookup sym (info ^. Reg.extraInfoMaxStackHeight)
|
||||
|
||||
getLocalVarsNum :: Reg.ExtraInfo -> Reg.Symbol -> Int
|
||||
getLocalVarsNum info sym = fromJust $ HashMap.lookup sym (info ^. Reg.extraInfoLocalVarsNum)
|
||||
|
||||
getFunctionIdent :: Reg.ExtraInfo -> Reg.Symbol -> Text
|
||||
getFunctionIdent info sym = mkRustIdent $ "JUVIX_FUNCTION_" <> T.toUpper (getFunctionName info sym) <> "_" <> show (getFUID info sym)
|
||||
|
||||
stmtAssign :: Text -> Expression -> Statement
|
||||
stmtAssign result value = StatementAssignment $ Assignment result value
|
||||
|
||||
stmtsAssign :: Text -> Expression -> [Statement]
|
||||
stmtsAssign result value = [stmtAssign result value]
|
||||
|
||||
stmtsCall :: Text -> [Expression] -> [Statement]
|
||||
stmtsCall fun args = [StatementExpression $ mkCall fun args]
|
||||
|
||||
stmtsBlock :: [Statement] -> [Statement]
|
||||
stmtsBlock stmts = [StatementExpression (ExprBlock (Block stmts))]
|
||||
|
||||
stmtLet :: IsMut -> Text -> Expression -> Statement
|
||||
stmtLet isMut result value =
|
||||
StatementLet $
|
||||
Let
|
||||
{ _letMutable = isMut,
|
||||
_letVariable = result,
|
||||
_letType = Nothing,
|
||||
_letInitializer = Just value
|
||||
}
|
||||
|
||||
stmtDecl :: IsMut -> Text -> Type -> Statement
|
||||
stmtDecl isMut var ty =
|
||||
StatementLet $
|
||||
Let
|
||||
{ _letMutable = isMut,
|
||||
_letVariable = var,
|
||||
_letType = Just ty,
|
||||
_letInitializer = Nothing
|
||||
}
|
||||
|
||||
stmtIf :: Expression -> [Statement] -> [Statement] -> Statement
|
||||
stmtIf v br1 br2 = StatementIf $ If v br1 br2
|
||||
|
||||
stmtsIf :: Expression -> [Statement] -> [Statement] -> [Statement]
|
||||
stmtsIf v br1 br2 = [stmtIf v br1 br2]
|
||||
|
||||
mkCall :: Text -> [Expression] -> Expression
|
||||
mkCall fun args = ExprCall $ Call fun args
|
||||
|
||||
mkInteger :: (Integral a) => a -> Expression
|
||||
mkInteger i = ExprLiteral $ LitInteger (fromIntegral i)
|
||||
|
||||
mkString :: Text -> Expression
|
||||
mkString s = ExprLiteral $ LitString s
|
||||
|
||||
mkVar :: Text -> Expression
|
||||
mkVar = ExprVar . Var
|
||||
|
||||
mkArray :: [Expression] -> Expression
|
||||
mkArray = ExprArray . Array
|
||||
|
||||
mkVec :: [Expression] -> Expression
|
||||
mkVec = ExprVec . Vec
|
@ -23,6 +23,7 @@ data TransformationId
|
||||
| CombineInfoTables
|
||||
| CheckGeb
|
||||
| CheckExec
|
||||
| CheckRust
|
||||
| CheckVampIR
|
||||
| CheckAnoma
|
||||
| CheckCairo
|
||||
@ -103,6 +104,7 @@ instance TransformationId' TransformationId where
|
||||
CombineInfoTables -> strCombineInfoTables
|
||||
CheckGeb -> strCheckGeb
|
||||
CheckExec -> strCheckExec
|
||||
CheckRust -> strCheckRust
|
||||
CheckVampIR -> strCheckVampIR
|
||||
CheckAnoma -> strCheckAnoma
|
||||
CheckCairo -> strCheckCairo
|
||||
|
@ -77,6 +77,9 @@ strCheckGeb = "check-geb"
|
||||
strCheckExec :: Text
|
||||
strCheckExec = "check-exec"
|
||||
|
||||
strCheckRust :: Text
|
||||
strCheckRust = "check-rust"
|
||||
|
||||
strCheckVampIR :: Text
|
||||
strCheckVampIR = "check-vampir"
|
||||
|
||||
|
@ -17,6 +17,7 @@ import Juvix.Compiler.Core.Transformation.Check.Anoma
|
||||
import Juvix.Compiler.Core.Transformation.Check.Cairo
|
||||
import Juvix.Compiler.Core.Transformation.Check.Exec
|
||||
import Juvix.Compiler.Core.Transformation.Check.Geb
|
||||
import Juvix.Compiler.Core.Transformation.Check.Rust
|
||||
import Juvix.Compiler.Core.Transformation.Check.VampIR
|
||||
import Juvix.Compiler.Core.Transformation.CombineInfoTables (combineInfoTables)
|
||||
import Juvix.Compiler.Core.Transformation.ComputeTypeInfo
|
||||
@ -81,6 +82,7 @@ applyTransformations ts tbl = foldM (flip appTrans) tbl ts
|
||||
CombineInfoTables -> return . combineInfoTables
|
||||
CheckGeb -> mapError (JuvixError @CoreError) . checkGeb
|
||||
CheckExec -> mapError (JuvixError @CoreError) . checkExec
|
||||
CheckRust -> mapError (JuvixError @CoreError) . checkRust
|
||||
CheckVampIR -> mapError (JuvixError @CoreError) . checkVampIR
|
||||
CheckAnoma -> mapError (JuvixError @CoreError) . checkAnoma
|
||||
CheckCairo -> mapError (JuvixError @CoreError) . checkCairo
|
||||
|
@ -162,3 +162,36 @@ checkMainExists md =
|
||||
_coreErrorNode = Nothing,
|
||||
_coreErrorLoc = defaultLoc
|
||||
}
|
||||
|
||||
checkMainTypeExec :: (Member (Error CoreError) r) => Module -> Sem r ()
|
||||
checkMainTypeExec md =
|
||||
case md ^. moduleInfoTable . infoMain of
|
||||
Nothing ->
|
||||
throw
|
||||
CoreError
|
||||
{ _coreErrorMsg = ppOutput "no `main` function",
|
||||
_coreErrorNode = Nothing,
|
||||
_coreErrorLoc = defaultLoc
|
||||
}
|
||||
Just sym ->
|
||||
case ii ^. identifierType of
|
||||
NPi {} ->
|
||||
throw
|
||||
CoreError
|
||||
{ _coreErrorMsg = ppOutput "`main` cannot have a function type for this target",
|
||||
_coreErrorNode = Nothing,
|
||||
_coreErrorLoc = loc
|
||||
}
|
||||
ty
|
||||
| isTypeConstr md ty ->
|
||||
throw
|
||||
CoreError
|
||||
{ _coreErrorMsg = ppOutput "`main` cannot be a type for this target",
|
||||
_coreErrorNode = Nothing,
|
||||
_coreErrorLoc = loc
|
||||
}
|
||||
_ ->
|
||||
return ()
|
||||
where
|
||||
ii = lookupIdentifierInfo md sym
|
||||
loc = fromMaybe defaultLoc (ii ^. identifierLocation)
|
||||
|
@ -4,44 +4,10 @@ import Juvix.Compiler.Core.Error
|
||||
import Juvix.Compiler.Core.Extra
|
||||
import Juvix.Compiler.Core.Transformation.Base
|
||||
import Juvix.Compiler.Core.Transformation.Check.Base
|
||||
import Juvix.Data.PPOutput
|
||||
|
||||
checkExec :: forall r. (Member (Error CoreError) r) => Module -> Sem r Module
|
||||
checkExec md = do
|
||||
checkNoAxioms md
|
||||
checkMainExists md
|
||||
checkMainType
|
||||
checkMainTypeExec md
|
||||
mapAllNodesM (checkBuiltins' (builtinsCairo ++ builtinsAnoma) []) md
|
||||
where
|
||||
checkMainType :: Sem r ()
|
||||
checkMainType =
|
||||
case md ^. moduleInfoTable . infoMain of
|
||||
Nothing ->
|
||||
throw
|
||||
CoreError
|
||||
{ _coreErrorMsg = ppOutput "no `main` function",
|
||||
_coreErrorNode = Nothing,
|
||||
_coreErrorLoc = defaultLoc
|
||||
}
|
||||
Just sym ->
|
||||
case ii ^. identifierType of
|
||||
NPi {} ->
|
||||
throw
|
||||
CoreError
|
||||
{ _coreErrorMsg = ppOutput "`main` cannot have a function type for this target",
|
||||
_coreErrorNode = Nothing,
|
||||
_coreErrorLoc = loc
|
||||
}
|
||||
ty
|
||||
| isTypeConstr md ty ->
|
||||
throw
|
||||
CoreError
|
||||
{ _coreErrorMsg = ppOutput "`main` cannot be a type for this target",
|
||||
_coreErrorNode = Nothing,
|
||||
_coreErrorLoc = loc
|
||||
}
|
||||
_ ->
|
||||
return ()
|
||||
where
|
||||
ii = lookupIdentifierInfo md sym
|
||||
loc = fromMaybe defaultLoc (ii ^. identifierLocation)
|
||||
|
14
src/Juvix/Compiler/Core/Transformation/Check/Rust.hs
Normal file
14
src/Juvix/Compiler/Core/Transformation/Check/Rust.hs
Normal file
@ -0,0 +1,14 @@
|
||||
module Juvix.Compiler.Core.Transformation.Check.Rust where
|
||||
|
||||
import Juvix.Compiler.Core.Error
|
||||
import Juvix.Compiler.Core.Extra
|
||||
import Juvix.Compiler.Core.Transformation.Base
|
||||
import Juvix.Compiler.Core.Transformation.Check.Base
|
||||
|
||||
checkRust :: forall r. (Member (Error CoreError) r) => Module -> Sem r Module
|
||||
checkRust md = do
|
||||
checkNoAxioms md
|
||||
checkMainExists md
|
||||
checkMainTypeExec md
|
||||
mapAllNodesM checkNoIO md
|
||||
mapAllNodesM (checkBuiltins False) md
|
@ -16,6 +16,7 @@ import Juvix.Compiler.Backend qualified as Backend
|
||||
import Juvix.Compiler.Backend.C qualified as C
|
||||
import Juvix.Compiler.Backend.Cairo qualified as Cairo
|
||||
import Juvix.Compiler.Backend.Geb qualified as Geb
|
||||
import Juvix.Compiler.Backend.Rust.Translation.FromReg qualified as Rust
|
||||
import Juvix.Compiler.Backend.VampIR.Translation qualified as VampIR
|
||||
import Juvix.Compiler.Casm.Data.Builtins qualified as Casm
|
||||
import Juvix.Compiler.Casm.Data.Result qualified as Casm
|
||||
@ -158,6 +159,11 @@ upToAnoma ::
|
||||
Sem r NockmaTree.AnomaResult
|
||||
upToAnoma = upToStoredCore >>= \Core.CoreResult {..} -> storedCoreToAnoma _coreResultModule
|
||||
|
||||
upToRust ::
|
||||
(Members '[HighlightBuilder, Reader Parser.ParserResult, Reader EntryPoint, Reader Store.ModuleTable, Files, NameIdGen, Error JuvixError, PathResolver] r) =>
|
||||
Sem r Rust.Result
|
||||
upToRust = upToStoredCore >>= \Core.CoreResult {..} -> storedCoreToRust _coreResultModule
|
||||
|
||||
upToCoreTypecheck ::
|
||||
(Members '[HighlightBuilder, Reader Parser.ParserResult, Reader EntryPoint, Reader Store.ModuleTable, Files, NameIdGen, Error JuvixError, PathResolver] r) =>
|
||||
Sem r Core.CoreResult
|
||||
@ -191,6 +197,9 @@ storedCoreToReg = storedCoreToAsm >=> asmToReg
|
||||
storedCoreToMiniC :: (Members '[Error JuvixError, Reader EntryPoint] r) => Core.Module -> Sem r C.MiniCResult
|
||||
storedCoreToMiniC = storedCoreToAsm >=> asmToMiniC
|
||||
|
||||
storedCoreToRust :: (Members '[Error JuvixError, Reader EntryPoint] r) => Core.Module -> Sem r Rust.Result
|
||||
storedCoreToRust = storedCoreToTree Core.CheckRust >=> treeToReg >=> regToRust
|
||||
|
||||
storedCoreToCasm :: (Members '[Error JuvixError, Reader EntryPoint] r) => Core.Module -> Sem r Casm.Result
|
||||
storedCoreToCasm = local (set entryPointFieldSize cairoFieldSize) . storedCoreToTree Core.CheckCairo >=> treeToCasm
|
||||
|
||||
@ -283,6 +292,12 @@ regToMiniC tab = do
|
||||
e <- ask
|
||||
return $ C.fromReg (Backend.getLimits (getEntryPointTarget e) (e ^. entryPointDebug)) tab'
|
||||
|
||||
regToRust :: (Member (Reader EntryPoint) r) => Reg.InfoTable -> Sem r Rust.Result
|
||||
regToRust tab = do
|
||||
tab' <- Reg.toRust tab
|
||||
e <- ask
|
||||
return $ Rust.fromReg (Backend.getLimits (getEntryPointTarget e) (e ^. entryPointDebug)) tab'
|
||||
|
||||
regToCasm :: Reg.InfoTable -> Sem r Casm.Result
|
||||
regToCasm = Reg.toCasm >=> return . Casm.fromReg
|
||||
|
||||
|
@ -14,6 +14,7 @@ data TransformationId
|
||||
data PipelineId
|
||||
= PipelineCasm
|
||||
| PipelineC
|
||||
| PipelineRust
|
||||
deriving stock (Data, Bounded, Enum)
|
||||
|
||||
type TransformationLikeId = TransformationLikeId' TransformationId PipelineId
|
||||
@ -21,6 +22,9 @@ type TransformationLikeId = TransformationLikeId' TransformationId PipelineId
|
||||
toCTransformations :: [TransformationId]
|
||||
toCTransformations = [Cleanup]
|
||||
|
||||
toRustTransformations :: [TransformationId]
|
||||
toRustTransformations = [Cleanup]
|
||||
|
||||
toCasmTransformations :: [TransformationId]
|
||||
toCasmTransformations = [Cleanup, SSA]
|
||||
|
||||
@ -36,9 +40,11 @@ instance PipelineId' TransformationId PipelineId where
|
||||
pipelineText :: PipelineId -> Text
|
||||
pipelineText = \case
|
||||
PipelineC -> strCPipeline
|
||||
PipelineRust -> strRustPipeline
|
||||
PipelineCasm -> strCasmPipeline
|
||||
|
||||
pipeline :: PipelineId -> [TransformationId]
|
||||
pipeline = \case
|
||||
PipelineC -> toCTransformations
|
||||
PipelineRust -> toRustTransformations
|
||||
PipelineCasm -> toCasmTransformations
|
||||
|
@ -5,6 +5,9 @@ import Juvix.Prelude
|
||||
strCPipeline :: Text
|
||||
strCPipeline = "pipeline-c"
|
||||
|
||||
strRustPipeline :: Text
|
||||
strRustPipeline = "pipeline-rust"
|
||||
|
||||
strCasmPipeline :: Text
|
||||
strCasmPipeline = "pipeline-casm"
|
||||
|
||||
|
@ -14,6 +14,10 @@ import Juvix.Compiler.Reg.Translation.Blocks.FromReg qualified as Blocks
|
||||
toC :: InfoTable -> Sem r InfoTable
|
||||
toC = applyTransformations toCTransformations
|
||||
|
||||
-- | Perform transformations on JuvixReg necessary before the translation to Rust
|
||||
toRust :: InfoTable -> Sem r InfoTable
|
||||
toRust = applyTransformations toRustTransformations
|
||||
|
||||
-- | Perform transformations on JuvixReg necessary before the translation to
|
||||
-- Cairo assembly
|
||||
toCasm :: InfoTable -> Sem r Blocks.InfoTable
|
||||
|
@ -22,6 +22,7 @@ data FileExt
|
||||
| FileExtPlonk
|
||||
| FileExtHalo
|
||||
| FileExtLisp
|
||||
| FileExtRust
|
||||
| FileExtC
|
||||
| FileExtMarkdown
|
||||
| FileExtHtml
|
||||
@ -85,6 +86,9 @@ markdownFileExt = ".md"
|
||||
cFileExt :: (IsString a) => a
|
||||
cFileExt = ".c"
|
||||
|
||||
rustFileExt :: (IsString a) => a
|
||||
rustFileExt = ".rs"
|
||||
|
||||
cssFileExt :: (IsString a) => a
|
||||
cssFileExt = ".css"
|
||||
|
||||
@ -110,6 +114,7 @@ fileExtToIsString = \case
|
||||
FileExtPlonk -> plonkFileExt
|
||||
FileExtHalo -> haloFileExt
|
||||
FileExtLisp -> lispFileExt
|
||||
FileExtRust -> rustFileExt
|
||||
FileExtC -> cFileExt
|
||||
FileExtMarkdown -> markdownFileExt
|
||||
FileExtHtml -> htmlFileExt
|
||||
@ -135,6 +140,7 @@ toMetavar = \case
|
||||
FileExtPlonk -> "PLONK_FILE"
|
||||
FileExtHalo -> "HALO_FILE"
|
||||
FileExtLisp -> "LISP_FILE"
|
||||
FileExtRust -> "RUST_FILE"
|
||||
FileExtC -> "C_FILE"
|
||||
FileExtMarkdown -> "MARKDOWN_FILE"
|
||||
FileExtHtml -> "HTML_FILE"
|
||||
@ -194,6 +200,9 @@ isLispFile = (== Just lispFileExt) . fileExtension
|
||||
isMarkdownFile :: Path b File -> Bool
|
||||
isMarkdownFile = (== Just markdownFileExt) . fileExtension
|
||||
|
||||
isRustFile :: Path b File -> Bool
|
||||
isRustFile = (== Just rustFileExt) . fileExtension
|
||||
|
||||
isCFile :: Path b File -> Bool
|
||||
isCFile = (== Just cFileExt) . fileExtension
|
||||
|
||||
@ -221,6 +230,7 @@ toFileExt p
|
||||
| isPlonkFile p = Just FileExtPlonk
|
||||
| isHaloFile p = Just FileExtHalo
|
||||
| isLispFile p = Just FileExtLisp
|
||||
| isRustFile p = Just FileExtRust
|
||||
| isCFile p = Just FileExtC
|
||||
| isMarkdownFile p = Just FileExtMarkdown
|
||||
| isHtmlFile p = Just FileExtHtml
|
||||
|
@ -1054,3 +1054,45 @@ cairoEcPoint = "ec_point"
|
||||
|
||||
cairoMkEcPoint :: (IsString s) => s
|
||||
cairoMkEcPoint = "mkEcPoint"
|
||||
|
||||
rustFn :: (IsString s) => s
|
||||
rustFn = "fn"
|
||||
|
||||
rustIf :: (IsString s) => s
|
||||
rustIf = "if"
|
||||
|
||||
rustElse :: (IsString s) => s
|
||||
rustElse = "else"
|
||||
|
||||
rustMatch :: (IsString s) => s
|
||||
rustMatch = "match"
|
||||
|
||||
rustLoop :: (IsString s) => s
|
||||
rustLoop = "loop"
|
||||
|
||||
rustLet :: (IsString s) => s
|
||||
rustLet = "let"
|
||||
|
||||
rustConst :: (IsString s) => s
|
||||
rustConst = "const"
|
||||
|
||||
rustMut :: (IsString s) => s
|
||||
rustMut = "mut"
|
||||
|
||||
rustVec :: (IsString s) => s
|
||||
rustVec = "vec!"
|
||||
|
||||
rustVector :: (IsString s) => s
|
||||
rustVector = "Vec"
|
||||
|
||||
rustWord :: (IsString s) => s
|
||||
rustWord = "Word"
|
||||
|
||||
rustMemory :: (IsString s) => s
|
||||
rustMemory = "Memory"
|
||||
|
||||
rustContinue :: (IsString s) => s
|
||||
rustContinue = "continue"
|
||||
|
||||
rustReturn :: (IsString s) => s
|
||||
rustReturn = "return"
|
||||
|
34
test/Base.hs
34
test/Base.hs
@ -21,6 +21,7 @@ import Juvix.Data.Effect.TaggedLock
|
||||
import Juvix.Extra.Paths hiding (rootBuildDir)
|
||||
import Juvix.Prelude hiding (assert)
|
||||
import Juvix.Prelude.Env
|
||||
import System.Process qualified as P
|
||||
import Test.Tasty
|
||||
import Test.Tasty.HUnit hiding (assertFailure)
|
||||
import Test.Tasty.HUnit qualified as HUnit
|
||||
@ -114,3 +115,36 @@ testRunIOEitherTermination entry =
|
||||
|
||||
assertFailure :: (MonadIO m) => String -> m a
|
||||
assertFailure = liftIO . HUnit.assertFailure
|
||||
|
||||
-- | The same as `P.readProcess` but instead of inheriting `stderr` redirects it
|
||||
-- to the child's `stdout`.
|
||||
readProcess :: FilePath -> [String] -> Text -> IO Text
|
||||
readProcess = readProcessCwd' Nothing
|
||||
|
||||
readProcessCwd :: FilePath -> FilePath -> [String] -> Text -> IO Text
|
||||
readProcessCwd cwd = readProcessCwd' (Just cwd)
|
||||
|
||||
readProcessCwd' :: Maybe FilePath -> FilePath -> [String] -> Text -> IO Text
|
||||
readProcessCwd' mcwd cmd args stdinText =
|
||||
withTempDir'
|
||||
( \dirPath -> do
|
||||
(_, hin) <- openTempFile dirPath "stdin"
|
||||
(_, hout) <- openTempFile dirPath "stdout"
|
||||
hPutStr hin stdinText
|
||||
hSeek hin AbsoluteSeek 0
|
||||
(_, _, _, ph) <-
|
||||
P.createProcess_
|
||||
"readProcess"
|
||||
(P.proc cmd args)
|
||||
{ P.std_in = P.UseHandle hin,
|
||||
P.std_out = P.UseHandle hout,
|
||||
P.std_err = P.UseHandle hout,
|
||||
P.cwd = mcwd
|
||||
}
|
||||
P.waitForProcess ph
|
||||
hSeek hout AbsoluteSeek 0
|
||||
r <- hGetContents hout
|
||||
hClose hin
|
||||
hClose hout
|
||||
return r
|
||||
)
|
||||
|
@ -12,12 +12,11 @@ import Juvix.Compiler.Casm.Validate
|
||||
import Juvix.Data.Field
|
||||
import Juvix.Data.PPOutput
|
||||
import Juvix.Parser.Error
|
||||
import Runtime.Base qualified as R
|
||||
|
||||
casmRunVM' :: Path Abs Dir -> Path Abs File -> Maybe (Path Abs File) -> IO Text
|
||||
casmRunVM' dirPath outputFile inputFile = do
|
||||
let args = maybe [] (\f -> ["--program_input", toFilePath f]) inputFile
|
||||
R.readProcessCwd (toFilePath dirPath) "run_cairo_vm.sh" (toFilePath outputFile : args) ""
|
||||
readProcessCwd (toFilePath dirPath) "run_cairo_vm.sh" (toFilePath outputFile : args) ""
|
||||
|
||||
casmRunVM :: LabelInfo -> Code -> [Builtin] -> Maybe (Path Abs File) -> Path Abs File -> (String -> IO ()) -> Assertion
|
||||
casmRunVM labi instrs blts inputFile expectedFile step = do
|
||||
|
@ -19,6 +19,7 @@ import Reg qualified
|
||||
import Repl qualified
|
||||
import Resolver qualified
|
||||
import Runtime qualified
|
||||
import Rust qualified
|
||||
import Scope qualified
|
||||
import Termination qualified
|
||||
import Tree qualified
|
||||
@ -38,6 +39,7 @@ slowTests =
|
||||
Internal.allTests,
|
||||
Compilation.allTests,
|
||||
Examples.allTests,
|
||||
Rust.allTests,
|
||||
Casm.allTests,
|
||||
VampIR.allTests,
|
||||
Anoma.allTests,
|
||||
|
@ -23,39 +23,6 @@ clangCompile mkClangArgs inputFile outputFile execute step =
|
||||
execute outputFile'
|
||||
)
|
||||
|
||||
-- | The same as `P.readProcess` but instead of inheriting `stderr` redirects it
|
||||
-- to the child's `stdout`.
|
||||
readProcess :: FilePath -> [String] -> Text -> IO Text
|
||||
readProcess = readProcessCwd' Nothing
|
||||
|
||||
readProcessCwd :: FilePath -> FilePath -> [String] -> Text -> IO Text
|
||||
readProcessCwd cwd = readProcessCwd' (Just cwd)
|
||||
|
||||
readProcessCwd' :: Maybe FilePath -> FilePath -> [String] -> Text -> IO Text
|
||||
readProcessCwd' mcwd cmd args stdinText =
|
||||
withTempDir'
|
||||
( \dirPath -> do
|
||||
(_, hin) <- openTempFile dirPath "stdin"
|
||||
(_, hout) <- openTempFile dirPath "stdout"
|
||||
hPutStr hin stdinText
|
||||
hSeek hin AbsoluteSeek 0
|
||||
(_, _, _, ph) <-
|
||||
P.createProcess_
|
||||
"readProcess"
|
||||
(P.proc cmd args)
|
||||
{ P.std_in = P.UseHandle hin,
|
||||
P.std_out = P.UseHandle hout,
|
||||
P.std_err = P.UseHandle hout,
|
||||
P.cwd = mcwd
|
||||
}
|
||||
P.waitForProcess ph
|
||||
hSeek hout AbsoluteSeek 0
|
||||
r <- hGetContents hout
|
||||
hClose hin
|
||||
hClose hout
|
||||
return r
|
||||
)
|
||||
|
||||
clangAssertion :: Int -> Path Abs File -> Path Abs File -> Text -> ((String -> IO ()) -> Assertion)
|
||||
clangAssertion optLevel inputFile expectedFile stdinText step = do
|
||||
step "Check clang and wasmer are on path"
|
||||
|
7
test/Rust.hs
Normal file
7
test/Rust.hs
Normal file
@ -0,0 +1,7 @@
|
||||
module Rust where
|
||||
|
||||
import Base
|
||||
import Rust.Compilation qualified as Compilation
|
||||
|
||||
allTests :: TestTree
|
||||
allTests = testGroup "Juvix to Rust tests" [Compilation.allTests]
|
7
test/Rust/Compilation.hs
Normal file
7
test/Rust/Compilation.hs
Normal file
@ -0,0 +1,7 @@
|
||||
module Rust.Compilation where
|
||||
|
||||
import Base
|
||||
import Rust.Compilation.Positive qualified as P
|
||||
|
||||
allTests :: TestTree
|
||||
allTests = testGroup "Juvix to native Rust compilation tests" [P.allTests, P.allTestsNoOptimize]
|
81
test/Rust/Compilation/Base.hs
Normal file
81
test/Rust/Compilation/Base.hs
Normal file
@ -0,0 +1,81 @@
|
||||
module Rust.Compilation.Base where
|
||||
|
||||
import Base
|
||||
import Data.FileEmbed
|
||||
import Juvix.Compiler.Backend.Rust.Data.Result
|
||||
import Juvix.Compiler.Backend.Rust.Pretty
|
||||
import Juvix.Compiler.Core qualified as Core
|
||||
import System.Process qualified as P
|
||||
|
||||
compileAssertion ::
|
||||
Path Abs Dir ->
|
||||
Int ->
|
||||
Path Abs File ->
|
||||
Path Abs File ->
|
||||
(String -> IO ()) ->
|
||||
Assertion
|
||||
compileAssertion root' optLevel mainFile expectedFile step = do
|
||||
step "Translate to JuvixCore"
|
||||
entryPoint <- testDefaultEntryPointIO root' mainFile
|
||||
PipelineResult {..} <- snd <$> testRunIO entryPoint upToStoredCore
|
||||
step "Translate to Rust"
|
||||
case run $ runError @JuvixError $ runReader entryPoint $ storedCoreToRust (_pipelineResult ^. Core.coreResultModule) of
|
||||
Left err -> assertFailure (prettyString (fromJuvixError @GenericError err))
|
||||
Right Result {..} -> do
|
||||
withTempDir'
|
||||
( \dirPath -> do
|
||||
let inputFile = dirPath <//> $(mkRelFile "Program.rs")
|
||||
writeFileEnsureLn inputFile _resultRustCode
|
||||
|
||||
step "Check rustc is on path"
|
||||
assertCmdExists $(mkRelFile "rustc")
|
||||
|
||||
expected <- readFile expectedFile
|
||||
|
||||
let executeNative :: Path Abs File -> IO Text
|
||||
executeNative outputFile = readProcess (toFilePath outputFile) [] ""
|
||||
|
||||
step "Compile Rust to native code"
|
||||
actualNative <- rustcCompile (nativeArgs optLevel) inputFile $(mkRelFile "Program") executeNative step
|
||||
step "Compare expected and actual program output"
|
||||
assertEqDiffText ("check: native output = " <> toFilePath expectedFile) actualNative expected
|
||||
)
|
||||
|
||||
rustcCompile ::
|
||||
(Path Abs File -> Path Abs File -> [String]) ->
|
||||
Path Abs File ->
|
||||
Path Rel File ->
|
||||
(Path Abs File -> IO Text) ->
|
||||
(String -> IO ()) ->
|
||||
IO Text
|
||||
rustcCompile mkRustcArgs inputFile outputFile execute step =
|
||||
withTempDir'
|
||||
( \dirPath -> do
|
||||
let outputFile' = dirPath <//> outputFile
|
||||
step "Rust compilation"
|
||||
P.callProcess
|
||||
"rustc"
|
||||
(mkRustcArgs outputFile' inputFile)
|
||||
step "Execution"
|
||||
execute outputFile'
|
||||
)
|
||||
|
||||
nativeArgs :: Int -> Path Abs File -> Path Abs File -> [String]
|
||||
nativeArgs optLevel outputFile inputFile =
|
||||
[ "-o",
|
||||
toFilePath outputFile,
|
||||
"-C",
|
||||
"opt-level="
|
||||
<> show optLevel,
|
||||
"-L",
|
||||
juvixLibraryDir,
|
||||
toFilePath inputFile
|
||||
]
|
||||
where
|
||||
juvixLibraryDir :: FilePath
|
||||
juvixLibraryDir =
|
||||
if
|
||||
| optLevel > 0 ->
|
||||
$(makeRelativeToProject "runtime/rust/target/release" >>= strToExp)
|
||||
| otherwise ->
|
||||
$(makeRelativeToProject "runtime/rust/target/debug" >>= strToExp)
|
348
test/Rust/Compilation/Positive.hs
Normal file
348
test/Rust/Compilation/Positive.hs
Normal file
@ -0,0 +1,348 @@
|
||||
module Rust.Compilation.Positive where
|
||||
|
||||
import Base
|
||||
import Data.HashSet qualified as HashSet
|
||||
import Rust.Compilation.Base
|
||||
|
||||
data PosTest = PosTest
|
||||
{ _name :: String,
|
||||
_dir :: Path Abs Dir,
|
||||
_file :: Path Abs File,
|
||||
_expectedFile :: Path Abs File
|
||||
}
|
||||
|
||||
makeLenses ''PosTest
|
||||
|
||||
root :: Path Abs Dir
|
||||
root = relToProject $(mkRelDir "tests/Rust/Compilation/positive/")
|
||||
|
||||
toTestDescr :: Int -> PosTest -> TestDescr
|
||||
toTestDescr optLevel PosTest {..} =
|
||||
let tRoot = _dir
|
||||
file' = _file
|
||||
expected' = _expectedFile
|
||||
in TestDescr
|
||||
{ _testName = _name,
|
||||
_testRoot = tRoot,
|
||||
_testAssertion = Steps $ compileAssertion _dir optLevel file' expected'
|
||||
}
|
||||
|
||||
allTests :: TestTree
|
||||
allTests =
|
||||
testGroup
|
||||
"Juvix to native Rust positive tests"
|
||||
(map (mkTest . toTestDescr 3) tests)
|
||||
|
||||
allTestsNoOptimize :: TestTree
|
||||
allTestsNoOptimize =
|
||||
testGroup
|
||||
"Juvix to native Rust positive tests (no optimization)"
|
||||
(map (mkTest . toTestDescr 0) tests)
|
||||
|
||||
posTest :: String -> Path Rel Dir -> Path Rel File -> Path Rel File -> PosTest
|
||||
posTest _name rdir rfile routfile =
|
||||
let _dir = root <//> rdir
|
||||
_file = _dir <//> rfile
|
||||
_expectedFile = root <//> routfile
|
||||
in PosTest {..}
|
||||
|
||||
isIgnored :: PosTest -> Bool
|
||||
isIgnored t = HashSet.member (t ^. name) ignored
|
||||
|
||||
ignored :: HashSet String
|
||||
ignored =
|
||||
HashSet.fromList
|
||||
[ -- strings not supported (Partial trait)
|
||||
"Test026: Functional queues"
|
||||
]
|
||||
|
||||
tests :: [PosTest]
|
||||
tests =
|
||||
filter
|
||||
(not . isIgnored)
|
||||
[ posTest
|
||||
"Test001: Arithmetic operators"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test001.juvix")
|
||||
$(mkRelFile "out/test001.out"),
|
||||
posTest
|
||||
"Test002: Arithmetic operators inside lambdas"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test002.juvix")
|
||||
$(mkRelFile "out/test002.out"),
|
||||
posTest
|
||||
"Test003: Integer arithmetic"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test003.juvix")
|
||||
$(mkRelFile "out/test003.out"),
|
||||
posTest
|
||||
"Test005: Higher-order functions"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test005.juvix")
|
||||
$(mkRelFile "out/test005.out"),
|
||||
posTest
|
||||
"Test006: If-then-else and lazy boolean operators"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test006.juvix")
|
||||
$(mkRelFile "out/test006.out"),
|
||||
posTest
|
||||
"Test007: Pattern matching and lambda-case"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test007.juvix")
|
||||
$(mkRelFile "out/test007.out"),
|
||||
posTest
|
||||
"Test008: Recursion"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test008.juvix")
|
||||
$(mkRelFile "out/test008.out"),
|
||||
posTest
|
||||
"Test009: Tail recursion"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test009.juvix")
|
||||
$(mkRelFile "out/test009.out"),
|
||||
posTest
|
||||
"Test010: Let"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test010.juvix")
|
||||
$(mkRelFile "out/test010.out"),
|
||||
posTest
|
||||
"Test013: Functions returning functions with variable capture"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test013.juvix")
|
||||
$(mkRelFile "out/test013.out"),
|
||||
posTest
|
||||
"Test014: Arithmetic"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test014.juvix")
|
||||
$(mkRelFile "out/test014.out"),
|
||||
posTest
|
||||
"Test015: Local functions with free variables"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test015.juvix")
|
||||
$(mkRelFile "out/test015.out"),
|
||||
posTest
|
||||
"Test016: Recursion through higher-order functions"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test016.juvix")
|
||||
$(mkRelFile "out/test016.out"),
|
||||
posTest
|
||||
"Test017: Tail recursion through higher-order functions"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test017.juvix")
|
||||
$(mkRelFile "out/test017.out"),
|
||||
posTest
|
||||
"Test018: Higher-order functions and recursion"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test018.juvix")
|
||||
$(mkRelFile "out/test018.out"),
|
||||
posTest
|
||||
"Test019: Self-application"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test019.juvix")
|
||||
$(mkRelFile "out/test019.out"),
|
||||
posTest
|
||||
"Test020: Recursive functions: McCarthy's 91 function, subtraction by increments"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test020.juvix")
|
||||
$(mkRelFile "out/test020.out"),
|
||||
posTest
|
||||
"Test021: Fast exponentiation"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test021.juvix")
|
||||
$(mkRelFile "out/test021.out"),
|
||||
posTest
|
||||
"Test022: Lists"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test022.juvix")
|
||||
$(mkRelFile "out/test022.out"),
|
||||
posTest
|
||||
"Test023: Mutual recursion"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test023.juvix")
|
||||
$(mkRelFile "out/test023.out"),
|
||||
posTest
|
||||
"Test024: Nested binders with variable capture"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test024.juvix")
|
||||
$(mkRelFile "out/test024.out"),
|
||||
posTest
|
||||
"Test025: Euclid's algorithm"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test025.juvix")
|
||||
$(mkRelFile "out/test025.out"),
|
||||
posTest
|
||||
"Test026: Functional queues"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test026.juvix")
|
||||
$(mkRelFile "out/test026.out"),
|
||||
posTest
|
||||
"Test028: Streams without memoization"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test028.juvix")
|
||||
$(mkRelFile "out/test028.out"),
|
||||
posTest
|
||||
"Test029: Ackermann function"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test029.juvix")
|
||||
$(mkRelFile "out/test029.out"),
|
||||
posTest
|
||||
"Test030: Ackermann function (higher-order definition)"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test030.juvix")
|
||||
$(mkRelFile "out/test030.out"),
|
||||
posTest
|
||||
"Test032: Merge sort"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test032.juvix")
|
||||
$(mkRelFile "out/test032.out"),
|
||||
posTest
|
||||
"Test033: Eta-expansion of builtins and constructors"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test033.juvix")
|
||||
$(mkRelFile "out/test033.out"),
|
||||
posTest
|
||||
"Test034: Recursive let"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test034.juvix")
|
||||
$(mkRelFile "out/test034.out"),
|
||||
posTest
|
||||
"Test035: Pattern matching"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test035.juvix")
|
||||
$(mkRelFile "out/test035.out"),
|
||||
posTest
|
||||
"Test036: Eta-expansion"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test036.juvix")
|
||||
$(mkRelFile "out/test036.out"),
|
||||
posTest
|
||||
"Test037: Applications with lets and cases in function position"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test037.juvix")
|
||||
$(mkRelFile "out/test037.out"),
|
||||
posTest
|
||||
"Test038: Simple case expression"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test038.juvix")
|
||||
$(mkRelFile "out/test038.out"),
|
||||
posTest
|
||||
"Test039: Mutually recursive let expression"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test039.juvix")
|
||||
$(mkRelFile "out/test039.out"),
|
||||
posTest
|
||||
"Test040: Pattern matching nullary constructor"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test040.juvix")
|
||||
$(mkRelFile "out/test040.out"),
|
||||
posTest
|
||||
"Test045: Implicit builtin bool"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test045.juvix")
|
||||
$(mkRelFile "out/test045.out"),
|
||||
posTest
|
||||
"Test046: Polymorphic type arguments"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test046.juvix")
|
||||
$(mkRelFile "out/test046.out"),
|
||||
posTest
|
||||
"Test047: Local Modules"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test047.juvix")
|
||||
$(mkRelFile "out/test047.out"),
|
||||
posTest
|
||||
"Test050: Pattern matching with integers"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test050.juvix")
|
||||
$(mkRelFile "out/test050.out"),
|
||||
posTest
|
||||
"Test053: Inlining"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test053.juvix")
|
||||
$(mkRelFile "out/test053.out"),
|
||||
posTest
|
||||
"Test054: Iterators"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test054.juvix")
|
||||
$(mkRelFile "out/test054.out"),
|
||||
posTest
|
||||
"Test056: Argument specialization"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test056.juvix")
|
||||
$(mkRelFile "out/test056.out"),
|
||||
posTest
|
||||
"Test057: Case folding"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test057.juvix")
|
||||
$(mkRelFile "out/test057.out"),
|
||||
posTest
|
||||
"Test058: Ranges"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test058.juvix")
|
||||
$(mkRelFile "out/test058.out"),
|
||||
posTest
|
||||
"Test059: Builtin list"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test059.juvix")
|
||||
$(mkRelFile "out/test059.out"),
|
||||
posTest
|
||||
"Test060: Record update"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test060.juvix")
|
||||
$(mkRelFile "out/test060.out"),
|
||||
posTest
|
||||
"Test062: Overapplication"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test062.juvix")
|
||||
$(mkRelFile "out/test062.out"),
|
||||
posTest
|
||||
"Test064: Constant folding"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test064.juvix")
|
||||
$(mkRelFile "out/test064.out"),
|
||||
posTest
|
||||
"Test065: Arithmetic simplification"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test065.juvix")
|
||||
$(mkRelFile "out/test065.out"),
|
||||
posTest
|
||||
"Test066: Import function with a function call in default argument"
|
||||
$(mkRelDir "test066")
|
||||
$(mkRelFile "M.juvix")
|
||||
$(mkRelFile "out/test066.out"),
|
||||
posTest
|
||||
"Test067: Dependent default values inserted during translation FromConcrete"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test067.juvix")
|
||||
$(mkRelFile "out/test067.out"),
|
||||
posTest
|
||||
"Test068: Dependent default values inserted in the arity checker"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test068.juvix")
|
||||
$(mkRelFile "out/test068.out"),
|
||||
posTest
|
||||
"Test069: Dependent default values for Ord trait"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test069.juvix")
|
||||
$(mkRelFile "out/test069.out"),
|
||||
posTest
|
||||
"Test070: Nested default values and named arguments"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test070.juvix")
|
||||
$(mkRelFile "out/test070.out"),
|
||||
posTest
|
||||
"Test071: Named application (Ord instance with default cmp)"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test071.juvix")
|
||||
$(mkRelFile "out/test071.out"),
|
||||
posTest
|
||||
"Test072: Monad transformers (ReaderT + StateT + Identity)"
|
||||
$(mkRelDir "test072")
|
||||
$(mkRelFile "ReaderT.juvix")
|
||||
$(mkRelFile "out/test072.out"),
|
||||
posTest
|
||||
"Test073: Import and use a syntax alias"
|
||||
$(mkRelDir "test073")
|
||||
$(mkRelFile "test073.juvix")
|
||||
$(mkRelFile "out/test073.out")
|
||||
]
|
1
tests/Rust/Compilation/positive/out/test001.out
Normal file
1
tests/Rust/Compilation/positive/out/test001.out
Normal file
@ -0,0 +1 @@
|
||||
11
|
1
tests/Rust/Compilation/positive/out/test002.out
Normal file
1
tests/Rust/Compilation/positive/out/test002.out
Normal file
@ -0,0 +1 @@
|
||||
11
|
1
tests/Rust/Compilation/positive/out/test003.out
Normal file
1
tests/Rust/Compilation/positive/out/test003.out
Normal file
@ -0,0 +1 @@
|
||||
11
|
1
tests/Rust/Compilation/positive/out/test005.out
Normal file
1
tests/Rust/Compilation/positive/out/test005.out
Normal file
@ -0,0 +1 @@
|
||||
6
|
1
tests/Rust/Compilation/positive/out/test006.out
Normal file
1
tests/Rust/Compilation/positive/out/test006.out
Normal file
@ -0,0 +1 @@
|
||||
3
|
1
tests/Rust/Compilation/positive/out/test007.out
Normal file
1
tests/Rust/Compilation/positive/out/test007.out
Normal file
@ -0,0 +1 @@
|
||||
6
|
1
tests/Rust/Compilation/positive/out/test008.out
Normal file
1
tests/Rust/Compilation/positive/out/test008.out
Normal file
@ -0,0 +1 @@
|
||||
50005000
|
1
tests/Rust/Compilation/positive/out/test009.out
Normal file
1
tests/Rust/Compilation/positive/out/test009.out
Normal file
@ -0,0 +1 @@
|
||||
532635520
|
1
tests/Rust/Compilation/positive/out/test010.out
Normal file
1
tests/Rust/Compilation/positive/out/test010.out
Normal file
@ -0,0 +1 @@
|
||||
32
|
1
tests/Rust/Compilation/positive/out/test013.out
Normal file
1
tests/Rust/Compilation/positive/out/test013.out
Normal file
@ -0,0 +1 @@
|
||||
8
|
1
tests/Rust/Compilation/positive/out/test014.out
Normal file
1
tests/Rust/Compilation/positive/out/test014.out
Normal file
@ -0,0 +1 @@
|
||||
92
|
1
tests/Rust/Compilation/positive/out/test015.out
Normal file
1
tests/Rust/Compilation/positive/out/test015.out
Normal file
@ -0,0 +1 @@
|
||||
771
|
1
tests/Rust/Compilation/positive/out/test016.out
Normal file
1
tests/Rust/Compilation/positive/out/test016.out
Normal file
@ -0,0 +1 @@
|
||||
55
|
1
tests/Rust/Compilation/positive/out/test017.out
Normal file
1
tests/Rust/Compilation/positive/out/test017.out
Normal file
@ -0,0 +1 @@
|
||||
50005000
|
1
tests/Rust/Compilation/positive/out/test018.out
Normal file
1
tests/Rust/Compilation/positive/out/test018.out
Normal file
@ -0,0 +1 @@
|
||||
11
|
1
tests/Rust/Compilation/positive/out/test019.out
Normal file
1
tests/Rust/Compilation/positive/out/test019.out
Normal file
@ -0,0 +1 @@
|
||||
7
|
1
tests/Rust/Compilation/positive/out/test020.out
Normal file
1
tests/Rust/Compilation/positive/out/test020.out
Normal file
@ -0,0 +1 @@
|
||||
4876
|
1
tests/Rust/Compilation/positive/out/test021.out
Normal file
1
tests/Rust/Compilation/positive/out/test021.out
Normal file
@ -0,0 +1 @@
|
||||
80320
|
1
tests/Rust/Compilation/positive/out/test022.out
Normal file
1
tests/Rust/Compilation/positive/out/test022.out
Normal file
@ -0,0 +1 @@
|
||||
100010000
|
1
tests/Rust/Compilation/positive/out/test023.out
Normal file
1
tests/Rust/Compilation/positive/out/test023.out
Normal file
@ -0,0 +1 @@
|
||||
6386010
|
1
tests/Rust/Compilation/positive/out/test024.out
Normal file
1
tests/Rust/Compilation/positive/out/test024.out
Normal file
@ -0,0 +1 @@
|
||||
6688
|
1
tests/Rust/Compilation/positive/out/test025.out
Normal file
1
tests/Rust/Compilation/positive/out/test025.out
Normal file
@ -0,0 +1 @@
|
||||
87
|
1
tests/Rust/Compilation/positive/out/test026.out
Normal file
1
tests/Rust/Compilation/positive/out/test026.out
Normal file
@ -0,0 +1 @@
|
||||
5050
|
1
tests/Rust/Compilation/positive/out/test028.out
Normal file
1
tests/Rust/Compilation/positive/out/test028.out
Normal file
@ -0,0 +1 @@
|
||||
2040
|
1
tests/Rust/Compilation/positive/out/test029.out
Normal file
1
tests/Rust/Compilation/positive/out/test029.out
Normal file
@ -0,0 +1 @@
|
||||
78
|
1
tests/Rust/Compilation/positive/out/test030.out
Normal file
1
tests/Rust/Compilation/positive/out/test030.out
Normal file
@ -0,0 +1 @@
|
||||
2247
|
1
tests/Rust/Compilation/positive/out/test032.out
Normal file
1
tests/Rust/Compilation/positive/out/test032.out
Normal file
@ -0,0 +1 @@
|
||||
195
|
1
tests/Rust/Compilation/positive/out/test033.out
Normal file
1
tests/Rust/Compilation/positive/out/test033.out
Normal file
@ -0,0 +1 @@
|
||||
31
|
1
tests/Rust/Compilation/positive/out/test034.out
Normal file
1
tests/Rust/Compilation/positive/out/test034.out
Normal file
@ -0,0 +1 @@
|
||||
501527
|
1
tests/Rust/Compilation/positive/out/test035.out
Normal file
1
tests/Rust/Compilation/positive/out/test035.out
Normal file
@ -0,0 +1 @@
|
||||
34422
|
1
tests/Rust/Compilation/positive/out/test036.out
Normal file
1
tests/Rust/Compilation/positive/out/test036.out
Normal file
@ -0,0 +1 @@
|
||||
18
|
1
tests/Rust/Compilation/positive/out/test037.out
Normal file
1
tests/Rust/Compilation/positive/out/test037.out
Normal file
@ -0,0 +1 @@
|
||||
9
|
1
tests/Rust/Compilation/positive/out/test038.out
Normal file
1
tests/Rust/Compilation/positive/out/test038.out
Normal file
@ -0,0 +1 @@
|
||||
1
|
1
tests/Rust/Compilation/positive/out/test039.out
Normal file
1
tests/Rust/Compilation/positive/out/test039.out
Normal file
@ -0,0 +1 @@
|
||||
1
|
1
tests/Rust/Compilation/positive/out/test040.out
Normal file
1
tests/Rust/Compilation/positive/out/test040.out
Normal file
@ -0,0 +1 @@
|
||||
1
|
1
tests/Rust/Compilation/positive/out/test045.out
Normal file
1
tests/Rust/Compilation/positive/out/test045.out
Normal file
@ -0,0 +1 @@
|
||||
4
|
1
tests/Rust/Compilation/positive/out/test046.out
Normal file
1
tests/Rust/Compilation/positive/out/test046.out
Normal file
@ -0,0 +1 @@
|
||||
7
|
1
tests/Rust/Compilation/positive/out/test047.out
Normal file
1
tests/Rust/Compilation/positive/out/test047.out
Normal file
@ -0,0 +1 @@
|
||||
660
|
1
tests/Rust/Compilation/positive/out/test050.out
Normal file
1
tests/Rust/Compilation/positive/out/test050.out
Normal file
@ -0,0 +1 @@
|
||||
11
|
1
tests/Rust/Compilation/positive/out/test053.out
Normal file
1
tests/Rust/Compilation/positive/out/test053.out
Normal file
@ -0,0 +1 @@
|
||||
21
|
1
tests/Rust/Compilation/positive/out/test054.out
Normal file
1
tests/Rust/Compilation/positive/out/test054.out
Normal file
@ -0,0 +1 @@
|
||||
189
|
1
tests/Rust/Compilation/positive/out/test056.out
Normal file
1
tests/Rust/Compilation/positive/out/test056.out
Normal file
@ -0,0 +1 @@
|
||||
69
|
1
tests/Rust/Compilation/positive/out/test057.out
Normal file
1
tests/Rust/Compilation/positive/out/test057.out
Normal file
@ -0,0 +1 @@
|
||||
8
|
1
tests/Rust/Compilation/positive/out/test058.out
Normal file
1
tests/Rust/Compilation/positive/out/test058.out
Normal file
@ -0,0 +1 @@
|
||||
7550
|
1
tests/Rust/Compilation/positive/out/test059.out
Normal file
1
tests/Rust/Compilation/positive/out/test059.out
Normal file
@ -0,0 +1 @@
|
||||
11
|
1
tests/Rust/Compilation/positive/out/test060.out
Normal file
1
tests/Rust/Compilation/positive/out/test060.out
Normal file
@ -0,0 +1 @@
|
||||
42
|
1
tests/Rust/Compilation/positive/out/test062.out
Normal file
1
tests/Rust/Compilation/positive/out/test062.out
Normal file
@ -0,0 +1 @@
|
||||
1
|
1
tests/Rust/Compilation/positive/out/test064.out
Normal file
1
tests/Rust/Compilation/positive/out/test064.out
Normal file
@ -0,0 +1 @@
|
||||
37
|
1
tests/Rust/Compilation/positive/out/test065.out
Normal file
1
tests/Rust/Compilation/positive/out/test065.out
Normal file
@ -0,0 +1 @@
|
||||
42
|
1
tests/Rust/Compilation/positive/out/test066.out
Normal file
1
tests/Rust/Compilation/positive/out/test066.out
Normal file
@ -0,0 +1 @@
|
||||
0
|
1
tests/Rust/Compilation/positive/out/test067.out
Normal file
1
tests/Rust/Compilation/positive/out/test067.out
Normal file
@ -0,0 +1 @@
|
||||
30
|
1
tests/Rust/Compilation/positive/out/test068.out
Normal file
1
tests/Rust/Compilation/positive/out/test068.out
Normal file
@ -0,0 +1 @@
|
||||
30
|
1
tests/Rust/Compilation/positive/out/test069.out
Normal file
1
tests/Rust/Compilation/positive/out/test069.out
Normal file
@ -0,0 +1 @@
|
||||
1
|
1
tests/Rust/Compilation/positive/out/test070.out
Normal file
1
tests/Rust/Compilation/positive/out/test070.out
Normal file
@ -0,0 +1 @@
|
||||
1463
|
1
tests/Rust/Compilation/positive/out/test071.out
Normal file
1
tests/Rust/Compilation/positive/out/test071.out
Normal file
@ -0,0 +1 @@
|
||||
1528
|
1
tests/Rust/Compilation/positive/out/test072.out
Normal file
1
tests/Rust/Compilation/positive/out/test072.out
Normal file
@ -0,0 +1 @@
|
||||
10
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user