diff --git a/runtime/flan_dyn.c b/runtime/flan_dyn.c index cacfa7d9..1044f30e 100644 --- a/runtime/flan_dyn.c +++ b/runtime/flan_dyn.c @@ -994,6 +994,9 @@ static void say_render(sayer *s, flan_dyn v, int depth) { if (d != d) snprintf(buf, sizeof buf, "nan"); else snprintf(buf, sizeof buf, "%g", d); say_puts(s, buf); + /* A trap's sentence says 2.0 for a float of 2, so it cannot be read as + the int 2; inf and an exponent already say float. */ + if (strspn(buf, "-0123456789") == strlen(buf)) say_puts(s, ".0"); return; } case FLAN_DYN_TAG_TEXT: { @@ -4536,6 +4539,23 @@ static void into_put(into_site *s, const uint8_t *d, flan_dyn x, uint8_t *p) { int64_t lo, hi; if (int_range(*d, &lo, &hi)) { int64_t n; + /* A char goes in as its code point where it fits, as it does into a + typed parameter ([flan_dyn_need_int]): into a byte only when ASCII, + since a byte past ASCII is not that char in UTF-8. */ + if (flan_dyn_tag(x) == FLAN_DYN_TAG_CHAR) { + char cs[16]; + n = (int64_t)dyn_payload(x); + if (n <= ((*d == 'b' || *d == 'B') ? 127 : hi)) goto store; + char_spell((uint32_t)n, cs); + desc_spell(d, ty, sizeof ty); + if (*d == 'b' || *d == 'B') + into_trap(s, "DynRange", "%s is the char %s, which is more than one " + "byte in UTF-8, so it is not %s %s. Take its code point as " + "an i32", into_who(s), cs, an(ty), ty); + into_trap(s, "DynRange", "%s is the char %s, code point %lld, and %s %s " + "holds %lld to %lld", into_who(s), cs, (long long)n, an(ty), + ty, (long long)lo, (long long)hi); + } if (flan_dyn_tag(x) != FLAN_DYN_TAG_INT) { into_wanted(why, sizeof why, d); into_wrong(s, x, why); @@ -4550,6 +4570,7 @@ static void into_put(into_site *s, const uint8_t *d, flan_dyn x, uint8_t *p) { into_who(s), (long long)n, an(ty), ty, (long long)lo, (long long)hi); } + store: switch (*d) { case 'b': case 'B': { uint8_t b = (uint8_t)n; memcpy(p, &b, 1); return; } case 'h': case 'H': { uint16_t h = (uint16_t)n; memcpy(p, &h, 2); return; } diff --git a/test/programs/dyn-int-widths.flan b/test/programs/dyn-int-widths.flan index 7faf69da..63857a26 100644 --- a/test/programs/dyn-int-widths.flan +++ b/test/programs/dyn-int-widths.flan @@ -31,6 +31,8 @@ (println (i8 (d \a)) (u8 (d \a)) (i16 (d \a)) (u16 (d \a)) (i32 (d \a)) (u32 (d \a)) (i64 (d \a)) (u64 (d \a))) (println (u32 (d -1)) (u32 (the i64 -1)) (u8 (d 256)) (u8 (the i64 256))) + ;; into a typed array and a struct, chars by the same rule + (println (sum (d [\a \b])) (pair-sum (d {:a \a :b \日}))) (when (> (length args) 1) (let [w (at args 1)] (cond @@ -44,5 +46,21 @@ (= w "u64-neg") (println (to-u64 (d -1))) (= w "u8-char") (println (to-u8 (d \é))) (= w "u16-char") (println (to-u16 (d \😀))) + (= w "float") (println (to-i64 (d 2.0))) + (= w "elem-char") (println (bytes-sum (d [\a \é]))) + (= w "field-char") (println (pair-sum (d {:a \é :b 1}))) :else (println (to-i64 (d "x"))))))) 0) + +(defn sum [xs [const i32]] i64 + (let [t (the i64 0)] + (dotimes [i (length xs)] (set t (+ t (i64 (at xs i))))) + t)) + +(defn bytes-sum [xs [const u8]] i64 + (let [t (the i64 0)] + (dotimes [i (length xs)] (set t (+ t (i64 (at xs i))))) + t)) + +(defstruct Pair [a u8 b i32]) +(defn pair-sum [p Pair] i64 (+ (i64 (.a p)) (i64 (.b p)))) diff --git a/test/test_acceptance.ml b/test/test_acceptance.ml index 0dfb48b0..11b717c8 100644 --- a/test/test_acceptance.ml +++ b/test/test_acceptance.ml @@ -5456,7 +5456,7 @@ level "1" -2147483648 2147483647 128512\n0 4294967295 128512\n\ -9223372036854775807 9223372036854775807 128512\n\ 0 9223372036854775807 128512\n97 97 97 97 97 97 97 97\n\ - 4294967295 4294967295 0 0\n" + 4294967295 4294967295 0 0\n195 26182\n" in outputs "dyn: every integer width" "programs/dyn-int-widths.flan" widths_out; outputs ~opt:"-O0" "dyn: every integer width, -O0" @@ -5477,24 +5477,30 @@ level "1" wanted: %S (exit 134)\n" arg (if x86 then ", --x86" else "") text code want end) - [ ("u8-256", "37:42: dyn: a u8 is wanted here, and the int 256 is \ + [ ("u8-256", "39:42: dyn: a u8 is wanted here, and the int 256 is \ outside a u8's range"); - ("u8-neg", "38:42: dyn: a u8 is wanted here, and the int -1 is \ + ("u8-neg", "40:42: dyn: a u8 is wanted here, and the int -1 is \ outside a u8's range"); - ("i8-128", "39:42: dyn: an i8 is wanted here, and the int 128 is \ + ("i8-128", "41:42: dyn: an i8 is wanted here, and the int 128 is \ outside an i8's range"); - ("i16-big", "40:44: dyn: an i16 is wanted here, and the int 32768"); - ("u16-big", "41:44: dyn: a u16 is wanted here, and the int 65536"); - ("i32-big", "42:44: dyn: an i32 is wanted here, and the int \ + ("i16-big", "42:44: dyn: an i16 is wanted here, and the int 32768"); + ("u16-big", "43:44: dyn: a u16 is wanted here, and the int 65536"); + ("i32-big", "44:44: dyn: an i32 is wanted here, and the int \ 2147483648"); - ("u32-neg", "43:44: dyn: a u32 is wanted here, and the int -1 is \ + ("u32-neg", "45:44: dyn: a u32 is wanted here, and the int -1 is \ outside a u32's range"); - ("u64-neg", "44:44: dyn: a u64 is wanted here, and the int -1"); - ("u8-char", "45:43: dyn: a u8 is wanted here, and the char \\é is \ + ("u64-neg", "46:44: dyn: a u64 is wanted here, and the int -1"); + ("u8-char", "47:43: dyn: a u8 is wanted here, and the char \\é is \ more than one byte in UTF-8"); - ("u16-char", "46:45: dyn: a u16 is wanted here, and the char \ + ("u16-char", "48:45: dyn: a u16 is wanted here, and the char \ \\😀, code point 128512, is outside a u16's range"); - ("x", "47:34: dyn: an i64 is wanted here, and this is a text, \ + ("float", "49:42: dyn: an i64 is wanted here, and this is a \ + float, 2.0."); + ("elem-char", "50:49: dyn into [const u8]: element 1 is the \ + char \\é, which is more than one byte in UTF-8"); + ("field-char", "51:49: dyn into Pair: field :a is the char \\é, \ + which is more than one byte in UTF-8"); + ("x", "52:34: dyn: an i64 is wanted here, and this is a text, \ \"x\". An i64 takes an int or a char's code point") ]) [ false; true ]; (* Print, then read: each char dyn-char-spell.flan prints — every ASCII