Fun 0.41.5
The programming language that makes You have fun
Loading...
Searching...
No Matches
value.c
Go to the documentation of this file.
1/*
2 * This file is part of the Fun programming language.
3 * https://fun-lang.xyz/
4 *
5 * Copyright 2025 Johannes Findeisen <you@hanez.org>
6 * Licensed under the terms of the Apache-2.0 license.
7 * https://opensource.org/license/apache-2-0
8 */
9
21
22#include "value.h"
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27/* Compile helper implementations into this TU to avoid build system changes */
28#include "array_utils.c"
29#include "str_utils.c"
30
31typedef struct Array {
33 int count;
34 Value *items; /* owns items; each item owned by array */
36
37typedef struct Map {
38 int refcount;
39 int count;
40 int cap;
41 char **keys; /* each key owned here */
42 Value *vals; /* each value owned here */
44
51Value make_int(int64_t v) {
53 val.type = VAL_INT;
54 val.i = v;
55 return val;
56}
57
64Value make_float(double v) {
66 val.type = VAL_FLOAT;
67 val.d = v;
68 return val;
69}
70
81 val.type = VAL_BOOL;
82 val.i = v ? 1 : 0;
83 return val;
84}
85
95Value make_string(const char *s) {
97 val.type = VAL_STRING;
98 if (s)
99 val.s = strdup(s);
100 else
101 val.s = strdup("");
102 return val;
103}
104
115 Value val;
116 val.type = VAL_FUNCTION;
117 val.fn = fn;
118 return val;
119}
120
127 Value v;
128 v.type = VAL_NIL;
129 return v;
130}
131
143 if (count < 0) count = 0;
144 Array *arr = (Array *)malloc(sizeof(Array));
145 if (!arr) {
146 Value nil = make_nil();
147 return nil;
148 }
149 arr->refcount = 1;
150 arr->count = count;
151 if (count > 0) {
152 arr->items = (Value *)malloc(sizeof(Value) * count);
153 if (!arr->items) {
154 free(arr);
155 Value nil = make_nil();
156 return nil;
157 }
158 for (int i = 0; i < count; ++i) {
159 arr->items[i] = copy_value(&vals[i]);
160 }
161 } else {
162 arr->items = NULL;
163 }
164 Value v;
165 v.type = VAL_ARRAY;
166 v.arr = (struct Array *)arr;
167 return v;
168}
169
176int array_length(const Value *v) {
177 if (!v || v->type != VAL_ARRAY || !v->arr) return -1;
178 const Array *a = (const Array *)v->arr;
179 return a->count;
180}
181
192int array_get_copy(const Value *v, int index, Value *out) {
193 if (!v || v->type != VAL_ARRAY || !v->arr) return 0;
194 const Array *a = (const Array *)v->arr;
195 if (index < 0 || index >= a->count) return 0;
196 if (out) *out = copy_value(&a->items[index]);
197 return 1;
198}
199
210int array_set(Value *v, int index, Value newElem) {
211 if (!v || v->type != VAL_ARRAY || !v->arr) return 0;
212 Array *a = (Array *)v->arr;
213 if (index < 0 || index >= a->count) return 0;
214 free_value(a->items[index]);
215 a->items[index] = newElem; /* take ownership */
216 return 1;
217}
218
228static int ensure_array_capacity(Array *a, int newCount) {
229 if (newCount <= a->count) return 1;
230 /* grow to at least newCount; double strategy */
231 int curr = a->count;
232 int cap = curr;
233 if (cap < 4) cap = 4;
234 while (cap < newCount)
235 cap *= 2;
236 Value *newItems = (Value *)realloc(a->items, sizeof(Value) * cap);
237 if (!newItems) return 0;
238 /* if growing beyond current count, initialize new slots to nil */
239 if (cap > a->count) {
240 for (int i = a->count; i < cap; ++i) {
241 newItems[i] = make_nil();
242 }
243 }
244 a->items = newItems;
245 return 1;
246}
247
257int array_push(Value *v, Value newElem) {
258 if (!v || v->type != VAL_ARRAY || !v->arr) return -1;
259 Array *a = (Array *)v->arr;
260 /* ensure capacity for count+1 by reallocating items array to at least count+1 elements */
261 Value *newItems = (Value *)realloc(a->items, sizeof(Value) * (a->count + 1));
262 if (!newItems) {
263 free_value(newElem);
264 return -1;
265 }
266 a->items = newItems;
267 a->items[a->count] = newElem; /* take ownership */
268 a->count += 1;
269 return a->count;
270}
271
283 if (!v || v->type != VAL_ARRAY || !v->arr) return 0;
284 Array *a = (Array *)v->arr;
285 if (a->count <= 0) return 0;
286 int idx = a->count - 1;
287 if (out)
288 *out = a->items[idx]; /* transfer ownership */
289 else
290 free_value(a->items[idx]);
291 a->count -= 1;
292 return 1;
293}
294
305int array_insert(Value *v, int index, Value newElem) {
306 if (!v || v->type != VAL_ARRAY || !v->arr) return -1;
307 Array *a = (Array *)v->arr;
308 if (index < 0) index = 0;
309 if (index > a->count) index = a->count;
310 Value *newItems = (Value *)realloc(a->items, sizeof(Value) * (a->count + 1));
311 if (!newItems) {
312 free_value(newElem);
313 return -1;
314 }
315 a->items = newItems;
316 /* shift right */
317 for (int i = a->count; i > index; --i) {
318 a->items[i] = a->items[i - 1];
319 }
320 a->items[index] = newElem; /* take ownership */
321 a->count += 1;
322 return a->count;
323}
324
336int array_remove(Value *v, int index, Value *out) {
337 if (!v || v->type != VAL_ARRAY || !v->arr) return 0;
338 Array *a = (Array *)v->arr;
339 if (index < 0 || index >= a->count) return 0;
340 if (out)
341 *out = a->items[index]; /* transfer ownership */
342 else
343 free_value(a->items[index]);
344 /* shift left */
345 for (int i = index; i < a->count - 1; ++i) {
346 a->items[i] = a->items[i + 1];
347 }
348 a->count -= 1;
349 return 1;
350}
351
362Value array_slice(const Value *v, int start, int end) {
363 if (!v || v->type != VAL_ARRAY || !v->arr) return make_nil();
364 const Array *a = (const Array *)v->arr;
365 int n = a->count;
366 if (start < 0) start = 0;
367 if (end < 0 || end > n) end = n;
368 if (start > end) start = end;
369 int m = end - start;
370 if (m <= 0) {
371 return make_array_from_values(NULL, 0);
372 }
373 return make_array_from_values(a->items + start, m);
374}
375
386Value array_concat(const Value *av, const Value *bv) {
387 if (!av || !bv || av->type != VAL_ARRAY || bv->type != VAL_ARRAY) return make_nil();
388 const Array *a = (const Array *)av->arr;
389 const Array *b = (const Array *)bv->arr;
390 int na = a ? a->count : 0;
391 int nb = b ? b->count : 0;
392 int total = na + nb;
393 if (total <= 0) return make_array_from_values(NULL, 0);
394 Value *tmp = (Value *)malloc(sizeof(Value) * total);
395 if (!tmp) return make_nil();
396 for (int i = 0; i < na; ++i)
397 tmp[i] = a->items[i];
398 for (int j = 0; j < nb; ++j)
399 tmp[na + j] = b->items[j];
400 Value out = make_array_from_values(tmp, total);
401 /* free temporaries we copied from (deep copy in make_array_from_values) */
402 free(tmp);
403 return out;
404}
405
416 Value out;
417 out.type = v->type;
418 switch (v->type) {
419 case VAL_INT:
420 out.i = v->i;
421 break;
422 case VAL_FLOAT:
423 out.d = v->d;
424 break;
425 case VAL_BOOL:
426 out.i = v->i ? 1 : 0;
427 break;
428 case VAL_STRING:
429 out.s = v->s ? strdup(v->s) : strdup("");
430 break;
431 case VAL_FUNCTION:
432 out.fn = v->fn; /* shallow copy pointer */
433 break;
434 case VAL_ARRAY: {
435 Array *a = (Array *)v->arr;
436 out.arr = (struct Array *)a;
437 if (a) a->refcount++;
438 break;
439 }
440 case VAL_MAP: {
441 Map *m = (Map *)v->map;
442 out.map = (struct Map *)m;
443 if (m) m->refcount++;
444 break;
445 }
446 case VAL_NIL:
447 default:
448 break;
449 }
450 return out;
451}
452
453/* deep copy including arrays (recursively copies items) */
464 switch (v->type) {
465 case VAL_INT:
466 return make_int(v->i);
467 case VAL_FLOAT:
468 return make_float(v->d);
469 case VAL_BOOL:
470 return make_bool(v->i);
471 case VAL_STRING:
472 return make_string(v->s ? v->s : "");
473 case VAL_FUNCTION:
474 return make_function(v->fn); /* shallow pointer for function bytecode */
475 case VAL_ARRAY: {
476 const Array *a = (const Array *)v->arr;
477 if (!a || a->count <= 0) {
478 return make_array_from_values(NULL, 0);
479 }
480 /* copy items deeply */
481 Value *tmp = (Value *)malloc(sizeof(Value) * a->count);
482 if (!tmp) return make_nil();
483 for (int i = 0; i < a->count; ++i) {
484 tmp[i] = deep_copy_value(&a->items[i]);
485 }
486 Value out = make_array_from_values(tmp, a->count);
487 for (int i = 0; i < a->count; ++i) {
488 free_value(tmp[i]);
489 }
490 free(tmp);
491 return out;
492 }
493 case VAL_MAP: {
494 const Map *m = (const Map *)v->map;
495 if (!m || m->count <= 0) return make_map_empty();
497 for (int i = 0; i < m->count; ++i) {
498 Value dv = deep_copy_value(&m->vals[i]);
499 map_set(&out, m->keys[i], dv);
500 }
501 return out;
502 }
503 case VAL_NIL:
504 default:
505 return make_nil();
506 }
507}
508
518 if (v.type == VAL_STRING && v.s) {
519 free(v.s);
520 } else if (v.type == VAL_ARRAY && v.arr) {
521 Array *a = (Array *)v.arr;
522 if (--a->refcount == 0) {
523 for (int i = 0; i < a->count; ++i) {
524 free_value(a->items[i]);
525 }
526 free(a->items);
527 free(a);
528 }
529 } else if (v.type == VAL_MAP && v.map) {
530 Map *m = (Map *)v.map;
531 if (--m->refcount == 0) {
532 for (int i = 0; i < m->count; ++i) {
533 if (m->keys[i]) free(m->keys[i]);
534 free_value(m->vals[i]);
535 }
536 free(m->keys);
537 free(m->vals);
538 free(m);
539 }
540 }
541 /* VAL_FUNCTION: we *do not* free the Bytecode here (caller frees it) */
542}
543
552void print_value(const Value *v) {
553 switch (v->type) {
554 case VAL_INT:
555 printf("%" PRId64, v->i);
556 break;
557 case VAL_FLOAT:
558 printf("%.17g", v->d);
559 break;
560 case VAL_STRING:
561 printf("%s", v->s ? v->s : "");
562 break;
563 case VAL_BOOL:
564 printf("%s", v->i ? "true" : "false");
565 break;
566 case VAL_FUNCTION:
567 printf("<function@%p>", (void *)v->fn);
568 break;
569 case VAL_ARRAY: {
570 const Array *a = (const Array *)v->arr;
571 printf("[");
572 if (a) {
573 for (int i = 0; i < a->count; ++i) {
574 if (i > 0) printf(", ");
575 print_value(&a->items[i]);
576 }
577 }
578 printf("]");
579 break;
580 }
581 case VAL_MAP: {
582 const Map *m = (const Map *)v->map;
583 printf("{");
584 if (m) {
585 for (int i = 0; i < m->count; ++i) {
586 if (i > 0) printf(", ");
587 printf("\"%s\": ", m->keys[i] ? m->keys[i] : "");
588 print_value(&m->vals[i]);
589 }
590 }
591 printf("}");
592 break;
593 }
594 case VAL_NIL:
595 default:
596 printf("nil");
597 break;
598 }
599}
600
610int value_is_truthy(const Value *v) {
611 switch (v->type) {
612 case VAL_INT:
613 return v->i != 0;
614 case VAL_FLOAT:
615 return v->d != 0.0;
616 case VAL_BOOL:
617 return v->i != 0;
618 case VAL_STRING:
619 return v->s && v->s[0] != '\0';
620 case VAL_FUNCTION:
621 return 1;
622 case VAL_ARRAY: {
623 const Array *a = (const Array *)v->arr;
624 return a && a->count > 0;
625 }
626 case VAL_NIL:
627 default:
628 return 0;
629 }
630}
631
632/* allocate a printable C string for the value; caller must free */
642 if (!v) return strdup("nil");
643 char buf[128];
644 switch (v->type) {
645 case VAL_INT: {
646 char tmp[64];
647 snprintf(tmp, sizeof(tmp), "%" PRId64, v->i);
648 return strdup(tmp);
649 }
650 case VAL_FLOAT: {
651 char tmp[64];
652 snprintf(tmp, sizeof(tmp), "%.17g", v->d);
653 return strdup(tmp);
654 }
655 case VAL_STRING:
656 return strdup(v->s ? v->s : "");
657 case VAL_BOOL:
658 return strdup(v->i ? "true" : "false");
659 case VAL_FUNCTION: {
660 snprintf(buf, sizeof(buf), "<function@%p>", (void *)v->fn);
661 return strdup(buf);
662 }
663 case VAL_ARRAY: {
664 int n = array_length(v);
665 if (n < 0) n = 0;
666 snprintf(buf, sizeof(buf), "[array n=%d]", n);
667 return strdup(buf);
668 }
669 case VAL_MAP: {
670 int n = 0;
671 if (v->type == VAL_MAP && v->map) {
672 const Map *m = (const Map *)v->map;
673 n = m ? m->count : 0;
674 }
675 snprintf(buf, sizeof(buf), "{map n=%d}", n);
676 return strdup(buf);
677 }
678 case VAL_NIL:
679 default:
680 return strdup("nil");
681 }
682}
683
695int value_equals(const Value *a, const Value *b) {
696 // Numeric cross-type equality: int vs float compares numerically
697 if ((a->type == VAL_INT || a->type == VAL_FLOAT) && (b->type == VAL_INT || b->type == VAL_FLOAT)) {
698 double da = (a->type == VAL_INT) ? (double)a->i : a->d;
699 double db = (b->type == VAL_INT) ? (double)b->i : b->d;
700 return da == db;
701 }
702 if (a->type != b->type) return 0;
703 switch (a->type) {
704 case VAL_INT:
705 return a->i == b->i;
706 case VAL_BOOL:
707 return (a->i != 0) == (b->i != 0);
708 case VAL_STRING: {
709 const char *sa = a->s ? a->s : "";
710 const char *sb = b->s ? b->s : "";
711 return strcmp(sa, sb) == 0;
712 }
713 default:
714 return 0;
715 }
716}
Value a
Definition add.c:37
Value out
Definition apop.c:38
Utility functions for operating on Value arrays.
uint32_t b
Definition band.c:32
Value v
Definition cast.c:22
array_clear & arr
Definition clear.c:38
double da
Definition fmax.c:26
double db
Definition fmax.c:27
Value m
Definition has_key.c:27
int idx
Definition index_of.c:38
size_t cap
Definition input_line.c:101
char * buf
Definition input_line.c:103
int n
Definition insert.c:41
Value val
Definition load_local.c:36
Value * vals
Definition make_array.c:39
free(vals)
int map_set(Value *vm, const char *key, Value v)
Insert or replace a key in the map.
Definition map.c:79
Value make_map_empty(void)
Construct a new empty map Value.
Definition map.c:35
int count
Definition parser.c:266
uint32_t s
Definition rol.c:31
Value start
Definition slice.c:34
Helpers for manipulating C strings and bridging with Value arrays.
Definition value.c:31
Value * items
Definition value.c:34
int refcount
Definition value.c:32
int count
Definition value.c:33
Definition map.c:20
int refcount
Definition map.c:21
char ** keys
Definition map.c:24
int cap
Definition map.c:23
int count
Definition map.c:22
Value * vals
Definition map.c:25
Tagged union representing a Fun value.
Definition value.h:68
struct Array * arr
Definition value.h:75
ValueType type
Definition value.h:69
int value_is_truthy(const Value *v)
Evaluate a Value's truthiness according to Fun language rules.
Definition value.c:610
Value make_bool(int v)
Construct a boolean Value.
Definition value.c:79
void print_value(const Value *v)
Print a human-readable representation of a Value to stdout.
Definition value.c:552
Value array_concat(const Value *av, const Value *bv)
Concatenate two array Values.
Definition value.c:386
Value make_nil(void)
Construct a nil Value.
Definition value.c:126
int array_insert(Value *v, int index, Value newElem)
Insert a new element at a specific position in an array.
Definition value.c:305
int array_pop(Value *v, Value *out)
Remove the last element from an array.
Definition value.c:282
Value make_string(const char *s)
Construct a string Value by duplicating the given C string.
Definition value.c:95
int array_length(const Value *v)
Get the element count of an array Value.
Definition value.c:176
Value make_function(struct Bytecode *fn)
Construct a function Value referencing bytecode.
Definition value.c:114
Value deep_copy_value(const Value *v)
Deep copy a Value, recursively copying arrays and maps.
Definition value.c:463
void free_value(Value v)
Free dynamic storage owned by a Value.
Definition value.c:517
char * value_to_string_alloc(const Value *v)
Allocate a printable C string for a Value.
Definition value.c:641
int array_get_copy(const Value *v, int index, Value *out)
Copy an array element into out.
Definition value.c:192
Value make_float(double v)
Construct a Value representing a double-precision float.
Definition value.c:64
int array_push(Value *v, Value newElem)
Append a Value to an array.
Definition value.c:257
int value_equals(const Value *a, const Value *b)
Compare two Values for equality.
Definition value.c:695
Value make_int(int64_t v)
Construct a Value representing a 64-bit integer.
Definition value.c:51
Value array_slice(const Value *v, int start, int end)
Create a shallow-copied slice of an array Value.
Definition value.c:362
Value make_array_from_values(const Value *vals, int count)
Create an array Value by copying items from an input span.
Definition value.c:142
int array_set(Value *v, int index, Value newElem)
Replace an element of an array with a new Value.
Definition value.c:210
Value copy_value(const Value *v)
Shallow copy a Value.
Definition value.c:415
int array_remove(Value *v, int index, Value *out)
Remove an element at index from an array.
Definition value.c:336
Defines the Value type and associated functions for the Fun VM.
@ VAL_BOOL
Definition value.h:52
@ VAL_ARRAY
Definition value.h:55
@ VAL_MAP
Definition value.h:56
@ VAL_STRING
Definition value.h:53
@ VAL_FUNCTION
Definition value.h:54
@ VAL_NIL
Definition value.h:57
@ VAL_INT
Definition value.h:51
@ VAL_FLOAT
Definition value.h:58