summaryrefslogtreecommitdiff
path: root/lib.c
blob: 33ca58b91fb038d2253fdb0d54e1200658fbbe6c (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
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#include <math.h>
#include <time.h>
#include <string.h>
#include <stdio.h>

#include "lib.h"
#include "state.h"
#include "val.h"
#include "util.h"
#include "mem.h"

static Val fn_clock(State *S, int nargs, Val *args) {
	return VAL_NUM((double)clock() / CLOCKS_PER_SEC);
}

static Val fn_write(State *S, int nargs, Val *args) {
	CHECK(nargs>0, "need 1 arg to write");
	for (int i = 0; i < nargs; i++) print_val(args[i]);
	return VAL_NIL;
}
static Val fn_say(State *S, int nargs, Val *args) {
	CHECK(nargs>0, "need 1 arg to say");
	for (int i = 0; i < nargs; i++) println_val(args[i]);
	return VAL_NIL;
}

static uint8_t num_to_u8(Val v) {
	CHECK(IS_NUM(v), "can't convert non-num to u8");
	return (uint8_t)AS_NUM(v);
}
static Val fn_writebytes(State *S, int nargs, Val *args) {
	CHECK(nargs == 1, "need exactly 1 arg to writebytes");
	CHECK(IS_ARR(args[0]), "need array arg to writebytes");
	ObjArr *a = AS_ARR(args[0]);
	uint8_t *buf = malloc(1 * a->len);
	for (int i = 0; i < a->len; i++) {
		buf[i] = num_to_u8(a->d[i]);
	}
	fwrite(buf, 1, a->len, stdout);
	return VAL_NIL;
}

static Val fn_readstring(State *S, int nargs, Val *args){
	CHECK(nargs == 1, "need exactly 1 arg to readstring");
	CHECK(IS_STRING(args[0]), "need string arg to readstring");
	FILE *f = fopen(AS_CSTRING(args[0]), "r");
	CHECK(f != NULL, "io error (fopen)");
	fseek(f, 0L, SEEK_END);
	long flen = ftell(f);
	char *buf = NEW_ARR(S, char, flen+1);
	rewind(f); fread(buf, 1, flen, f);
		CHECK(!ferror(f), "file error");
	buf[flen] = '\0';
	return VAL_OBJ(objstring_take(S, buf, flen));
}


// lists
static Val fn_arr(State *S, int nargs, Val *args) {
	CHECK(nargs == 0, "need 0 args to arr");
	ObjArr *o = objarr_new(S);
	return VAL_OBJ(o);
}
static Val fn_append(State *S, int nargs, Val *args) {
	CHECK(nargs == 2, "need 2 args to append!");
	CHECK(IS_ARR(args[0]), "can only append to arr");
	ObjArr *a = AS_ARR(args[0]);
	objarr_append(S, a, args[1]);
	return args[0];
}
static Val fn_delete(State *S, int nargs, Val *args) {
	CHECK(nargs == 2, "need 2 args to delete!");
	CHECK(IS_ARR(args[0]), "can only delete from arr");
	CHECK(IS_NUM(args[1]), "can only delete using num index");
	ObjArr *a = AS_ARR(args[0]);
	size_t ix = (size_t)AS_NUM(args[1]);
	objarr_delete(S, a, ix);
	return args[0];
}
static Val fn_len(State *S, int nargs, Val *args) {
	CHECK(nargs == 1, "need 1 arg to len");
	CHECK(IS_ARR(args[0]), "can only take length of arr");
	ObjArr *a = AS_ARR(args[0]);
	return VAL_NUM(a->len);
}
static Val fn_pend(State *S, int nargs, Val *args) {
	CHECK(nargs > 0, "need at least 1 arg to ,");
	ObjArr *a = objarr_new(S);
	for (int i = 0; i < nargs; i++) {
		Val v = args[i];
		if (!IS_ARR(v))
			objarr_append(S, a, v);
		else {
			ObjArr *b = AS_ARR(v);
			for (int j = 0; j < b->len; j++) 
				objarr_append(S, a, b->d[j]);
		}
	}
	return VAL_OBJ(a);
}


// strings
static Val fn_spend(State *S, int nargs, Val *args) {
	size_t len = 0;
	for (int i = 0; i < nargs; i++) {
		CHECK(IS_STRING(args[i]), "can only spend strings");
		len += AS_STRING(args[i])->len;
	}
	char *new = NEW_ARR(S, char, len+1);
	char *cur = new;
	for (int i = 0; i < nargs; i++) {
		ObjString *s = AS_STRING(args[i]);
		memcpy(cur, s->d, s->len); 
		cur += s->len;
	}
	new[len] = '\0';
	return VAL_OBJ(objstring_take(S, new, len));
}
static Val fn_spendsplat(State *S, int nargs, Val *args) {
	CHECK(nargs==1, "need exactly 1 arg for spendsplat");
	CHECK(IS_ARR(args[0]), "need arr arg for spendsplat");
	ObjArr *a = AS_ARR(args[0]);
	return fn_spend(S, a->len, a->d);
}
static Val fn_ssub(State *S, int nargs, Val *args) {
	CHECK(nargs == 2, "need exactly 2 args for ssub?");
	CHECK(IS_STRING(args[0]) && IS_STRING(args[1]), "need 2 strings for ssub?");
	ObjString *needle = AS_STRING(args[0]);
	ObjString *haystack = AS_STRING(args[1]);
	int maxoff = haystack->len - needle->len;
	for (int i = 0; i <= maxoff; i++)
		if (0 == memcmp(needle->d, haystack->d + i, needle->len))
			return VAL_TRUE;
	return VAL_FALSE;
}


static Val fn_ssplit(State *S, int nargs, Val *args) {
	CHECK(nargs==2,"need exactly 2 args for ssplit");
	CHECK(IS_STRING(args[0]) && IS_STRING(args[1]), "need two strings for ssplit");
	ObjString *delim = AS_STRING(args[0]);
	ObjString *text = AS_STRING(args[1]);
	CHECK(delim->len == 1, "need length-1 delimiter");
	char delimc = delim->d[0];

	ObjArr *out = objarr_new(S);
	int start = 0;
	for (int i = 0; i <= text->len; i++) {
		if (text->d[i] == delimc || i == text->len) {
			ObjString *new = objstring_copy(S, &text->d[start], i-start);
			objarr_append(S, out, VAL_OBJ(new));
			start = i + 1;
		}
	}

	return VAL_OBJ(out);
}
static Val fn_sbytes(State *S, int nargs, Val *args) {
	CHECK(nargs==1, "need exactly 1 args for sbytes");
	CHECK(IS_STRING(args[0]), "need string arg for sbytes");
	ObjString *s = AS_STRING(args[0]);
	ObjArr *a = objarr_new(S);
	for (int i = 0; i < s->len; i++)
		objarr_append(S, a, VAL_OBJ(objstring_copy(S, &s->d[i], 1)));
	return VAL_OBJ(a);
}

// math
static Val fn_sin(State *S, int nargs, Val *args) {
	CHECK(nargs == 1, "need exactly 1 arg for sin");
	CHECK(IS_NUM(args[0]), "need num for sin");
	double x = AS_NUM(args[0]);
	return VAL_NUM(sin(x));
}
static Val fn_cos(State *S, int nargs, Val *args) {
	CHECK(nargs == 1, "need exactly 1 arg for cos");
	CHECK(IS_NUM(args[0]), "need num for cos");
	double x = AS_NUM(args[0]);
	return VAL_NUM(cos(x));
}
static Val fn_ceil(State *S, int nargs, Val *args) {
	CHECK(nargs == 1, "need exactly 1 arg for ceil");
	CHECK(IS_NUM(args[0]), "need num for ceil");
	double x = AS_NUM(args[0]);
	return VAL_NUM(ceil(x));
}
static Val fn_floor(State *S, int nargs, Val *args) {
	CHECK(nargs == 1, "need exactly 1 arg for floor");
	CHECK(IS_NUM(args[0]), "need num for floor");
	double x = AS_NUM(args[0]);
	return VAL_NUM(floor(x));
}
static Val fn_abs(State *S, int nargs, Val *args) {
	CHECK(nargs == 1, "need exactly 1 arg for abs");
	CHECK(IS_NUM(args[0]), "need num for abs");
	double x = AS_NUM(args[0]);
	return VAL_NUM(abs(x));
}


typedef struct {
	char *name;
	CFunc func;
} BuiltinFunc;
static BuiltinFunc builtin_funcs[] = {
	{ "clock", fn_clock },
	{ "say", fn_say },
	{ "write", fn_write },
	{ "writebytes", fn_writebytes },
	{ "readstring", fn_readstring },

	{ "arr", fn_arr },
	{ "append!", fn_append },
	{ "delete!", fn_delete },
	{ "#", fn_len },
	{ ",", fn_pend },

	{ "s,", fn_spend },
	{ "s,@", fn_spendsplat },
	{ "ssub?", fn_ssub },
	{ "ssplit", fn_ssplit },
	{ "sbytes", fn_sbytes },

	{ "sin", fn_sin },
	{ "cos", fn_cos },
	{ "ceil", fn_ceil },
	{ "floor", fn_floor },
	{ "abs", fn_abs },
	{ 0 },
};

void load_stdlib(State *S) {
	for (BuiltinFunc *b = builtin_funcs; b->name != NULL; b++) {
		ObjString *oname = objstring_copy_cstr(S, b->name);
		ht_put(S, &S->globals, oname, VAL_CFUNC(b->func));
	}
}