1
0
Fork 0
forked from fun/fun

Integer/Number and uint(8,16,32,64bit) fun... ;)

This commit is contained in:
Johannes Findeisen 2025-09-16 12:29:28 +02:00
commit 6d3456b62c
6 changed files with 182 additions and 6 deletions

75
examples/types_integers.fun Executable file
View file

@ -0,0 +1,75 @@
#!/usr/bin/env fun
/*
* This file is part of the Fun programming language.
* https://hanez.org/project/fun/
*
* Copyright 2025 Johannes Findeisen <you@hanez.org>
* Licensed under the terms of the ISC license.
* https://opensource.org/license/isc-license-txt
*/
// Integer (number) and boolean usage examples
// Basic typed integers
number a = 42
number b = -7
number zero = 0
print("a = " + to_string(a) + " :: " + typeof(a)) // "Number"
print("b = " + to_string(b) + " :: " + typeof(b)) // "Number"
print("zero = " + to_string(zero) + " :: " + typeof(zero))
// Arithmetic with integers
number sum = a + b
number diff = a - b
number prod = a * 3
number quot = a / 2
number rem = a % 5
print("sum (a + b) = " + to_string(sum))
print("diff (a - b) = " + to_string(diff))
print("prod (a * 3) = " + to_string(prod))
print("quot (a / 2) = " + to_string(quot))
print("rem (a % 5) = " + to_string(rem))
// Comparisons (results are numbers 1/0 in Fun)
print("a > b = " + to_string(a > b))
print("a >= b = " + to_string(a >= b))
print("a < b = " + to_string(a < b))
print("a <= b = " + to_string(a <= b))
print("a == b = " + to_string(a == b))
print("a != b = " + to_string(a != b))
// Booleans are numeric 1/0; typeof returns "Number"
boolean t = true
boolean f = false
print("t = " + to_string(t) + " :: " + typeof(t))
print("f = " + to_string(f) + " :: " + typeof(f))
// Short-circuit logic with numeric truthiness
print("t && (a > 0) = " + to_string(t && (a > 0)))
print("f || (a < 0) = " + to_string(f || (a < 0)))
// Using integers in a for-range loop: sum 1..5
fun sum_range(lo, hi)
number acc = 0
for i in range(lo, hi + 1)
acc = acc + i
return acc
print("sum 1..5 = " + to_string(sum_range(1, 5)))
// Arrays of integers
nums = [1, 2, 3, 4, 5]
print("nums length = " + to_string(len(nums)))
print("nums[2] = " + to_string(nums[2]))
// Map with numeric fields
pt = { "x": 10, "y": -3 }
print("pt['x'] = " + to_string(pt["x"]) + " :: " + typeof(pt["x"]))
print("pt['y'] = " + to_string(pt["y"]) + " :: " + typeof(pt["y"]))
// Conversions
print("to_string(123) => " + to_string(123))
print("to_number(\"456\") => " + to_string(to_number("456")))

42
examples/uint_types.fun Executable file
View file

@ -0,0 +1,42 @@
#!/usr/bin/env fun
/*
* This file is part of the Fun programming language.
* https://hanez.org/project/fun/
*
* Copyright 2025 Johannes Findeisen <you@hanez.org>
* Licensed under the terms of the ISC license.
* https://opensource.org/license/isc-license-txt
*/
// Unsigned integer type examples with wrapping behavior
uint8 u8 = 255
uint16 u16 = 65535
uint32 u32 = 4294967295
uint64 u64 = 18446744073709551615 // will wrap to 64-bit
print("u8 = " + to_string(u8) + " :: " + typeof(u8))
print("u16 = " + to_string(u16) + " :: " + typeof(u16))
print("u32 = " + to_string(u32) + " :: " + typeof(u32))
print("u64 = " + to_string(u64) + " :: " + typeof(u64))
// Demonstrate wrapping on assignment
u8 = 256 // wraps to 0
u16 = 65536 // wraps to 0
u32 = 4294967296 // wraps to 0
u64 = 18446744073709551616 // wraps to 0
print("wrap u8 -> " + to_string(u8))
print("wrap u16 -> " + to_string(u16))
print("wrap u32 -> " + to_string(u32))
print("wrap u64 -> " + to_string(u64))
// Mixed arithmetic then wrapping
u8 = 250
u8 = u8 + 10 // 260 -> wrap 260 % 256 = 4
print("u8 after +10 wrap -> " + to_string(u8))
// 'number' maps to 64-bit unsigned behavior
number n = -1 // will clamp/wrap to 64-bit (implementation-defined display)
print("number n = " + to_string(n) + " :: " + typeof(n))

View file

