From 0ceebfbdadfd2a8801fbaa941395868f1d2bb155 Mon Sep 17 00:00:00 2001 From: hanez Date: Tue, 16 Sep 2025 12:59:44 +0200 Subject: [PATCH] Added S as a prefix to signed integers to make more consistent. E.g.: sint8 instead of int8. --- examples/signed_ints.fun | 8 ++-- examples/typeof_features.fun | 63 +++++++++++++++++++++++++++++++ src/parser.c | 72 ++++++++++++++++++++++++++++++++++-- 3 files changed, 136 insertions(+), 7 deletions(-) create mode 100644 examples/typeof_features.fun diff --git a/examples/signed_ints.fun b/examples/signed_ints.fun index ed1b524..7190e0a 100644 --- a/examples/signed_ints.fun +++ b/examples/signed_ints.fun @@ -2,10 +2,10 @@ // Signed integer type examples with two's complement wrapping -int8 s8 = -1 // should be -1 within int8 range -int16 s16 = -32768 // min int16 -int32 s32 = -2147483648 -int64 s64 = -9223372036854775808 +sint8 s8 = -1 // should be -1 within sint8 range +sint16 s16 = -32768 // min sint16 +sint32 s32 = -2147483648 +sint64 s64 = -9223372036854775808 print("s8 = " + to_string(s8) + " :: " + typeof(s8)) print("s16 = " + to_string(s16) + " :: " + typeof(s16)) diff --git a/examples/typeof_features.fun b/examples/typeof_features.fun new file mode 100644 index 0000000..058088d --- /dev/null +++ b/examples/typeof_features.fun @@ -0,0 +1,63 @@ +#!/usr/bin/env fun + +// Demonstration of enhanced typeof behavior: +// +// - typeof() for declared integer types returns the subtype: +// Sint8, Sint16, Sint32, Sint64, Uint8, Uint16, Uint32, Uint64 +// - typeof() or non-integer identifiers returns runtime categories: +// Number, String, Array, Map, Function, Nil + +// Integer subtypes (declared) +sint8 si8 = -1 +sint16 si16 = -32768 +sint32 si32 = -2147483648 +sint64 si64 = -9223372036854775808 + +uint8 ui8 = 255 +uint16 ui16 = 65535 +uint32 ui32 = 4294967295 +uint64 ui64 = 18446744073709551615 + +// 'number' maps to Uint64 behavior by design +number n = 42 + +// Other runtime types +string s = "hello" +arr = [1, 2, 3] +m = { "k": 1 } + +fun f() + return 0 + +nil x = nil + +// typeof on identifiers (for integers => declared subtype) +print("typeof(si8) = " + typeof(si8)) // Int8 +print("typeof(si16) = " + typeof(si16)) // Int16 +print("typeof(si32) = " + typeof(si32)) // Int32 +print("typeof(si64) = " + typeof(si64)) // Int64 + +print("typeof(ui8) = " + typeof(ui8)) // Uint8 +print("typeof(ui16) = " + typeof(ui16)) // Uint16 +print("typeof(ui32) = " + typeof(ui32)) // Uint32 +print("typeof(ui64) = " + typeof(ui64)) // Uint64 + +print("typeof(n) = " + typeof(n)) // Uint64 + +// typeof on identifiers for non-integers -> runtime categories +print("typeof(s) = " + typeof(s)) // String +print("typeof(arr) = " + typeof(arr)) // Array +print("typeof(m) = " + typeof(m)) // Map +print("typeof(f) = " + typeof(f)) // Function +print("typeof(x) = " + typeof(x)) // Nil + +// typeof on expressions -> runtime category (Number), not the declared subtype +print("typeof(ui8 + 1) = " + typeof(ui8 + 1)) // Number +print("typeof(si16 - 2) = " + typeof(si16 - 2))// Number + +// Demonstrate that subtype remains on identifier after operations (assignment clamps) +ui8 = ui8 + 10 +print("ui8 value = " + to_string(ui8) + ", typeof(ui8) = " + typeof(ui8)) // Uint8 + +si8 = si8 - 5 +print("si8 value = " + to_string(si8) + ", typeof(si8) = " + typeof(si8)) // Int8 diff --git a/src/parser.c b/src/parser.c index 60c8e56..128046d 100644 --- a/src/parser.c +++ b/src/parser.c @@ -453,9 +453,68 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos) } if (strcmp(name, "typeof") == 0) { (*pos)++; /* '(' */ - if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "typeof expects 1 argument"); free(name); return 0; } - if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after typeof arg"); free(name); return 0; } - bytecode_add_instruction(bc, OP_TYPEOF, 0); + /* Special-case: typeof() -> use declared integer subtype if available */ + size_t peek = *pos; + char *vname = NULL; + int handled = 0; + if (read_identifier_into(src, len, &peek, &vname)) { + /* allow spaces before ')' */ + skip_spaces(src, len, &peek); + if (peek < len && src[peek] == ')') { + /* Find declared type metadata for the identifier */ + int decl_bits = 0; /* >0 unsigned width, <0 signed width, 0 unknown/non-integer */ + int lidx2 = local_find(vname); + if (lidx2 >= 0 && g_locals) { + decl_bits = g_locals->types[lidx2]; + } else { + /* lookup existing global without creating a new symbol */ + int gidx2 = -1; + for (int gi_ = 0; gi_ < G.count; ++gi_) { + if (strcmp(G.names[gi_], vname) == 0) { gidx2 = gi_; break; } + } + if (gidx2 >= 0) decl_bits = G.types[gidx2]; + } + + if (decl_bits != 0) { + int bits = decl_bits < 0 ? -decl_bits : decl_bits; + int is_signed = (decl_bits < 0); + char tbuf[16]; + snprintf(tbuf, sizeof(tbuf), "%s%d", is_signed ? "Sint" : "Uint", bits); + int ci = bytecode_add_constant(bc, make_string(tbuf)); + bytecode_add_instruction(bc, OP_LOAD_CONST, ci); + } else { + /* Fallback: load the variable and use runtime typeof */ + if (lidx2 >= 0) { + bytecode_add_instruction(bc, OP_LOAD_LOCAL, lidx2); + } else { + /* If global not yet present, create symbol to load its value (likely nil) */ + int gi2 = -1; + /* try to reuse existing id if found earlier */ + for (int gi_ = 0; gi_ < G.count; ++gi_) { + if (strcmp(G.names[gi_], vname) == 0) { gi2 = gi_; break; } + } + if (gi2 < 0) gi2 = sym_index(vname); + bytecode_add_instruction(bc, OP_LOAD_GLOBAL, gi2); + } + bytecode_add_instruction(bc, OP_TYPEOF, 0); + } + free(vname); + /* consume the ')' */ + *pos = peek + 1; + handled = 1; + } else { + /* not a simple identifier-only typeof */ + free(vname); + } + } + + if (!handled) { + /* General case: typeof(expression) */ + if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "typeof expects 1 argument"); free(name); return 0; } + if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after typeof arg"); free(name); return 0; } + bytecode_add_instruction(bc, OP_TYPEOF, 0); + } + free(name); return 1; } @@ -1398,6 +1457,13 @@ static void parse_simple_statement(Bytecode *bc, const char *src, size_t len, si size_t local_pos = *pos; char *name = NULL; if (read_identifier_into(src, len, &local_pos, &name)) { + + /* alias: accept 'sint*' as synonyms for 'int*' */ + if (strcmp(name, "sint8") == 0) { free(name); name = strdup("int8"); } + else if (strcmp(name, "sint16") == 0) { free(name); name = strdup("int16"); } + else if (strcmp(name, "sint32") == 0) { free(name); name = strdup("int32"); } + else if (strcmp(name, "sint64") == 0) { free(name); name = strdup("int64"); } + /* return statement */ if (strcmp(name, "return") == 0) { free(name);