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

Fix bug in IO runtime #1906

Merged
merged 5 commits into from
Mar 21, 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
6 changes: 5 additions & 1 deletion runtime/src/juvix/arch/wasi.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@

_Noreturn void exit(int code) { proc_exit(code); }

void puts(const char *msg) {
void puts_nonl(const char *msg) {
size_t n = 0;
while (msg[n]) ++n;
ciovec_t vec = {.buf = (uint8_t *)msg, .buf_len = n};
fd_write(1, &vec, 1, 0);
}

void puts(const char *msg) {
puts_nonl(msg);
uint8_t c = '\n';
ciovec_t vec1 = {.buf = &c, .buf_len = 1};
fd_write(1, &vec1, 1, 0);
Expand Down
1 change: 1 addition & 0 deletions runtime/src/juvix/arch/wasi.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

_Noreturn void exit(int code);

void puts_nonl(const char *str);
void puts(const char *str);

typedef struct Ciovec {
Expand Down
10 changes: 9 additions & 1 deletion runtime/src/juvix/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,20 @@ extern int errno;
/**********************************************/
/* Basic primitive functions and macros */

static void print_msg(const char *msg) {
static inline void print_msg(const char *msg) {
#if defined(API_LIBC) || defined(API_WASI)
puts(msg);
#endif
}

static inline void print_msg_nonl(const char *msg) {
#if defined(API_LIBC)
fputs(msg, stdout);
#elif defined(API_WASI)
puts_nonl(msg);
#endif
}

_Noreturn static inline void error_exit() {
#if defined(API_LIBC)
abort();
Expand Down
7 changes: 6 additions & 1 deletion runtime/src/juvix/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ void io_flush() {
io_index = 0;
#else
io_buffer[io_index] = 0;
print_msg(io_buffer);
print_msg_nonl(io_buffer);
io_index = 0;
#endif
}
Expand Down Expand Up @@ -84,6 +84,11 @@ static word_t io_readln() {
error_exit_msg("read error");
}
io_buffer[MAX_CSTRING_LENGTH - 1] = 0;
// remove trailing newline
size_t len = strlen(io_buffer);
if (len > 0) {
io_buffer[len - 1] = 0;
}
return alloc_cstring(io_buffer);
#elif defined(API_WASI)
io_flush();
Expand Down
1 change: 1 addition & 0 deletions runtime/src/juvix/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ bool io_interpret(word_t x, word_t *ret, word_t *arg);
CALL_CLOSURE(juvix_io_ret, juvix_io_interpret_label_1); \
STACK_LEAVE; \
} else { \
RESTORE_MEMORY_POINTERS; \
juvix_result = juvix_io_ret; \
RETURN_NS; \
} \
Expand Down
14 changes: 11 additions & 3 deletions src/Juvix/Compiler/Asm/Pretty/Base.hs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ quoteAsmName txt =
(":", "__colon__")
]

quoteAsmFunName :: Text -> Text
quoteAsmFunName txt =
foldr
(uncurry Text.replace)
txt
[ ("readLn", "__readLn__")
]

ppConstrName :: (Member (Reader Options) r) => Tag -> Sem r (Doc Ann)
ppConstrName tag = do
opts <- ask
Expand All @@ -70,7 +78,7 @@ ppFunName sym = do
annotate (AnnKind KNameFunction) $
pretty ("unnamed_function_" ++ show sym :: String)
)
(\fi -> return $ annotate (AnnKind KNameFunction) (pretty (quoteAsmName (fi ^. functionName))))
(\fi -> return $ annotate (AnnKind KNameFunction) (pretty (quoteAsmFunName $ quoteAsmName (fi ^. functionName))))
(HashMap.lookup sym (tab ^. infoFunctions))

instance PrettyCode BuiltinDataTag where
Expand Down Expand Up @@ -342,7 +350,7 @@ instance PrettyCode FunctionInfo where
c <- ppCodeCode _functionCode
return $
keyword Str.function
<+> annotate (AnnKind KNameFunction) (pretty _functionName)
<+> annotate (AnnKind KNameFunction) (pretty (quoteAsmFunName $ quoteAsmName _functionName))
<> encloseSep lparen rparen ", " argtys
<+> colon
<+> targetty
Expand All @@ -354,7 +362,7 @@ ppFunSig FunctionInfo {..} = do
targetty <- ppCode (typeTarget _functionType)
return $
keyword Str.function
<+> annotate (AnnKind KNameFunction) (pretty (quoteAsmName _functionName))
<+> annotate (AnnKind KNameFunction) (pretty (quoteAsmFunName $ quoteAsmName _functionName))
<> encloseSep lparen rparen ", " argtys
<+> colon
<+> targetty
Expand Down
12 changes: 6 additions & 6 deletions test/Asm/Compile/Base.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import Juvix.Compiler.Backend.C qualified as C
import Juvix.Compiler.Pipeline qualified as Pipeline
import Runtime.Base qualified as Runtime

asmCompileAssertion' :: InfoTable -> Path Abs File -> Path Abs File -> (String -> IO ()) -> Assertion
asmCompileAssertion' tab mainFile expectedFile step = do
asmCompileAssertion' :: InfoTable -> Path Abs File -> Path Abs File -> Text -> (String -> IO ()) -> Assertion
asmCompileAssertion' tab mainFile expectedFile stdinText step = do
step "Generate C code"
case run $ runError @JuvixError $ Pipeline.asmToMiniC asmOpts tab of
Left e -> do
Expand All @@ -23,16 +23,16 @@ asmCompileAssertion' tab mainFile expectedFile step = do
( \dirPath -> do
let cFile = dirPath <//> replaceExtension' ".c" (filename mainFile)
TIO.writeFile (toFilePath cFile) _resultCCode
Runtime.clangAssertion cFile expectedFile "" step
Runtime.clangAssertion cFile expectedFile stdinText step
)
where
asmOpts :: Options
asmOpts = makeOptions Backend.TargetCNative64 True

asmCompileAssertion :: Path Abs File -> Path Abs File -> (String -> IO ()) -> Assertion
asmCompileAssertion mainFile expectedFile step = do
asmCompileAssertion :: Path Abs File -> Path Abs File -> Text -> (String -> IO ()) -> Assertion
asmCompileAssertion mainFile expectedFile stdinText step = do
step "Parse"
s <- readFile (toFilePath mainFile)
case runParser (toFilePath mainFile) s of
Left err -> assertFailure (show err)
Right tab -> asmCompileAssertion' tab mainFile expectedFile step
Right tab -> asmCompileAssertion' tab mainFile expectedFile stdinText step
2 changes: 1 addition & 1 deletion test/Asm/Compile/Positive.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ testDescr Run.PosTest {..} =
in TestDescr
{ _testName = _name,
_testRoot = tRoot,
_testAssertion = Steps $ asmCompileAssertion file' expected'
_testAssertion = Steps $ asmCompileAssertion file' expected' ""
}

allTests :: TestTree
Expand Down
19 changes: 14 additions & 5 deletions test/Compilation/Base.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,29 @@ import Juvix.Compiler.Core.Translation.FromInternal.Data qualified as Core
import Juvix.Compiler.Pipeline
import Juvix.Data.PPOutput

data CompileAssertionMode
= EvalOnly
| -- | Specify text to be sent to stdin of the process under test
CompileOnly Text
| EvalAndCompile

compileAssertion ::
Bool ->
CompileAssertionMode ->
Path Abs File ->
Path Abs File ->
(String -> IO ()) ->
Assertion
compileAssertion onlyEval mainFile expectedFile step = do
compileAssertion mode mainFile expectedFile step = do
step "Translate to JuvixCore"
cwd <- getCurrentDir
let entryPoint = defaultEntryPoint cwd mainFile
tab <- (^. Core.coreResultTable) . snd <$> runIO' iniState entryPoint upToCore
case run $ runError $ Core.toEval tab of
Left err -> assertFailure (show (pretty (fromJuvixError @GenericError err)))
Right tab' -> do
coreEvalAssertion' tab' mainFile expectedFile step
unless onlyEval $
coreCompileAssertion' tab' mainFile expectedFile step
let evalAssertion = coreEvalAssertion' tab' mainFile expectedFile step
compileAssertion' stdinText = coreCompileAssertion' tab' mainFile expectedFile stdinText step
case mode of
EvalOnly -> evalAssertion
CompileOnly stdinText -> compileAssertion' stdinText
EvalAndCompile -> evalAssertion >> compileAssertion' ""
27 changes: 20 additions & 7 deletions test/Compilation/Positive.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ data PosTest = PosTest
{ _name :: String,
_dir :: Path Abs Dir,
_file :: Path Abs File,
_onlyEval :: Bool,
_assertionMode :: CompileAssertionMode,
_expectedFile :: Path Abs File
}

Expand All @@ -27,7 +27,7 @@ toTestDescr PosTest {..} =
in TestDescr
{ _testName = _name,
_testRoot = tRoot,
_testAssertion = Steps $ compileAssertion _onlyEval file' expected'
_testAssertion = Steps $ compileAssertion _assertionMode file' expected'
}

allTests :: TestTree
Expand All @@ -36,19 +36,26 @@ allTests =
"Juvix compilation pipeline positive tests"
(map (mkTest . toTestDescr) tests)

posTest' :: Bool -> String -> Path Rel Dir -> Path Rel File -> Path Rel File -> PosTest
posTest' _onlyEval _name rdir rfile routfile =
posTest' :: CompileAssertionMode -> String -> Path Rel Dir -> Path Rel File -> Path Rel File -> PosTest
posTest' _assertionMode _name rdir rfile routfile =
let _dir = root <//> rdir
_file = _dir <//> rfile
_expectedFile = root <//> routfile
in PosTest {..}

posTestStdin :: String -> Path Rel Dir -> Path Rel File -> Path Rel File -> Text -> PosTest
posTestStdin _name rdir rfile routfile _stdinText =
let t = posTest _name rdir rfile routfile
in t
{ _assertionMode = CompileOnly _stdinText
}

posTest :: String -> Path Rel Dir -> Path Rel File -> Path Rel File -> PosTest
posTest = posTest' False
posTest = posTest' EvalAndCompile

-- tests which use large integers are only evaluated but not compiled
posTestEval :: String -> Path Rel Dir -> Path Rel File -> Path Rel File -> PosTest
posTestEval = posTest' True
posTestEval = posTest' EvalOnly

tests :: [PosTest]
tests =
Expand Down Expand Up @@ -266,5 +273,11 @@ tests =
"Builtin trace"
$(mkRelDir ".")
$(mkRelFile "test043.juvix")
$(mkRelFile "out/test043.out")
$(mkRelFile "out/test043.out"),
posTestStdin
"Builtin readline"
$(mkRelDir ".")
$(mkRelFile "test044.juvix")
$(mkRelFile "out/test044.out")
"a\n"
]
12 changes: 7 additions & 5 deletions test/Core/Compile/Base.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,30 +32,32 @@ toTestDescr Test {..} =
in TestDescr
{ _testName = _name,
_testRoot = tRoot,
_testAssertion = Steps $ coreCompileAssertion file' expected'
_testAssertion = Steps $ coreCompileAssertion file' expected' ""
}

coreCompileAssertion' ::
InfoTable ->
Path Abs File ->
Path Abs File ->
Text ->
(String -> IO ()) ->
Assertion
coreCompileAssertion' tab mainFile expectedFile step = do
coreCompileAssertion' tab mainFile expectedFile stdinText step = do
step "Translate to JuvixAsm"
case run $ runError $ toStripped tab of
Left err -> assertFailure (show (pretty (fromJuvixError @GenericError err)))
Right tab0 -> do
let tab' = Asm.fromCore $ Stripped.fromCore $ tab0
length (fromText (Asm.ppPrint tab' tab') :: String) `seq`
Asm.asmCompileAssertion' tab' mainFile expectedFile step
Asm.asmCompileAssertion' tab' mainFile expectedFile stdinText step

coreCompileAssertion ::
Path Abs File ->
Path Abs File ->
Text ->
(String -> IO ()) ->
Assertion
coreCompileAssertion mainFile expectedFile step = do
coreCompileAssertion mainFile expectedFile stdinText step = do
step "Parse"
r <- parseFile mainFile
case r of
Expand All @@ -65,4 +67,4 @@ coreCompileAssertion mainFile expectedFile step = do
expected <- TIO.readFile (toFilePath expectedFile)
assertEqDiffText ("Check: EVAL output = " <> toFilePath expectedFile) "" expected
Right (tabIni, Just node) ->
coreCompileAssertion' (setupMainFunction tabIni node) mainFile expectedFile step
coreCompileAssertion' (setupMainFunction tabIni node) mainFile expectedFile stdinText step
1 change: 1 addition & 0 deletions tests/Compilation/positive/out/test044.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
a
10 changes: 10 additions & 0 deletions tests/Compilation/positive/test044.juvix
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- Builtin readline
module test044;

builtin string axiom String : Type;
builtin IO axiom IO : Type;
builtin IO-readline axiom readLn : (String → IO) → IO;
builtin string-print axiom printString : String → IO;

main : IO;
main := readLn printString;