From a31e079f93d827141c1b6554c2b2c8cd07160f3e Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Thu, 27 Aug 2020 07:46:00 -0500 Subject: [PATCH] Fix import macro to not coerce everything to string. --- CHANGELOG.md | 2 ++ src/boot/boot.janet | 3 ++- src/core/io.c | 27 ++++++++++++++++++--------- src/include/janet.h | 1 + test/suite0010.janet | 4 ++++ 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a41ed2b..0078e527 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. ## Unreleased - ??? +- Add `:n` flag to `file/open` to raise an error if file cannot be opened. +- Fix import macro to not try and coerce everything to a string. - Allow passing a second argument to `disasm`. - Add `cancel`. Resumes a fiber but makes it immediately error at the yield point. - Allow multi-line paste into built in repl. diff --git a/src/boot/boot.janet b/src/boot/boot.janet index e6f0fcf0..4a465207 100644 --- a/src/boot/boot.janet +++ b/src/boot/boot.janet @@ -2475,7 +2475,8 @@ to be called. Dynamic bindings will NOT be imported. Use :fresh to bypass the module cache." [path & args] - (def argm (map |(if (keyword? $) $ (string $)) args)) + (def ps (partition 2 args)) + (def argm (mapcat (fn [[k v]] [k (if (= k :as) (string v) v)]) ps)) (tuple import* (string path) ;argm)) (defmacro use diff --git a/src/core/io.c b/src/core/io.c index d6db1476..d62a0f7a 100644 --- a/src/core/io.c +++ b/src/core/io.c @@ -56,8 +56,8 @@ static int32_t checkflags(const uint8_t *str) { int32_t flags = 0; int32_t i; int32_t len = janet_string_length(str); - if (!len || len > 3) - janet_panic("file mode must have a length between 1 and 3"); + if (!len || len > 10) + janet_panic("file mode must have a length between 1 and 10"); switch (*str) { default: janet_panicf("invalid flag %c, expected w, a, or r", *str); @@ -75,7 +75,7 @@ static int32_t checkflags(const uint8_t *str) { for (i = 1; i < len; i++) { switch (str[i]) { default: - janet_panicf("invalid flag %c, expected + or b", str[i]); + janet_panicf("invalid flag %c, expected +, b, or n", str[i]); break; case '+': if (flags & JANET_FILE_UPDATE) return -1; @@ -85,6 +85,10 @@ static int32_t checkflags(const uint8_t *str) { if (flags & JANET_FILE_BINARY) return -1; flags |= JANET_FILE_BINARY; break; + case 'n': + if (flags & JANET_FILE_NONIL) return -1; + flags |= JANET_FILE_NONIL; + break; } } return flags; @@ -112,11 +116,11 @@ static Janet cfun_io_popen(int32_t argc, Janet *argv) { int32_t flags; if (argc == 2) { fmode = janet_getkeyword(argv, 1); - if (janet_string_length(fmode) != 1 || - !(fmode[0] == 'r' || fmode[0] == 'w')) { - janet_panicf("invalid file mode :%S, expected :r or :w", fmode); + flags = JANET_FILE_PIPED | checkflags(fmode); + if (flags & (JANET_FILE_UPDATE | JANET_FILE_BINARY | JANET_FILE_APPEND)) { + janet_panicf("invalid popen file mode :%S, expected :r or :w", fmode); } - flags = JANET_FILE_PIPED | (fmode[0] == 'r' ? JANET_FILE_READ : JANET_FILE_WRITE); + fmode = (const uint8_t *)((fmode[0] == 'r') ? "r" : "w"); } else { fmode = (const uint8_t *)"r"; flags = JANET_FILE_PIPED | JANET_FILE_READ; @@ -126,6 +130,8 @@ static Janet cfun_io_popen(int32_t argc, Janet *argv) { #endif FILE *f = popen((const char *)fname, (const char *)fmode); if (!f) { + if (flags & JANET_FILE_NONIL) + janet_panicf("failed to popen %s: %s", fname, strerror(errno)); return janet_wrap_nil(); } return janet_makefile(f, flags); @@ -155,7 +161,9 @@ static Janet cfun_io_fopen(int32_t argc, Janet *argv) { flags = JANET_FILE_READ; } FILE *f = fopen((const char *)fname, (const char *)fmode); - return f ? janet_makefile(f, flags) : janet_wrap_nil(); + return f ? janet_makefile(f, flags) + : (flags & JANET_FILE_NONIL) ? (janet_panicf("failed to open file %s: %s", fname, strerror(errno)), janet_wrap_nil()) + : janet_wrap_nil(); } /* Read up to n bytes into buffer. */ @@ -720,7 +728,8 @@ static const JanetReg io_cfuns[] = { "\tw - allow writing to the file\n" "\ta - append to the file\n" "\tb - open the file in binary mode (rather than text mode)\n" - "\t+ - append to the file instead of overwriting it") + "\t+ - append to the file instead of overwriting it\n" + "\tn - error if the file cannot be opened instead of returning nil") }, { "file/close", cfun_io_fclose, diff --git a/src/include/janet.h b/src/include/janet.h index e9f3e5a6..2f40d144 100644 --- a/src/include/janet.h +++ b/src/include/janet.h @@ -1540,6 +1540,7 @@ extern JANET_API const JanetAbstractType janet_file_type; #define JANET_FILE_BINARY 64 #define JANET_FILE_SERIALIZABLE 128 #define JANET_FILE_PIPED 256 +#define JANET_FILE_NONIL 512 JANET_API Janet janet_makefile(FILE *f, int32_t flags); JANET_API FILE *janet_getfile(const Janet *argv, int32_t n, int32_t *flags); diff --git a/test/suite0010.janet b/test/suite0010.janet index 1205d192..62ef3bab 100644 --- a/test/suite0010.janet +++ b/test/suite0010.janet @@ -57,4 +57,8 @@ (assert (= nil (curenv 1000000)) "curenv 3") (assert (= root-env (curenv 1)) "curenv 4") +# Import macro test +(assert-no-error "import macro 1" (macex '(import a :as b :fresh maybe))) +(assert (deep= ~(,import* "a" :as "b" :fresh maybe) (macex '(import a :as b :fresh maybe))) "import macro 2") + (end-suite)