diff --git a/examples/typeof.fun b/examples/typeof.fun new file mode 100755 index 0000000..3d11071 --- /dev/null +++ b/examples/typeof.fun @@ -0,0 +1,50 @@ +#!/usr/bin/env fun + +/* + * This file is part of the Fun programming language. + * https://hanez.org/project/fun/ + * + * Copyright 2025 Johannes Findeisen + * Licensed under the terms of the ISC license. + * https://opensource.org/license/isc-license-txt + */ + +print("=== Typeof test start ===") + + // Array +a = [1, 2, 3] +print(typeof(a)) + +fun f() + print("A function!") + +// Function +print(typeof(f)) +f() + +// Map +m = { "x": 1, "y": 2, "move": move } +print(typeof(m)) + +// Nil +nil x = nil +print(typeof(x)) + +// Number +number n = 10 +print(typeof(n)) + +string s = "Have fun!" +print(typeof(s)) + +print("=== Typeof test end ===") + +/* Expected output: +Array +Function +A function! +Map +Nil +Number +String +*/ diff --git a/src/bytecode.h b/src/bytecode.h index cf1e5c2..f6cb18d 100644 --- a/src/bytecode.h +++ b/src/bytecode.h @@ -72,6 +72,7 @@ typedef enum { // conversions 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 // string ops OP_SPLIT, // pops sep, string; pushes array of strings diff --git a/src/parser.c b/src/parser.c index 571e0fd..6b46261 100644 --- a/src/parser.c +++ b/src/parser.c @@ -448,6 +448,14 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos) free(name); return 1; } + 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); + free(name); + return 1; + } if (strcmp(name, "keys") == 0) { (*pos)++; /* '(' */ if (!emit_expression(bc, src, len, pos) || !consume_char(src, len, pos, ')')) { parser_fail(*pos, "keys expects 1 arg"); free(name); return 0; } diff --git a/src/vm.c b/src/vm.c index 4ed5b84..1724131 100644 --- a/src/vm.c +++ b/src/vm.c @@ -273,6 +273,7 @@ void vm_run(VM *vm, Bytecode *entry) { #include "vm/print.c" #include "vm/to_number.c" #include "vm/to_string.c" + #include "vm/typeof.c" default: if (!opcode_is_valid(inst.op)) { diff --git a/src/vm.h b/src/vm.h index 9f90ae2..fff052e 100644 --- a/src/vm.h +++ b/src/vm.h @@ -35,7 +35,7 @@ static const char *opcode_names[] = { "MOD","AND","OR","NOT","DUP","SWAP", "MAKE_ARRAY","INDEX_GET","INDEX_SET", "LEN","ARR_PUSH","ARR_POP","ARR_SET","ARR_INSERT","ARR_REMOVE","SLICE", - "TO_NUMBER","TO_STRING", + "TO_NUMBER","TO_STRING","TYPEOF", "SPLIT","JOIN","SUBSTR","FIND", "CONTAINS","INDEX_OF","CLEAR", "ENUMERATE","ZIP", diff --git a/src/vm/typeof.c b/src/vm/typeof.c new file mode 100644 index 0000000..10287bd --- /dev/null +++ b/src/vm/typeof.c @@ -0,0 +1,17 @@ +case OP_TYPEOF: { + Value v = pop_value(vm); + const char *tname = "Unknown"; + switch (v.type) { + case VAL_INT: tname = "Number"; break; + case VAL_STRING: tname = "String"; break; + case VAL_FUNCTION: tname = "Function"; break; + case VAL_ARRAY: tname = "Array"; break; + case VAL_MAP: tname = "Map"; break; + case VAL_NIL: tname = "Nil"; break; + default: tname = "Unknown"; break; + } + /* push a new string value; make_string duplicates the C string */ + push_value(vm, make_string(tname)); + free_value(v); + break; +} \ No newline at end of file