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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
#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_map(o) ((struct us_val){.type=VAL_MAP, .dat={.map=(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_map(v) (v.dat.map)
#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)
#define cfunc_add_upval(c, v) da_append(struct us_val, &c->upvals, v)
#define cfunc_set_upval(c, i, v) (c->upvals[i] = (v))
#define cfunc_get_upval(c, i) (c->upvals[i])
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_MAP,
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_map *map;
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_map_kv {
struct us_val key;
struct us_val val;
};
struct us_map {
struct us_obj header;
struct us_map_kv *e;
struct us_val locked;
int len;
int cap;
};
struct us_proto {
struct us_obj header;
const struct us_str *name;
struct us_val constants[UINT8_MAX];
u8 *bytecode; // dyn_arr
int *lines; // 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;
struct us_val *upvals;
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_map *create_map(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);
bool val_as_bool(struct us_val v);
#endif // __USCRIPT_VAL_H__
|