diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1c74e4c7..e832e7fc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -119,7 +119,7 @@ jobs: sudo apt-get update sudo apt-get install gcc-arm-linux-gnueabi qemu-user - name: Compile the project - run: make RUN="qemu-arm -L /usr/arm-linux-gnueabi/" CC=arm-linux-gnueabi-gcc LD=arm-linux-gnueabi-gcc + run: make RUN="qemu-arm -L /usr/arm-linux-gnueabi/" CC=arm-linux-gnueabi-gcc LD=arm-linux-gnueabi-gcc - name: Test the project run: make RUN="qemu-arm -L /usr/arm-linux-gnueabi/" SUBRUN="qemu-arm -L /usr/arm-linux-gnueabi/" test VERBOSE=1 @@ -132,4 +132,4 @@ jobs: - name: Do Qemu build and test run: | docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - docker run --rm -v .:/janet s390x/ubuntu bash -c "apt-get -y update && apt-get -y install git build-essential && cd /janet && make -j3 && make test" + docker run --rm -v .:/janet --platform linux/s390x ubuntu bash -c "apt-get -y update && apt-get -y install git build-essential && cd /janet && make -j3 && make test" diff --git a/CHANGELOG.md b/CHANGELOG.md index c9fdb6ae..308f32f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,15 @@ All notable changes to this project will be documented in this file. ## ??? - Unreleased +- Change string hashing. +- Fix string equality bug. +- Add `assertf` - Change how JANET_PROFILE is loaded to allow more easily customizing the environment. - Add `*repl-prompt*` dynamic binding to allow customizing the built in repl. - Add multiple path support in the `JANET_PATH` environment variables. This lets user more easily import modules from many directories. +- Add `nth` and `only-tags` PEG specials to select from sub-captures while + dropping the rest. ## 1.36.0 - 2024-09-07 - Improve error messages in `bundle/add*` functions. diff --git a/README.md b/README.md index 274ed4ce..7376b433 100644 --- a/README.md +++ b/README.md @@ -250,8 +250,10 @@ Emacs, and Atom each have syntax packages for the Janet language, though. ## Installation -See the [Introduction](https://janet-lang.org/docs/index.html) for more details. If you just want -to try out the language, you don't need to install anything. You can also move the `janet` executable wherever you want on your system and run it. +If you just want to try out the language, you don't need to install anything. +In this case you can also move the `janet` executable wherever you want on +your system and run it. However, for a fuller setup, please see the +[Introduction](https://janet-lang.org/docs/index.html) for more details. ## Usage diff --git a/src/boot/boot.janet b/src/boot/boot.janet index d00e46c2..461e8928 100644 --- a/src/boot/boot.janet +++ b/src/boot/boot.janet @@ -154,6 +154,11 @@ ,v (,error ,(if err err (string/format "assert failure in %j" x)))))) +(defmacro assertf + "Convenience macro that combines `assert` and `string/format`." + [x & args] + ~(as-macro ,assert ,x (,string/format ,;args))) + (defmacro defdyn ``Define an alias for a keyword that is used as a dynamic binding. The alias is a normal, lexically scoped binding that can be used instead of @@ -3944,7 +3949,7 @@ (defn make-sig [] (ffi/signature :default real-ret-type ;computed-type-args)) (defn make-ptr [] - (assert (ffi/lookup (if lazy (llib) lib) raw-symbol) (string "failed to find ffi symbol " raw-symbol))) + (assertf (ffi/lookup (if lazy (llib) lib) raw-symbol) "failed to find ffi symbol %v" raw-symbol)) (if lazy ~(defn ,alias ,;meta [,;formal-args] (,ffi/call (,(delay (make-ptr))) (,(delay (make-sig))) ,;formal-args)) @@ -4121,7 +4126,7 @@ "Get the manifest for a give installed bundle" [bundle-name] (def name (get-manifest-filename bundle-name)) - (assert (fexists name) (string "no bundle " bundle-name " found")) + (assertf (fexists name) "no bundle %v found" bundle-name) (parse (slurp name))) (defn- get-bundle-module @@ -4264,11 +4269,9 @@ (def missing (seq [d :in deps :when (not (bundle/installed? d))] (string d))) (when (next missing) (errorf "missing dependencies %s" (string/join missing ", ")))) (def bundle-name (get config :name default-bundle-name)) - (assert bundle-name (errorf "unable to infer bundle name for %v, use :name argument" path)) - (assert (not (string/check-set "\\/" bundle-name)) - (string "bundle name " - bundle-name - " cannot contain path separators")) + (assertf bundle-name "unable to infer bundle name for %v, use :name argument" path) + (assertf (not (string/check-set "\\/" bundle-name)) + "bundle name %v cannot contain path separators" bundle-name) (assert (next bundle-name) "cannot use empty bundle-name") (assert (not (fexists (get-manifest-filename bundle-name))) "bundle is already installed") @@ -4320,7 +4323,7 @@ (var i 0) (def man (bundle/manifest bundle-name)) (def files (get man :files @[])) - (assert (os/mkdir dest-dir) (string "could not create directory " dest-dir " (or it already exists)")) + (assertf (os/mkdir dest-dir) "could not create directory %v (or it already exists)" dest-dir) (def s (sep)) (os/mkdir (string dest-dir s "bundle")) (def install-hook (string dest-dir s "bundle" s "init.janet")) diff --git a/src/core/ffi.c b/src/core/ffi.c index 9b149542..c95642ad 100644 --- a/src/core/ffi.c +++ b/src/core/ffi.c @@ -400,7 +400,7 @@ static JanetFFIStruct *build_struct_type(int32_t argc, const Janet *argv) { JanetFFIStruct *st = janet_abstract(&janet_struct_type, sizeof(JanetFFIStruct) + argc * sizeof(JanetFFIStructMember)); - st->field_count = member_count; + st->field_count = 0; st->size = 0; st->align = 1; if (argc == 0) { @@ -418,6 +418,7 @@ static JanetFFIStruct *build_struct_type(int32_t argc, const Janet *argv) { st->fields[i].type = decode_ffi_type(argv[j]); size_t el_size = type_size(st->fields[i].type); size_t el_align = type_align(st->fields[i].type); + if (el_align <= 0) janet_panicf("bad field type %V", argv[j]); if (all_packed || pack_one) { if (st->size % el_align != 0) is_aligned = 0; st->fields[i].offset = st->size; @@ -433,6 +434,7 @@ static JanetFFIStruct *build_struct_type(int32_t argc, const Janet *argv) { st->size += (st->align - 1); st->size /= st->align; st->size *= st->align; + st->field_count = member_count; return st; } diff --git a/src/core/parse.c b/src/core/parse.c index cfb566b2..6faa7948 100644 --- a/src/core/parse.c +++ b/src/core/parse.c @@ -231,7 +231,7 @@ static void delim_error(JanetParser *parser, size_t stack_index, char c, const c janet_buffer_push_u8(buffer, '`'); } } - janet_formatb(buffer, " opened at line %d, column %d", s->line, s->column); + janet_formatb(buffer, " opened at line %d, column %d", (int32_t) s->line, (int32_t) s->column); } parser->error = (const char *) janet_string(buffer->data, buffer->count); parser->flag |= JANET_PARSER_GENERATED_ERROR; diff --git a/src/core/string.c b/src/core/string.c index 277b1a25..6a67482c 100644 --- a/src/core/string.c +++ b/src/core/string.c @@ -71,10 +71,10 @@ int janet_string_compare(const uint8_t *lhs, const uint8_t *rhs) { int janet_string_equalconst(const uint8_t *lhs, const uint8_t *rhs, int32_t rlen, int32_t rhash) { int32_t lhash = janet_string_hash(lhs); int32_t llen = janet_string_length(lhs); - if (lhs == rhs) - return 1; if (lhash != rhash || llen != rlen) return 0; + if (lhs == rhs) + return 1; return !memcmp(lhs, rhs, rlen); } diff --git a/src/core/util.c b/src/core/util.c index d4c5aef3..9ad64c56 100644 --- a/src/core/util.c +++ b/src/core/util.c @@ -117,14 +117,20 @@ const char *const janet_status_names[16] = { "alive" }; +uint32_t janet_hash_mix(uint32_t input, uint32_t more) { + uint32_t mix1 = (more + 0x9e3779b9 + (input << 6) + (input >> 2)); + return input ^ (0x9e3779b9 + (mix1 << 6) + (mix1 >> 2)); +} + #ifndef JANET_PRF int32_t janet_string_calchash(const uint8_t *str, int32_t len) { - if (NULL == str) return 5381; + if (NULL == str || len == 0) return 5381; const uint8_t *end = str + len; uint32_t hash = 5381; while (str < end) hash = (hash << 5) + hash + *str++; + hash = janet_hash_mix(hash, (uint32_t) len); return (int32_t) hash; } @@ -240,11 +246,6 @@ int32_t janet_string_calchash(const uint8_t *str, int32_t len) { #endif -uint32_t janet_hash_mix(uint32_t input, uint32_t more) { - uint32_t mix1 = (more + 0x9e3779b9 + (input << 6) + (input >> 2)); - return input ^ (0x9e3779b9 + (mix1 << 6) + (mix1 >> 2)); -} - /* Computes hash of an array of values */ int32_t janet_array_calchash(const Janet *array, int32_t len) { const Janet *end = array + len; diff --git a/test/suite-boot.janet b/test/suite-boot.janet index c3c8b743..2168c410 100644 --- a/test/suite-boot.janet +++ b/test/suite-boot.janet @@ -997,4 +997,14 @@ (assert (deep= (get (dyn 'a) :source-form) source)) (setdyn *debug* nil) +# issue #1516 +(assert (assertf true) "assertf 1 argument") +(assert (assertf true "fun message") "assertf 2 arguments") +(assert (assertf true "%s message" "mystery") "assertf 3 arguments") +(assert (assertf (not nil) "%s message" "ordinary") "assertf not nil") +(assert-error "assertf error 1" (assertf false)) +(assert-error "assertf error 2" (assertf false "fun message")) +(assert-error "assertf error 3" (assertf false "%s message" "mystery")) +(assert-error "assertf error 4" (assertf nil "%s %s" "alice" "bob")) + (end-suite) diff --git a/test/suite-ffi.janet b/test/suite-ffi.janet index 0a810198..6305651e 100644 --- a/test/suite-ffi.janet +++ b/test/suite-ffi.janet @@ -52,5 +52,7 @@ (assert (= 26 (ffi/size [:char :pack :int @[:char 21]])) "array struct size")) -(end-suite) +(compwhen has-ffi + (assert-error "bad struct issue #1512" (ffi/struct :void))) +(end-suite)