aboutsummaryrefslogtreecommitdiffstats
path: root/compiler/compile.c
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-10-19 03:56:43 +0100
committereunhhu <[email protected]>2026-10-19 03:56:43 +0100
commit4aefbab3cdbcb5a7c4b7598795baa276f82fd842 (patch)
treef95850f5b392f6a24491004216564b796f0415ef /compiler/compile.c
parent0d66663351c411693c71788804717ad2694c81cd (diff)
downloadaup-4aefbab3cdbcb5a7c4b7598795baa276f82fd842.tar.gz
aup-4aefbab3cdbcb5a7c4b7598795baa276f82fd842.zip
Bytes compared (Pure's TEXT_COMPARE with PURE_COMPARE_BYTES): ==, !=, <, <=, >, >= between bytes by their bytes; a string (a literal, or one with formats) where bytes are what it meets, compared or joined, is its UTF-8 bytes, as 1 is an i64 where i64s go, values of text and bytes mixing in neither (bytes(t) or text(b)); test bytes_compared (400 random pairs with 0x00 and 0xff in the six relations, literals on either side, a formatted string, joins with literals, against Python), two diagnostics; the 60 sources compiled before the same modules; 002
Diffstat (limited to 'compiler/compile.c')
-rw-r--r--compiler/compile.c38
1 files changed, 31 insertions, 7 deletions
diff --git a/compiler/compile.c b/compiler/compile.c
index ec99e50..1fdd43a 100644
--- a/compiler/compile.c
+++ b/compiler/compile.c
@@ -2452,6 +2452,15 @@ static bool literal_only(const Expr *e) {
}
/* The type e has, compiled and taken back: what literals beside it take. */
+static Kind meeting(Compiler *c, const Expr *x, bool handler, int height, Type other) {
+ Kind kind = value(c, x, handler, height);
+ if (x->kind == E_STRING && kind.type == TEXT && other == BYTES) {
+ emit(c, x->line, x->column, BYTES_FROM, 0, 0);
+ return (Kind){BYTES, -1};
+ }
+ return kind;
+}
+
static Type probe(Compiler *c, const Expr *e, bool handler, int height) {
unsigned code = c->code_count, constants = c->constants, joins = c->joins, instances = c->instance_count;
size_t used = c->constant_used;
@@ -2724,6 +2733,13 @@ static uint32_t local_arg(const Compiler *c, int local) {
* where it cannot fail they compute it anyway (one AND or OR). */
static Type probe(Compiler *c, const Expr *e, bool handler, int height);
+/* A side of a comparison or a join: a string (a literal, or one with formats) where bytes are what it meets is its
+ * UTF-8 bytes, as 1 is an i64 where i64s go; other values do not mix (bytes(t) and text(b) convert them). */
+static Kind meeting(Compiler *c, const Expr *x, bool handler, int height, Type other);
+static bool meets_bytes(Compiler *c, const Expr *string, const Expr *other, bool handler, int height) {
+ return string->kind == E_STRING && probe(c, other, handler, height) == BYTES;
+}
+
/* A list the code makes (027's 2b), an event's: a register a list in a record is bound to, to be read (bound; a new one
* each time: each place reads its own), or the one empty list of a record (a LIST field's default). */
static int hidden_list(Compiler *c, int record, bool bound, int line, int column) {
@@ -3831,10 +3847,12 @@ static Kind value(Compiler *c, const Expr *e, bool handler, int height) {
if (e->op == ADD || e->op == SUB) {
/* at + 1 char moves a cursor, at + 1 an index; both stop at the ends. */
bool distance = e->args[1]->kind == E_UNIT;
- Kind left = wanted(c, e->args[0], handler, height, distance ? 0 : left_hint(c, e, handler, height, want));
+ Kind left = !distance && meets_bytes(c, e->args[0], e->args[1], handler, height + 1)
+ ? meeting(c, e->args[0], handler, height, BYTES)
+ : wanted(c, e->args[0], handler, height, distance ? 0 : left_hint(c, e, handler, height, want));
if (!distance && (left.type == BYTES || left.type == TEXT)) { /* joined */
if (e->op == SUB) fail_at(c, e->line, e->column, "texts and bytes are joined with +; - takes nothing apart");
- Kind right = value(c, e->args[1], handler, height + 1);
+ Kind right = meeting(c, e->args[1], handler, height + 1, left.type);
if (right.type != left.type)
fail_at(c, e->args[1]->line, e->args[1]->column, "%s joins %s, not %s", type_name(left.type), type_name(left.type),
type_name(right.type));
@@ -3855,11 +3873,17 @@ static Kind value(Compiler *c, const Expr *e, bool handler, int height) {
return (Kind){type, -1};
}
if (e->op >= LT && e->op <= NE) {
- /* Texts compare by their bytes, numbers and i64s as numbers; bools are equal or not. */
- Kind left = wanted(c, e->args[0], handler, height, left_hint(c, e, handler, height, 0));
- if (left.type == TEXT) {
- expect_kind(c, e->args[1], value(c, e->args[1], handler, height + 1), TEXT);
- emit(c, e->line, e->column, TEXT_COMPARE, (uint32_t)(e->op - LT), 0);
+ /* Texts and bytes compare by their bytes, numbers and i64s as numbers; bools are equal or not. */
+ Kind left = meets_bytes(c, e->args[0], e->args[1], handler, height + 1) ? meeting(c, e->args[0], handler, height, BYTES)
+ : wanted(c, e->args[0], handler, height, left_hint(c, e, handler, height, 0));
+ if (left.type == TEXT || left.type == BYTES) {
+ Kind right = meeting(c, e->args[1], handler, height + 1, left.type);
+ if (right.type == TEXT || right.type == BYTES) {
+ if (right.type != left.type)
+ fail_at(c, e->args[1]->line, e->args[1]->column, "%s compares with %s, not %s: convert one, as in bytes(t) or "
+ "text(b)", type_name(left.type), type_name(left.type), type_name(right.type));
+ } else expect_kind(c, e->args[1], right, left.type);
+ emit(c, e->line, e->column, TEXT_COMPARE, (uint32_t)(e->op - LT) | (left.type == BYTES ? 0x100u : 0), 0);
return (Kind){BOOL, -1};
}
if (left.type == BOOL) {