@ -75,6 +75,7 @@ typedef enum {
OP_TO_NUMBER, // pops any; pushes int (parse strings)
OP_TO_STRING, // pops any; pushes string
OP_TYPEOF, // pops any; pushes string name of type
OP_UCLAMP, // pops number; pushes number masked to N bits (operand = bits)
// string ops
OP_SPLIT, // pops sep, string; pushes array of strings

View file

@ -89,8 +89,9 @@ static void calc_line_col(const char *src, size_t len, size_t pos, int *out_line
/* very small global symbol table for LOAD_GLOBAL/STORE_GLOBAL */
static struct {
char *names[MAX_GLOBALS];
int types[MAX_GLOBALS]; /* 0=untyped/number default; else bit width: 8/16/32/64 */
int count;
} G = { {0}, 0 };
} G = { {0}, {0}, 0 };
static int sym_index(const char *name) {
for (int i = 0; i < G.count; ++i) {
@ -101,12 +102,14 @@ static int sym_index(const char *name) {
return 0;
}
G.names[G.count] = strdup(name);
G.types[G.count] = 0; /* default: untyped (treat as 64-bit number) */
return G.count++;
}
/* ---- locals environment for functions ---- */
typedef struct {
char *names[MAX_FRAME_LOCALS];
int types[MAX_FRAME_LOCALS]; /* 0=untyped; else bit width: 8/16/32/64 */
int count;
} LocalEnv;
@ -1451,12 +1454,18 @@ static void parse_simple_statement(Bytecode *bc, const char *src, size_t len, si
return;
}
/* typed declarations: number|string|boolean|nil <ident> (= expr)? */
if (strcmp(name, "number") == 0 || strcmp(name, "string") == 0 || strcmp(name, "boolean") == 0 || strcmp(name, "nil") == 0) {
/* typed declarations: number|string|boolean|nil|uint8|uint16|uint32|uint64 <ident> (= expr)? */
if (strcmp(name, "number") == 0 || strcmp(name, "string") == 0 || strcmp(name, "boolean") == 0 || strcmp(name, "nil") == 0
|| strcmp(name, "uint8") == 0 || strcmp(name, "uint16") == 0 || strcmp(name, "uint32") == 0 || strcmp(name, "uint64") == 0) {
int is_number = (strcmp(name, "number") == 0);
int is_string = (strcmp(name, "string") == 0);
int is_boolean = (strcmp(name, "boolean") == 0);
int is_nil = (strcmp(name, "nil") == 0);
int is_u8 = (strcmp(name, "uint8") == 0);
int is_u16 = (strcmp(name, "uint16") == 0);
int is_u32 = (strcmp(name, "uint32") == 0);
int is_u64 = (strcmp(name, "uint64") == 0) || is_number; /* number maps to uint64 */
int decl_bits = is_u8 ? 8 : is_u16 ? 16 : is_u32 ? 32 : is_u64 ? 64 : 0; /* 0 for non-integer types */
free(name);
/* read variable name */
@ -1474,8 +1483,14 @@ static void parse_simple_statement(Bytecode *bc, const char *src, size_t len, si
int existing = local_find(varname);
if (existing >= 0) lidx = existing;
else lidx = local_add(varname);
if (lidx >= 0) {
g_locals->types[lidx] = decl_bits; /* record declared bits (0 for non-integer types) */
}
} else {
gi = sym_index(varname);
if (gi >= 0) {
G.types[gi] = decl_bits;
}
}
free(varname);
@ -1486,6 +1501,10 @@ static void parse_simple_statement(Bytecode *bc, const char *src, size_t len, si
parser_fail(local_pos, "Expected initializer expression after '='");
return;
}
/* clamp if integer type was declared */
if (decl_bits > 0) {
bytecode_add_instruction(bc, OP_UCLAMP, decl_bits);
}
if (lidx >= 0) {
bytecode_add_instruction(bc, OP_STORE_LOCAL, lidx);
} else {
@ -1494,15 +1513,19 @@ static void parse_simple_statement(Bytecode *bc, const char *src, size_t len, si
} else {
/* default initialize if no '=' given */
int ci = -1;
if (is_number || is_boolean) {
ci = bytecode_add_constant(bc, make_int(0));
} else if (is_string) {
if (is_string) {
ci = bytecode_add_constant(bc, make_string(""));
} else if (is_nil) {
ci = bytecode_add_constant(bc, make_nil());
} else if (is_number || is_boolean || decl_bits > 0) {
/* integers/booleans default to 0 */
ci = bytecode_add_constant(bc, make_int(0));
}
if (ci >= 0) {
bytecode_add_instruction(bc, OP_LOAD_CONST, ci);
if (decl_bits > 0) {
bytecode_add_instruction(bc, OP_UCLAMP, decl_bits);
}
if (lidx >= 0) {
bytecode_add_instruction(bc, OP_STORE_LOCAL, lidx);
} else {
@ -1669,6 +1692,16 @@ static void parse_simple_statement(Bytecode *bc, const char *src, size_t len, si
if (local_pos < len && src[local_pos] == '=') {
local_pos++; /* '=' */
if (emit_expression(bc, src, len, &local_pos)) {
/* clamp to declared integer width if present */
int decl_bits = 0;
if (lidx >= 0 && g_locals) {
decl_bits = g_locals->types[lidx];
} else if (gi >= 0) {
decl_bits = G.types[gi];
}
if (decl_bits > 0) {
bytecode_add_instruction(bc, OP_UCLAMP, decl_bits);
}
if (lidx >= 0) {
bytecode_add_instruction(bc, OP_STORE_LOCAL, lidx);
} else {

View file

@ -301,6 +301,7 @@ void vm_run(VM *vm, Bytecode *entry) {
#include "vm/to_number.c"
#include "vm/to_string.c"
#include "vm/typeof.c"
#include "vm/uclamp.c"
default:
if (!opcode_is_valid(inst.op)) {

24
src/vm/uclamp.c Normal file
View file

@ -0,0 +1,24 @@
case OP_UCLAMP: {
/* Clamp/wrap the integer on top of the stack to 'bits' width (unsigned) */
Value v = pop_value(vm);
int bits = inst.operand;
uint64_t u = 0;
if (v.type == VAL_INT) {
u = (uint64_t) v.i;
} else {
/* Non-integers clamp to 0 */
u = 0;
}
if (bits > 0 && bits < 64) {
uint64_t mask = (1ULL << bits) - 1ULL;
u &= mask;
} else {
/* bits >= 64 -> no-op; bits <= 0 -> no-op */
}
push_value(vm, make_int((int64_t)u));
free_value(v);
break;
}