aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/module.c15
-rw-r--r--core/module.h6
-rw-r--r--core/test-module.c14
3 files changed, 27 insertions, 8 deletions
diff --git a/core/module.c b/core/module.c
index ca5b0e2..3657843 100644
--- a/core/module.c
+++ b/core/module.c
@@ -453,10 +453,10 @@ PURE_COLD static bool names_arg(const PureModule *m, unsigned kind, uint32_t arg
case A_POSITION: case A_JOINED: return arg <= 1;
case A_HELD: return (arg & ~(uint32_t)PURE_HELD_APPEND) < PURE_MODULE_HELD;
case A_FUNCTION: return arg < m->functions;
- case A_FORMAT: { /* a type; a width, zeros, a form fitting it and digits for FIXED alone */
+ case A_FORMAT: { /* a type; a width, zeros, a form fitting it and digits for FIXED and DECIMAL alone */
uint32_t type = arg & 3, form = arg >> PURE_FORMAT_FORM & 7, digits = arg >> PURE_FORMAT_DIGITS & 31;
return type <= 2 && !(arg & 0xFC) && !(arg >> 25) && form <= PURE_FORMAT_FIXED && (type != 1 || !form) &&
- (form != PURE_FORMAT_FIXED || type == 0) && (form == PURE_FORMAT_FIXED || !digits);
+ (form != PURE_FORMAT_FIXED || type == 0) && (form == PURE_FORMAT_FIXED || form == PURE_FORMAT_DECIMAL || !digits);
}
case A_RELATION: return arg <= PURE_NOT_EQUAL;
case A_KEYED: return state_of(m, arg, PURE_STATE_LIST) && m->state_key[arg];
@@ -2942,7 +2942,8 @@ static __attribute__((cold, noinline)) int kept_step(PureApp *app, PureArena *ar
}
/* NUM_TEXT's text of v in a format (the argument past its type, PureFormat): false where an integer's form meets a
- * number that is not a whole one within 2^53. */
+ * number that is not a whole one within 2^53. DECIMAL with digits writes the integer in minor units: its last
+ * digits after a point (money's cents: 1234 at two is 12.34, -5 is -0.05). */
static bool formatted(Slot v, uint32_t arg, char *out, size_t *length) {
unsigned type = arg & 3, width = arg >> PURE_FORMAT_WIDTH & 0xFF, form = arg >> PURE_FORMAT_FORM & 7,
digits = arg >> PURE_FORMAT_DIGITS & 31;
@@ -2960,10 +2961,14 @@ static bool formatted(Slot v, uint32_t arg, char *out, size_t *length) {
unsigned base = form == PURE_FORMAT_DECIMAL ? 10 : form <= PURE_FORMAT_HEX_UPPER ? 16 : form == PURE_FORMAT_BINARY ? 2 : 8;
const char *set = form == PURE_FORMAT_HEX_UPPER ? "0123456789ABCDEF" : "0123456789abcdef";
char reversed[64];
- unsigned count = 0;
+ unsigned count = 0, places = form == PURE_FORMAT_DECIMAL && digits ? digits - 1 : 0;
do reversed[count++] = set[magnitude % base], magnitude /= base; while (magnitude);
+ while (count <= places) reversed[count++] = '0'; /* a digit before the point */
if (i < 0) body[n++] = '-';
- while (count) body[n++] = reversed[--count];
+ for (; count; --count) {
+ if (count == places) body[n++] = '.';
+ body[n++] = reversed[count - 1];
+ }
} else
n = type == 2 ? (size_t)snprintf(body, sizeof(body), "%" PRId64, v.i64)
: type ? (size_t)snprintf(body, sizeof(body), "%s", v.num ? "true" : "false") : pure_format_number(v.num, body);
diff --git a/core/module.h b/core/module.h
index ce8cebf..75e27ba 100644
--- a/core/module.h
+++ b/core/module.h
@@ -101,8 +101,10 @@ typedef enum { PURE_BITS_AND, PURE_BITS_OR, PURE_BITS_XOR, PURE_BITS_LEFT, PURE_
* NUM_TEXT's argument: bits 0-1 the value's type (as CONST's), 8-15 a width
* the text is padded to on the left, bit 16 padding with zeros after a sign
* (else spaces), 17-19 the form (PureFormat), 20-24 one more than the digits
- * after the point of FIXED. A form of an integer takes an i64 or a whole
- * number (else LIMIT), in its base with a sign; FIXED takes a number. */
+ * after the point of FIXED or of DECIMAL (there the integer in minor units:
+ * 1234 at two digits is 12.34, as money's cents). A form of an integer takes
+ * an i64 or a whole number (else LIMIT), in its base with a sign; FIXED
+ * takes a number. */
enum { PURE_MODULE_HELD = 32, PURE_HELD_TEXT = 16, PURE_HELD_APPEND = 1 << 8 };
/* 027's stage 2b: lists in records. A record field of type LIST holds a list
* of the record its default names. In an event's list (and the lists in its
diff --git a/core/test-module.c b/core/test-module.c
index 36722d2..f89e198 100644
--- a/core/test-module.c
+++ b/core/test-module.c
@@ -6166,7 +6166,8 @@ static void bits_and_bytes(void) {
/* ---- Formats, slices and values held by name (docs/design/027, stage 2a) --
* NUM_TEXT writes a number, a bool or an i64 in a width, with zeros or
- * spaces, in a base or with fixed digits; an integer's form fails as limit
+ * spaces, in a base or with fixed digits, or an integer in minor units
+ * (money's: 1234 at two digits is 12.34); an integer's form fails as limit
* on a number that is not whole. BYTES_SLICE takes whole positions inside
* the value; BYTE makes one byte. BYTES_LOAD and BYTES_STORE keep bytes
* and texts by name for the event (a text's slots hold text alone): set,
@@ -6194,6 +6195,17 @@ static void formats_and_held(void) {
{0, 42, FMT(0, 0, 0, PURE_FORMAT_HEX, 0), PURE_FAULT_NONE, "2a"},
{0, 2.5, FMT(0, 0, 0, PURE_FORMAT_HEX, 0), PURE_FAULT_LIMIT, ""},
{0, 1, FMT(1, 6, 0, PURE_FORMAT_PLAIN, 0), PURE_FAULT_NONE, " true"},
+ /* Money's form (027's stage 5): an integer in minor units, its last digits after a point. */
+ {1, 1234, FMT(2, 0, 0, PURE_FORMAT_DECIMAL, 3), PURE_FAULT_NONE, "12.34"},
+ {1, -5, FMT(2, 0, 0, PURE_FORMAT_DECIMAL, 3), PURE_FAULT_NONE, "-0.05"},
+ {1, 0, FMT(2, 0, 0, PURE_FORMAT_DECIMAL, 3), PURE_FAULT_NONE, "0.00"},
+ {1, -5, FMT(2, 7, 1, PURE_FORMAT_DECIMAL, 3), PURE_FAULT_NONE, "-000.05"},
+ {1, 100, FMT(2, 6, 0, PURE_FORMAT_DECIMAL, 2), PURE_FAULT_NONE, " 10.0"},
+ {1, 7, FMT(2, 0, 0, PURE_FORMAT_DECIMAL, 1), PURE_FAULT_NONE, "7"},
+ {1, 5, FMT(2, 0, 0, PURE_FORMAT_DECIMAL, 26), PURE_FAULT_NONE, "0.0000000000000000000000005"},
+ {1, -0x1p63, FMT(2, 0, 0, PURE_FORMAT_DECIMAL, 3), PURE_FAULT_NONE, "-92233720368547758.08"},
+ {0, 1234, FMT(0, 0, 0, PURE_FORMAT_DECIMAL, 3), PURE_FAULT_NONE, "12.34"},
+ {0, 12.5, FMT(0, 0, 0, PURE_FORMAT_DECIMAL, 3), PURE_FAULT_LIMIT, ""},
};
for (size_t k = 0; k < LEN(shown); ++k) {
O value = shown[k].i64 ? IC((int64_t)shown[k].value) : (O){C, shown[k].format & 3, shown[k].value};