Add licence
[ilari-esolangs.git] / context.c
blob69e3fe2846dc51804731813ccc1c74598f065ef6
1 #include "context.h"
2 #include "object.h"
3 #include "vat.h"
4 #include "message.h"
5 #include <stdio.h>
6 #include <stdlib.h>
8 /* Stack slot. */
9 struct stack
11 /* Object reference held. */
12 struct object* s_object;
13 /* Next stack slot. */
14 struct stack* s_next;
17 /* Context. */
18 struct context
20 /* Vat used. */
21 struct vat* c_vat;
22 /* Message being handled. */
23 struct message* c_message;
24 /* Stack top pointer. */
25 struct stack* c_stacktop;
26 /* Instruction pointer. */
27 size_t c_ip;
28 /* Number register value. */
29 size_t c_numreg;
30 /* Alternative mode flag. */
31 unsigned c_alt_flag;
32 /* Context lock. */
33 struct lock c_lock;
34 /* Locals. */
35 struct object* c_locals[];
38 /*****************************************************************************/
39 struct object* context_pop(struct context* ctx)
41 if(!ctx->c_stacktop)
42 return NULL;
44 struct stack* tmp = ctx->c_stacktop;
45 struct object* obj = tmp->s_object;
46 ctx->c_stacktop = tmp->s_next;
47 free(tmp);
48 return obj;
51 /*****************************************************************************/
52 void context_push(struct context* ctx, struct object* obj)
54 struct stack* newslot = malloc(sizeof(struct stack));
55 if(!newslot) {
56 fprintf(stderr, "Out of memory!\n");
57 exit(1);
59 newslot->s_next = ctx->c_stacktop;
60 newslot->s_object = obj;
61 ctx->c_stacktop = newslot;
64 /*****************************************************************************/
65 unsigned context_prepare(struct context* ctx)
67 /* Grab message queue lock and context lock. */
68 vat_grab_queue_lock(ctx->c_vat);
69 mutex_lock(&ctx->c_lock);
71 ctx->c_message = vat_deque_message(ctx->c_vat);
72 if(!ctx->c_message)
73 return 0;
75 /* Mark object as being executed. */
76 object_set_executing(message_target(ctx->c_message));
78 /* Set fields. */
79 ctx->c_stacktop = NULL;
80 ctx->c_ip = 0;
81 ctx->c_numreg = 0;
82 ctx->c_alt_flag = 0;
83 for(size_t i = 0; i < vat_maxlocals(ctx->c_vat); i++)
84 ctx->c_locals[i] = NULL;
86 mutex_unlock(&ctx->c_lock);
87 vat_ungrab_queue_lock(ctx->c_vat);
88 return 1;
91 /*****************************************************************************/
92 void context_unprepare(struct context* ctx)
94 /* Grab message queue lock and context lock. */
95 vat_grab_queue_lock(ctx->c_vat);
96 mutex_lock(&ctx->c_lock);
98 object_clear_executing(message_target(ctx->c_message));
100 /* Kill the message. It is now handled. */
101 free(ctx->c_message);
103 /* Kill all the locals. */
104 for(size_t i = 0; i < vat_maxlocals(ctx->c_vat); i++)
105 ctx->c_locals[i] = NULL;
106 /* Kill stack. */
107 while(ctx->c_stacktop)
108 context_pop(ctx);
110 mutex_unlock(&ctx->c_lock);
111 vat_ungrab_queue_lock(ctx->c_vat);
114 /*****************************************************************************/
115 size_t context_stacksize(struct context* ctx)
117 size_t size = 0;
118 struct stack* s = ctx->c_stacktop;
119 while(s) {
120 s = s->s_next;
121 size++;
123 return size;
127 /*****************************************************************************/
128 void context_singlestep(struct context* ctx)
130 struct message* msg = ctx->c_message;
131 struct object* t = message_target(msg);
132 struct class* tc = object_class(t);
133 struct object* tmp1;
134 struct object* tmp2;
135 struct message* tmp4;
137 /* Grab context lock. */
138 mutex_lock(&ctx->c_lock);
140 if(ctx->c_alt_flag) {
141 switch(class_get_ins(tc, ctx->c_ip)) {
142 case 'f':
143 case 'F':
144 case 'l':
145 case 'L':
146 case 'p':
147 case 'P':
148 case 's':
149 case 'S':
150 case 'N':
151 /* Just clear the alternative mode. */
152 ctx->c_alt_flag = 0;
153 ctx->c_ip++;
154 mutex_unlock(&ctx->c_lock);
155 return;
159 switch(class_get_ins(tc, ctx->c_ip)) {
160 case '+':
161 ctx->c_numreg++;
162 break;
163 case '-':
164 ctx->c_numreg--;
165 break;
166 case 'E':
167 tmp1 = context_pop(ctx);
168 tmp2 = context_pop(ctx);
169 if(tmp1 != tmp2)
170 ctx->c_alt_flag = 1;
171 break;
172 case 'f':
173 object_write_field(t, ctx->c_numreg, context_pop(ctx));
174 break;
175 case 'F':
176 context_push(ctx, object_read_field(t, ctx->c_numreg));
177 break;
178 case 'l':
179 tmp1 = context_pop(ctx);
180 if(ctx->c_numreg < class_local_count(tc))
181 ctx->c_locals[ctx->c_numreg] = tmp1;
182 break;
183 case 'L':
184 if(ctx->c_numreg < class_local_count(tc))
185 tmp1 = ctx->c_locals[ctx->c_numreg];
186 else
187 tmp1 = NULL;
188 context_push(ctx, tmp1);
189 break;
190 case 'p':
191 message_write_slot(msg, ctx->c_numreg, context_pop(ctx));
192 break;
193 case 'P':
194 context_push(ctx, message_read_slot(msg, ctx->c_numreg));
195 break;
196 case 's':
197 tmp1 = context_pop(ctx);
198 if(!tmp1)
199 break;
201 /* Allocate it. */
202 tmp4 = message_create(tmp1, context_stacksize(ctx));
203 for(size_t i = 0; i < message_parameters(tmp4); i++)
204 message_write_slot(tmp4, i, context_pop(ctx));
205 vat_queue_message(ctx->c_vat, tmp4);
206 break;
207 case 'S':
208 context_push(ctx, t);
209 break;
210 case 'N':
211 tmp1 = object_create_ordinary(class_search(ctx->c_numreg));
212 vat_add_object(ctx->c_vat, tmp1);
213 context_push(ctx, tmp1);
214 break;
215 default:
216 /* Can't happen! */
219 ctx->c_ip++;
220 mutex_unlock(&ctx->c_lock);
223 /*****************************************************************************/
224 struct context* context_create(struct vat* vat)
226 struct context* ctx = malloc(sizeof(struct context) +
227 vat_maxlocals(vat) * sizeof(struct object*));
228 if(!ctx) {
229 fprintf(stderr, "Out of memory!\n");
230 exit(1);
233 ctx->c_vat = vat;
234 ctx->c_stacktop = NULL;
235 ctx->c_ip = 0;
236 ctx->c_numreg = 0;
237 ctx->c_alt_flag = 0;
238 for(size_t i = 0; i < vat_maxlocals(vat); i++)
239 ctx->c_locals[i] = NULL;
240 return ctx;
243 /*****************************************************************************/
244 void context_lock(struct context* ctx)
246 mutex_lock(&ctx->c_lock);
249 /*****************************************************************************/
250 void context_unlock(struct context* ctx)
252 mutex_unlock(&ctx->c_lock);
255 /*****************************************************************************/
256 void context_queue_message(struct context* context, struct message* message)
258 vat_queue_message(context->c_vat, message);
261 /*****************************************************************************/
262 unsigned context_execute_msghandler(struct context* ctx)
264 if(!context_prepare(ctx))
265 return 0;
267 struct message* m = ctx->c_message;
268 struct object* t = message_target(m);
269 struct class* tc = object_class(t);
271 if(object_exec_special(t, ctx, m)) {
272 context_unprepare(ctx);
273 return 1;
274 } else if(!tc) {
275 /* Should not happen... */
276 context_unprepare(ctx);
277 return 1;
280 while(ctx->c_ip < class_ins_count(tc)) {
281 context_singlestep(ctx);
284 context_unprepare(ctx);
285 return 1;