1
0
Fork 0
forked from fun/fun

Added typeof opcode to verify variable types.

This commit is contained in:
Johannes Findeisen 2025-09-16 03:45:25 +02:00
commit 7e9f24114e
6 changed files with 78 additions and 1 deletions

50
examples/typeof.fun Executable file
View file

@ -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 <you@hanez.org>
* 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
*/

View file

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

View file

@ -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; }

View file

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

View file

@ -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",

17
src/vm/typeof.c Normal file
View file

@ -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;
}