~swisschili/bluejay

ref: a7568dc427ab04f649fecea3e9425f1c18e586d0 bluejay/src/lisp/lisp.h -rw-r--r-- 4.9 KiB
a7568dc4swissChili Add unquote-splice (,@) 5 months ago
                                                                                
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
#pragma once

#include "error.h"
#include "istream.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdarg.h>

#define INT_MASK 0b11
#define INT_TAG 0b00

#define CHAR_MASK 0xff
#define CHAR_TAG 0b00001111

#define BOOL_MASK 0b1111111
#define BOOL_TAG 0b0011111

#define HEAP_MASK 0b111

#define CONS_TAG 0b001
#define CLASS_TAG 0b010
#define STRING_TAG 0b011
#define SYMBOL_TAG 0b101
#define CLOSURE_TAG 0b110

struct cons;

/// Represents a Lisp value
typedef unsigned int value_t;

struct cons
{
	value_t car, cdr;
	
	/// Line of the input file from where this was parsed, 0 if it was created
	/// in Lisp.
	int line;

	/// Description of where the cons was parsed from, or NULL if generated in
	/// code.
	char *name;
};

/**
 * Represents how many arguments a function takes.
 */
struct args
{
	/// The minimum valid number of arguments
	int num_required;

	/// The number of optional values
	int num_optional;

	/// Does this function accept variadic arguments? If `true`, any arguments
	/// after the required and optional arguments will be `cons`-ed to a list
	/// and passed as a final argument.
	bool variadic;

	/// The default values for the optional arguments, as expressions. These
	/// should be evaluated at the call site. They are known not to reference
	/// anything that could clash with scope at the call site.
	struct optional_argument
	{
		/// The default value of this argument
		value_t value;

		/// The name of this argument as a symbol
		value_t name;
	} optional_arguments[];
};

struct closure
{
	/// How many arguments does this closure take
	struct args *args;
	/// How many free variables does it capture (i.e. length of `data`)
	int num_captured;
	/// The function pointer itself
	void *function;

	/// This will be passed in edi.
	value_t data[];
};

/// Default pool (no pool)
#define NO_POOL 0

/**
 * The max used pool number, don't touch this.
 */
extern unsigned char max_pool;

/**
 * Current allocation pool, default 0 (no pool)
 */
extern unsigned char current_pool;

// It is integral that this be 16 bytes long so that whatever follows it is
// still aligned to 4 bits.
struct alloc
{
	/**
	 * One of the type tags, eg CONS_TAG, etc
	 */
	unsigned int type_tag;     //   4
	struct alloc *prev, *next; // + 8
	/**
	 * Zero if this is not part of a release pool, pool number otherwise.
	 */
	unsigned char pool;       // + 1
	/**
	 * Reserved for the GC.
	 */
	unsigned int mark : 24;   // + 2 = 16

	// Whatever else
};

extern struct alloc *first_a, *last_a;

struct cons_alloc
{
	struct alloc alloc;
	struct cons cons;
};

struct closure_alloc
{
	struct alloc alloc;
	struct closure closure;
};

/**
 * Create a new allocation pool.
 */
unsigned char make_pool();

/**
 * Set the allocation pull
 * @returns the old pool, you should reset this later with pop_pool.
 */
unsigned char push_pool(unsigned char pool);

/**
 * Set the allocation pool and throw away the old value.
 */
void pop_pool(unsigned char pool);

void add_to_pool(value_t form);

/**
 * @returns true if pool is still alive (in scope).
 */
bool pool_alive(unsigned char pool);

bool startswith(struct istream *s, char *pattern);

struct error readsym(struct istream *is, value_t *val) WARN_UNUSED;
struct error readstr(struct istream *is, value_t *val) WARN_UNUSED;
struct error readlist(struct istream *is, value_t *val) WARN_UNUSED;
struct error readint(struct istream *is, value_t *val) WARN_UNUSED;

/**
 * Read a quoted form, including `'` (quote) `\`` (backquote) and `,` (unquote)
 */
struct error readquote(struct istream *is, value_t *val) WARN_UNUSED;

value_t intval(int i);
value_t strval(char *str);
value_t symval(char *str);
value_t cons(value_t car, value_t cdr);
value_t merge2(value_t front, value_t back);
struct error read1(struct istream *is, value_t *val) WARN_UNUSED;
value_t read(struct istream *is);
value_t readn(struct istream *is);

value_t car(value_t v);
value_t cdr(value_t v);
/// Return a pointer to the "nil" tail of the list, or NULL if you do
/// something stupid.
value_t *nilptr(value_t val);
value_t *carref(value_t v);
value_t *cdrref(value_t v);
/// @returns the `index`-th `cdr`
value_t cxdr(value_t v, int index);
/// @returns a reference to the `index`-th `cdr`
value_t *cxdrref(value_t *v, int index);

value_t deep_copy(value_t val);

int cons_line(value_t val);
char *cons_file(value_t val);

bool integerp(value_t v);
bool symbolp(value_t v);
bool stringp(value_t v);
bool consp(value_t v);
bool listp(value_t v);
bool nilp(value_t v);
bool heapp(value_t v);
bool closurep(value_t v);
int length(value_t v);
value_t elt(value_t v, int index);

void printval(value_t v, int depth);

bool symstreq(value_t sym, char *str);

value_t create_closure(void *code, struct args *args, int ncaptures);

/**
 * Set the `index`th capture variable of `closure`. This should really only be
 * called when creating a new closure.
 */
void set_closure_capture_variable(int index, value_t value, value_t closure);

extern value_t nil;
extern value_t t;