1
0
Fork 0
forked from fun/fun

Added S as a prefix to signed integers to make more consistent. E.g.: sint8 instead of int8.

This commit is contained in:
Johannes Findeisen 2025-09-16 12:59:44 +02:00
commit 0ceebfbdad
3 changed files with 136 additions and 7 deletions

View file

@ -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))

View file

@ -0,0 +1,63 @@
#!/usr/bin/env fun
// Demonstration of enhanced typeof behavior:
//
// - typeof(<identifier>) for declared integer types returns the subtype:
// Sint8, Sint16, Sint32, Sint64, Uint8, Uint16, Uint32, Uint64
// - typeof(<expression>) 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

View file

@ -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(<identifier>) -> 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);