summaryrefslogtreecommitdiff
path: root/uscript/val.h
blob: 5140fc29f1c622c20e315bf08408539c65163306 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#ifndef __USCRIPT_VAL_H__
#define __USCRIPT_VAL_H__

#include "common.h"
#include "uscript.h"

#define create_num(n)  ((struct us_val){.type=VAL_NUM,   .dat={.number=(n)}})
#define create_bool(b) ((struct us_val){.type=VAL_BOOL,  .dat={.boolean=(b)}})
#define create_zilch() ((struct us_val){.type=VAL_ZILCH, .dat={.number=0}})
#define wrap_str(o)    ((struct us_val){.type=VAL_STR,   .dat={.str=(o)}})
#define wrap_arr(o)    ((struct us_val){.type=VAL_ARR,   .dat={.arr=(o)}})
#define wrap_proto(o)  ((struct us_val){.type=VAL_PROTO, .dat={.proto=(o)}})
#define wrap_func(o)   ((struct us_val){.type=VAL_FUNC,  .dat={.func=(o)}})
#define wrap_cfunc(o)  ((struct us_val){.type=VAL_CFUNC, .dat={.cfunc=(o)}})
#define wrap_upval(o)  ((struct us_val){.type=VAL_UPVAL, .dat={.upval=(o)}})

#define get_num(v)   (v.dat.number)
#define get_bool(v)  (v.dat.boolean)
#define get_obj(v)   (v.dat.obj)
#define get_str(v)   (v.dat.str)
#define get_arr(v)   (v.dat.arr)
#define get_proto(v) (v.dat.proto)
#define get_func(v)  (v.dat.func)
#define get_cfunc(v) (v.dat.cfunc)
#define get_upval(v) (v.dat.upval)

#define val_is_obj(v) (v.type >= VAL_STR)

#define proto_add_byte(func, op) da_append(u8, &(func)->bytecode, op)

enum val_type {
        VAL_NUM,
        VAL_BOOL,
        VAL_ZILCH,
        // Do not place any new object types before VAL_STR. Object types are
        // detected by doing a comparison with VAL_STR. See val_is_obj().
        VAL_STR,
        VAL_ARR,
        VAL_PROTO,
        VAL_FUNC,
        VAL_CFUNC,
        VAL_UPVAL,
};

struct us_val {
        enum val_type type;
        union {
                double number;
                bool boolean;
                struct us_obj *obj;
                struct us_str *str;
                struct us_arr *arr;
                struct us_proto *proto;
                struct us_func *func;
                struct us_cfunc *cfunc;
                struct us_upval *upval;
        } dat;
};

struct us_obj {
        // We don't need the object header for now; it will be useful in the
        // future, though.
        u8 _placeholder;
};

struct us_str {
        struct us_obj header;
        char *chars;
        size_t len;
};

struct us_arr {
        struct us_obj header;
        struct us_val *e; // dyn_arr
};

struct us_proto {
        struct us_obj header;
        const struct us_str *name;
        struct us_val constants[UINT8_MAX];
        u8 *bytecode; // dyn_arr
        int* upval_locs;
        int upvalc;
        int argc;
        bool is_variadic;
        u8 nconstants;
};

struct us_cfunc {
        struct us_obj header;
        us_cfunc_sig c;
        const struct us_str *name;
        int argc;
};

struct us_func {
        struct us_obj header;
        struct us_proto *proto;
        struct us_upval **upvals;
};

struct us_upval {
        struct us_obj header;
        struct us_val *loc;
        struct us_val closed;
        struct us_upval *next;
};

struct us_str *take_str(char *chars, int len);
struct us_str *copy_str(const char *chars, int len);
struct us_arr *create_arr(void);
struct us_proto *create_proto(struct us_str *name);
struct us_func *create_func(struct us_proto *proto);
struct us_cfunc *create_cfunc(struct us_str *name, us_cfunc_sig func, int argc);
struct us_upval *create_upval(struct us_val *val);

void free_val(struct us_val v);

void proto_add_const(struct us_proto *func, struct us_val v);

bool vals_eql(struct us_val a, struct us_val b);

char *val_to_str(struct us_val v, int *len_out);

#endif // __USCRIPT_VAL_H__