1
0
mirror of https://github.com/janet-lang/janet synced 2024-06-18 11:19:56 +00:00

Address #1121 - disallow extra splices.

This turns splices that are ignored into compiler errors. Other
alternatives here should also be considered, for example making this
a compiler warning rather than an error. For example, the latest
spork as of a3ee63c137ee3234987dbbca71b566994ff8ae8c has an error of this
kind, but the resulting program does work correctly.

Also disallow splice propagation - code of the
form (+ 1 (do ;[2 3 4]) 5).
This commit is contained in:
Calvin Rose 2023-05-06 12:08:07 -05:00
parent 4cc4a9d38b
commit 7d57f87007
6 changed files with 33 additions and 1 deletions

View File

@ -2,6 +2,7 @@
All notable changes to this project will be documented in this file.
## Unreleased - ???
- Disallow using `(splice x)` in contexts where it doesn't make sense rather than silently coercing to `x`.
- Change the names of `:user8` and `:user9` sigals to `:interrupt` and `:await`
- Change the names of `:user8` and `:user9` fiber statuses to `:interrupted` and `:suspended`.
- Add `ev/all-tasks` to see all currently suspended fibers.

View File

@ -422,6 +422,7 @@ JanetSlot *janetc_toslots(JanetCompiler *c, const Janet *vals, int32_t len) {
int32_t i;
JanetSlot *ret = NULL;
JanetFopts subopts = janetc_fopts_default(c);
subopts.flags |= JANET_FOPTS_ACCEPT_SPLICE;
for (i = 0; i < len; i++) {
janet_v_push(ret, janetc_value(subopts, vals[i]));
}
@ -432,6 +433,7 @@ JanetSlot *janetc_toslots(JanetCompiler *c, const Janet *vals, int32_t len) {
JanetSlot *janetc_toslotskv(JanetCompiler *c, Janet ds) {
JanetSlot *ret = NULL;
JanetFopts subopts = janetc_fopts_default(c);
subopts.flags |= JANET_FOPTS_ACCEPT_SPLICE;
const JanetKV *kvs = NULL;
int32_t cap = 0, len = 0;
janet_dictionary_view(ds, &kvs, &len, &cap);

View File

@ -187,6 +187,7 @@ struct JanetCompiler {
#define JANET_FOPTS_TAIL 0x10000
#define JANET_FOPTS_HINT 0x20000
#define JANET_FOPTS_DROP 0x40000
#define JANET_FOPTS_ACCEPT_SPLICE 0x80000
/* Options for compiling a single form */
struct JanetFopts {

View File

@ -39,6 +39,10 @@ static JanetSlot janetc_quote(JanetFopts opts, int32_t argn, const Janet *argv)
static JanetSlot janetc_splice(JanetFopts opts, int32_t argn, const Janet *argv) {
JanetSlot ret;
if (!(opts.flags & JANET_FOPTS_ACCEPT_SPLICE)) {
janetc_cerror(opts.compiler, "splice can only be used in function parameters and data constructors, it has no effect here");
return janetc_cslot(janet_wrap_nil());
}
if (argn != 1) {
janetc_cerror(opts.compiler, "expected 1 argument to splice");
return janetc_cslot(janet_wrap_nil());
@ -75,7 +79,9 @@ static JanetSlot quasiquote(JanetFopts opts, Janet x, int depth, int level) {
const uint8_t *head = janet_unwrap_symbol(tup[0]);
if (!janet_cstrcmp(head, "unquote")) {
if (level == 0) {
return janetc_value(janetc_fopts_default(opts.compiler), tup[1]);
JanetFopts subopts = janetc_fopts_default(opts.compiler);
subopts.flags |= JANET_FOPTS_ACCEPT_SPLICE;
return janetc_value(subopts, tup[1]);
} else {
level--;
}
@ -488,6 +494,7 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
/* Get options */
condopts = janetc_fopts_default(c);
bodyopts = opts;
bodyopts.flags &= ~JANET_FOPTS_ACCEPT_SPLICE;
/* Set target for compilation */
target = (drop || tail)
@ -564,6 +571,7 @@ static JanetSlot janetc_do(JanetFopts opts, int32_t argn, const Janet *argv) {
subopts.flags = JANET_FOPTS_DROP;
} else {
subopts = opts;
subopts.flags &= ~JANET_FOPTS_ACCEPT_SPLICE;
}
ret = janetc_value(subopts, argv[i]);
if (i != argn - 1) {
@ -587,6 +595,7 @@ static JanetSlot janetc_upscope(JanetFopts opts, int32_t argn, const Janet *argv
subopts.flags = JANET_FOPTS_DROP;
} else {
subopts = opts;
subopts.flags &= ~JANET_FOPTS_ACCEPT_SPLICE;
}
ret = janetc_value(subopts, argv[i]);
if (i != argn - 1) {

View File

@ -24,6 +24,11 @@
(def errsym (keyword (gensym)))
~(assert (= ,errsym (try (do ,;forms) ([_] ,errsym))) ,msg))
(defn check-compile-error
[form]
(def result (compile form))
(assert (table? result) (string/format "expected compilation error for %j, but compiled without error" form)))
(defmacro assert-no-error
[msg & forms]
(def errsym (keyword (gensym)))

View File

@ -103,4 +103,18 @@
# Quasiquote bracketed tuples
(assert (= (tuple/type ~[1 2 3]) (tuple/type '[1 2 3])) "quasiquote bracket tuples")
# No useless splices
(check-compile-error '((splice [1 2 3]) 0))
(check-compile-error '(if ;[1 2] 5))
(check-compile-error '(while ;[1 2 3] (print :hi)))
(check-compile-error '(def x ;[1 2 3]))
(check-compile-error '(fn [x] ;[x 1 2 3]))
# No splice propagation
(check-compile-error '(+ 1 (do ;[2 3 4]) 5))
(check-compile-error '(+ 1 (upscope ;[2 3 4]) 5))
# compiler inlines when condition is constant, ensure that optimization doesn't break
(check-compile-error '(+ 1 (if true ;[3 4])))
(check-compile-error '(+ 1 (if false nil ;[3 4])))
(end-suite)