diff --git a/CMakeLists.txt b/CMakeLists.txt index 28e7772..ee525fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.16) -project(fun VERSION 0.9.2 LANGUAGES C) +project(fun VERSION 0.9.3 LANGUAGES C) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) diff --git a/examples/byte_for_demo.fun b/examples/byte_for_demo.fun new file mode 100644 index 0000000..54106d1 --- /dev/null +++ b/examples/byte_for_demo.fun @@ -0,0 +1,31 @@ +#!/usr/bin/env fun + +// Byte + for-loop demonstration + +print("=== byte with hex literal and clamping ===") + +byte b = 0x1223 // 0x1223 -> 0x23 after 8-bit clamp +print(b) // -> 35 +b = 0xFF +print(b) // -> 255 +b = 0x1FF // 0x1FF -> 0xFF after clamp +print(b) // -> 255 + +print("") +print("=== for-loop reassigning a byte variable (shows clamping near the top end) ===") + +byte acc = 0 +for i in range(250, 260) + acc = i // will clamp at 255 + print(acc) + +print("") +print("=== dynamic vs typed ===") + +x = 0xAB +print(typeof(x)) // -> "Number" +x = "now string" // dynamic variable can change type +print(typeof(x)) // -> "String" + +// Typed byte must remain numeric (uint8): +// b = "oops" // Uncomment to see a runtime type error diff --git a/src/parser.c b/src/parser.c index 48d5161..2f9b0cc 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1752,17 +1752,19 @@ static void parse_simple_statement(Bytecode *bc, const char *src, size_t len, si } /* typed declarations: - number|string|boolean|nil|uint8|uint16|uint32|uint64|int8|int16|int32|int64 (= expr)? - Note: 'number' maps to signed 64-bit here. + number|string|boolean|nil|byte|uint8|uint16|uint32|uint64|int8|int16|int32|int64 (= expr)? + Note: 'number' maps to signed 64-bit here. 'byte' is an alias of unsigned 8-bit. */ if (strcmp(name, "number") == 0 || strcmp(name, "string") == 0 || strcmp(name, "boolean") == 0 || strcmp(name, "nil") == 0 + || strcmp(name, "byte") == 0 || strcmp(name, "uint8") == 0 || strcmp(name, "uint16") == 0 || strcmp(name, "uint32") == 0 || strcmp(name, "uint64") == 0 || strcmp(name, "int8") == 0 || strcmp(name, "int16") == 0 || strcmp(name, "int32") == 0 || strcmp(name, "int64") == 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_byte = (strcmp(name, "byte") == 0); + int is_u8 = (strcmp(name, "uint8") == 0) || is_byte; int is_u16 = (strcmp(name, "uint16") == 0); int is_u32 = (strcmp(name, "uint32") == 0); int is_u64 = (strcmp(name, "uint64") == 0); @@ -2270,7 +2272,7 @@ static void parse_block(Bytecode *bc, const char *src, size_t len, size_t *pos, #define MAP_TYPE_KIND(t) ( \ ((t) && strcmp((t), "string")==0) ? 2 : \ ((t) && strcmp((t), "nil")==0) ? 3 : \ - ((t) && (strcmp((t), "boolean")==0 || strcmp((t), "number")==0 || strncmp((t), "uint", 4)==0 || strncmp((t), "sint", 4)==0 || strncmp((t), "int", 3)==0)) ? 1 : \ + ((t) && (strcmp((t), "boolean")==0 || strcmp((t), "number")==0 || strcmp((t), "byte")==0 || strncmp((t), "uint", 4)==0 || strncmp((t), "sint", 4)==0 || strncmp((t), "int", 3)==0)) ? 1 : \ 0 ) skip_spaces(src, len, pos); diff --git a/src/parser_utils.c b/src/parser_utils.c index 74b722f..31c966a 100644 --- a/src/parser_utils.c +++ b/src/parser_utils.c @@ -167,7 +167,29 @@ static int64_t parse_int_literal_value(const char *src, size_t len, size_t *pos, if (src[p] == '-') sign = -1; p++; } - if (p >= len || !isdigit((unsigned char)src[p])) { *ok = 0; return 0; } + if (p >= len) { *ok = 0; return 0; } + + /* Hexadecimal: 0x... or 0X... */ + if ((p + 1) < len && src[p] == '0' && (src[p + 1] == 'x' || src[p + 1] == 'X')) { + p += 2; + if (p >= len || !isxdigit((unsigned char)src[p])) { *ok = 0; return 0; } + int64_t val = 0; + while (p < len && isxdigit((unsigned char)src[p])) { + char c = src[p]; + int d = (c >= '0' && c <= '9') ? (c - '0') + : (c >= 'a' && c <= 'f') ? (c - 'a' + 10) + : (c >= 'A' && c <= 'F') ? (c - 'A' + 10) + : 0; + val = (val << 4) + d; + p++; + } + *pos = p; + *ok = 1; + return sign * val; + } + + /* Decimal fallback */ + if (!isdigit((unsigned char)src[p])) { *ok = 0; return 0; } int64_t val = 0; while (p < len && isdigit((unsigned char)src[p])) { val = val * 10 + (src[p] - '0');