Skip to content

Latest commit

 

History

History
1395 lines (1139 loc) · 36.6 KB

toby_app.c

File metadata and controls

1395 lines (1139 loc) · 36.6 KB
 
Feb 8, 2007
Feb 8, 2007
1
2
3
4
5
6
7
8
/*
* Toby -- A programming language for learning.
* Copyright (C) 2007 Ryan C. Gordon.
*
* Please refer to LICENSE.txt in the root directory of the source
* distribution for licensing details.
*/
9
10
11
12
13
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>
Feb 26, 2007
Feb 26, 2007
14
#include <ctype.h> /* !!! FIXME: lose this with tolower/toupper... */
15
16
#include "toby_app.h"
Feb 26, 2007
Feb 26, 2007
17
18
19
20
21
22
23
24
25
26
typedef enum TobyExecState
{
EXEC_STOPPED=0,
EXEC_STOPPING,
EXEC_RUNNING,
EXEC_STEPPING,
EXEC_PAUSED,
} TobyExecState;
Jan 23, 2007
Jan 23, 2007
27
/* TurtlesSpace state... */
Feb 6, 2007
Feb 6, 2007
28
29
static int currentTurtleIndex = -1;
static int totalTurtles = 0;
Feb 11, 2007
Feb 11, 2007
30
static Turtle *turtles = NULL;
Jan 23, 2007
Jan 23, 2007
31
static int fenceEnabled = 1;
Jan 24, 2007
Jan 24, 2007
32
static int halted = 0;
Feb 6, 2007
Feb 6, 2007
33
static TurtleRGB background = { 0, 0, 0 };
Feb 28, 2007
Feb 28, 2007
34
static TobyDebugInfo *callstack = NULL;
Feb 18, 2007
Feb 18, 2007
35
static int callstackCount = 0;
Feb 28, 2007
Feb 28, 2007
36
37
static TobyDebugInfo *varList = NULL;
static int varCount = 0;
Feb 18, 2007
Feb 18, 2007
38
static lua_State *luaState = NULL;
Feb 26, 2007
Feb 26, 2007
39
40
41
42
43
static int turtleSpaceIsDirty = 0;
static int executingLine = 0;
static TobyExecState execState = EXEC_STOPPED;
static long delayPerLine = 0;
static long nextPumpTicks = 0;
Feb 18, 2007
Feb 18, 2007
44
Jan 23, 2007
Jan 23, 2007
45
Jan 30, 2007
Jan 30, 2007
46
47
48
49
50
51
52
53
void TOBY_background(int *r, int *g, int *b)
{
*r = background.r;
*g = background.g;
*b = background.b;
} /* TOBY_background */
Feb 8, 2007
Feb 8, 2007
54
55
56
57
58
59
60
61
62
63
64
65
66
67
static inline void throwError(lua_State *L, const char *err)
{
lua_pushstring(L, err);
lua_error(L);
} /* throwError */
static inline void haltProgram(lua_State *L)
{
halted = 1;
throwError(L, "program halted");
} /* haltProgram */
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/*
* All this math code had brilliant comments explaining it, but as proud as I
* was to figure it out in high school...really, it's fundamental
* mathematical wankery. Check the repository or Google it.
*/
static inline lua_Number degreesToRadians(lua_Number degrees)
{
/* !!! FIXME: fixed point... */
return(degrees * (M_PI / 180.0));
} /* degreesToRadians */
static inline lua_Number radiansToDegrees(lua_Number radians)
{
/* !!! FIXME: fixed point... */
return(radians * (180.0 / M_PI));
} /* degreesToRadians */
Jan 25, 2007
Jan 25, 2007
87
88
89
/* This can be optimized into one FPU operation on x86 chips. */
static inline void sinAndCos(lua_Number x, lua_Number *sval, lua_Number *cval)
{
Feb 26, 2007
Feb 26, 2007
90
91
/* !!! FIXME: x86 version */
/* !!! FIXME: fixed point? */
Jan 25, 2007
Jan 25, 2007
92
93
94
95
96
*sval = sin(x);
*cval = cos(x);
} /* sinAndCos */
97
98
99
100
static inline void calculateLine(lua_Number heading, lua_Number distance,
lua_Number startX, lua_Number startY,
lua_Number *endX, lua_Number *endY)
{
Feb 11, 2007
Feb 11, 2007
101
const lua_Number rad = degreesToRadians(heading);
Jan 25, 2007
Jan 25, 2007
102
lua_Number sinrad, cosrad;
Feb 11, 2007
Feb 11, 2007
103
104
/* !!! FIXME: fixed point... */
Jan 25, 2007
Jan 25, 2007
105
106
107
sinAndCos(rad, &sinrad, &cosrad);
*endY = (sinrad * distance) + startY;
*endX = (cosrad * distance) + startX;
108
109
110
} /* calculateLine */
Jan 25, 2007
Jan 25, 2007
111
#if 0 /* not used, yet. */
112
113
114
115
116
static inline lua_Number pythagorian(lua_Number s1, lua_Number hypotenuse)
{
/* !!! FIXME: fixed point... */
return(sqrt((hypotenuse * hypotenuse) - (s1 * s1)));
} /* pythagorian */
Jan 25, 2007
Jan 25, 2007
117
#endif
118
119
120
121
122
123
124
125
126
127
/* convert a lua_Number between 0.0 and 1.0 to 0 to 255. */
static inline int to8bit(lua_Number x)
{
/* !!! FIXME: fixed point... */
return (int) (x * N(255));
} /* to8bit */
Jan 23, 2007
Jan 23, 2007
128
129
130
131
132
static inline int secsToMs(lua_Number secs)
{
/* !!! FIXME: fixed point... */
return (int) (secs * N(1000));
} /* secsToMs */
Feb 10, 2007
Feb 10, 2007
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
/* Liang-Barsky line clipping algorithm implementation. */
static int clip(lua_Number *minimum, lua_Number *maximum,
lua_Number directedProjection, lua_Number directedDistance)
{
if (directedProjection == N(0))
{
if (directedDistance < N(0))
return 0;
} /* if */
else
{
const lua_Number amount = directedDistance / directedProjection;
if (directedProjection < N(0)) {
if (amount > *maximum)
return 0;
else if (amount > *minimum)
*minimum = amount;
} /* if */
else
{
if (amount < *minimum)
return 0;
else if (amount < *maximum)
*maximum = amount;
} /* else */
} /* else */
return 1;
} /* clip */
int TOBY_clipLine(lua_Number *_x1, lua_Number *_y1,
lua_Number *_x2, lua_Number *_y2,
lua_Number w, lua_Number h)
{
const lua_Number x1 = *_x1;
const lua_Number y1 = *_y1;
const lua_Number x2 = *_x2;
const lua_Number y2 = *_y2;
const lua_Number px = x2 - x1;
const lua_Number py = y2 - y1;
lua_Number minimum = N(0);
lua_Number maximum = N(1);
if (clip(&minimum, &maximum, -px, x1 - N(0)))
{
if (clip(&minimum, &maximum, px, w - x1))
{
if (clip(&minimum, &maximum, -py, y1 - N(0)))
{
if (clip(&minimum, &maximum, py, h - y1))
{
if (maximum < N(1))
{
*_x2 = x1 + maximum * px;
*_y2 = y1 + maximum * py;
} /* if */
if (minimum > N(0))
{
*_x1 += minimum * px;
*_y1 += minimum * py;
} /* if */
return 1;
} /* if */
} /* if */
} /* if */
} /* if */
return 0;
} /* TOBY_clipLine */
207
208
209
210
static inline int checkWholeNum(lua_State *L, int idx)
{
const lua_Number num = luaL_checknumber(L, idx);
const int intnum = (int) num;
Feb 8, 2007
Feb 8, 2007
211
212
if ( ((lua_Number) intnum) != num )
throwError(L, "Expected whole number");
213
214
215
216
217
return intnum;
} /* checkWholeNum */
Feb 8, 2007
Feb 8, 2007
218
static int allocateTurtle(lua_State *L)
Feb 11, 2007
Feb 11, 2007
220
221
222
Turtle *ptr;
ptr = (Turtle *) realloc(turtles, sizeof (Turtle) * (totalTurtles + 1));
Feb 6, 2007
Feb 6, 2007
223
if (ptr == NULL)
Feb 8, 2007
Feb 8, 2007
224
throwError(L, "Out of memory");
Feb 6, 2007
Feb 6, 2007
225
226
227
turtles = ptr;
ptr = &turtles[totalTurtles];
Feb 11, 2007
Feb 11, 2007
228
229
230
231
memset(ptr, '\0', sizeof (Turtle));
ptr->pos.x = ptr->pos.y = N(500); /* center of turtlespace. */
ptr->width = ptr->height = N(20);
Mar 18, 2008
Mar 18, 2008
232
ptr->pen.r = ptr->pen.g = ptr->pen.b = 255; /* white. */
Feb 11, 2007
Feb 11, 2007
233
234
235
236
ptr->angle = 270; /* due north. */
ptr->penDown = 1;
ptr->recalcPoints = 1;
ptr->visible = 1;
Feb 6, 2007
Feb 6, 2007
237
238
239
return totalTurtles++;
} /* allocateTurtle */
Feb 8, 2007
Feb 8, 2007
242
static inline Turtle *getTurtle(lua_State *L)
Feb 6, 2007
Feb 6, 2007
244
if (currentTurtleIndex < 0)
Feb 8, 2007
Feb 8, 2007
245
throwError(L, "No current turtle");
Feb 11, 2007
Feb 11, 2007
246
return &turtles[currentTurtleIndex];
247
248
249
} /* getTurtle */
Feb 6, 2007
Feb 6, 2007
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
/*
* See comments in Turtle::calcTriangle() for detailed discussion:
* http://svn.icculus.org/toby/branches/toby_rewrite_4/src/turtlespace/Turtle.cpp?view=markup
*/
static inline void calculateTurtleTriangle(Turtle *turtle)
{
if (turtle->recalcPoints)
{
const lua_Number w = turtle->width;
const lua_Number h = turtle->height;
const lua_Number angle = turtle->angle;
const lua_Number halfW = w / N(2);
TurtlePoint *pt = turtle->points;
lua_Number tailX, tailY;
calculateLine(angle + N(180), h / N(2), N(0), N(0), &tailX, &tailY);
calculateLine(angle, h, tailX, tailY, &pt[0].x, &pt[0].y);
calculateLine(angle + N(90), halfW, tailX, tailY, &pt[1].x, &pt[1].y);
calculateLine(angle - N(90), halfW, tailX, tailY, &pt[2].x, &pt[2].y);
pt[3].x = tailX;
pt[3].y = tailY;
turtle->recalcPoints = 0;
} /* if */
} /* calculateTurtleTriangle */
Feb 11, 2007
Feb 11, 2007
277
void TOBY_renderAllTurtles(void *udata)
Feb 6, 2007
Feb 6, 2007
278
279
{
int i;
Feb 26, 2007
Feb 26, 2007
280
int drewAtLeastOne = 0;
Feb 6, 2007
Feb 6, 2007
281
282
for (i = 0; i < totalTurtles; i++)
{
Feb 11, 2007
Feb 11, 2007
283
284
285
Turtle *turtle = &turtles[i];
calculateTurtleTriangle(turtle);
if (turtle->visible)
Feb 26, 2007
Feb 26, 2007
286
{
Feb 11, 2007
Feb 11, 2007
287
TOBY_drawTurtle(turtle, udata);
Feb 26, 2007
Feb 26, 2007
288
289
drewAtLeastOne = 1;
} /* if */
Feb 6, 2007
Feb 6, 2007
290
} /* for */
Feb 26, 2007
Feb 26, 2007
291
292
293
if ((drewAtLeastOne) && (udata == NULL))
turtleSpaceIsDirty = 1; /* put to backing store, must repaint... */
Feb 6, 2007
Feb 6, 2007
294
295
296
} /* TOBY_renderAllTurtles */
Feb 26, 2007
Feb 26, 2007
297
298
299
300
301
302
303
304
305
306
static inline void putToScreen(void)
{
if (turtleSpaceIsDirty)
{
TOBY_putToScreen();
turtleSpaceIsDirty = 0;
} /* if */
} /* putToScreen */
Feb 8, 2007
Feb 8, 2007
307
static void setTurtleAngle(lua_State *L, lua_Number angle)
Feb 8, 2007
Feb 8, 2007
309
Turtle *turtle = getTurtle(L);
Jan 23, 2007
Jan 23, 2007
310
311
if (angle != turtle->angle)
{
Feb 26, 2007
Feb 26, 2007
312
/* !!! FIXME: ugh, use modulus... */
Feb 8, 2007
Feb 8, 2007
313
while (angle >= N(360)) angle -= N(360);
Jan 23, 2007
Jan 23, 2007
314
315
while (angle < N(0)) angle += N(360);
turtle->angle = angle;
Feb 11, 2007
Feb 11, 2007
316
turtle->recalcPoints = 1;
Feb 27, 2007
Feb 27, 2007
317
318
if (turtle->visible)
turtleSpaceIsDirty = 1;
Jan 23, 2007
Jan 23, 2007
319
320
321
322
323
324
} /* if */
} /* setTurtleAngle */
static int luahook_setangle(lua_State *L)
{
Feb 8, 2007
Feb 8, 2007
325
setTurtleAngle(L, luaL_checknumber(L, 1));
Jan 23, 2007
Jan 23, 2007
326
327
328
329
return 0;
} /* luahook_setangle */
Feb 8, 2007
Feb 8, 2007
330
static inline void turnTurtle(lua_State *L, lua_Number degree)
Jan 23, 2007
Jan 23, 2007
331
{
Feb 8, 2007
Feb 8, 2007
332
Turtle *turtle = getTurtle(L);
Jan 23, 2007
Jan 23, 2007
333
if (degree != N(0))
Feb 8, 2007
Feb 8, 2007
334
setTurtleAngle(L, turtle->angle + degree);
Jan 23, 2007
Jan 23, 2007
335
336
337
338
339
} /* turnTurtle */
static int luahook_turnright(lua_State *L)
{
Feb 8, 2007
Feb 8, 2007
340
turnTurtle(L, luaL_checknumber(L, 1));
Jan 23, 2007
Jan 23, 2007
341
342
343
344
345
346
return 0;
} /* luahook_turnright */
static int luahook_turnleft(lua_State *L)
{
Feb 8, 2007
Feb 8, 2007
347
turnTurtle(L, -luaL_checknumber(L, 1));
Jan 23, 2007
Jan 23, 2007
348
349
350
351
return 0;
} /* luahook_turnleft */
Feb 8, 2007
Feb 8, 2007
352
static inline void testFence(lua_State *L, const Turtle *turtle)
Jan 23, 2007
Jan 23, 2007
353
{
Feb 8, 2007
Feb 8, 2007
354
355
356
357
358
359
360
361
362
363
const lua_Number x = turtle->pos.x;
const lua_Number y = turtle->pos.y;
if ( (x < N(0)) || (x > N(1000)) || (y < N(0)) || (y > N(1000)) )
throwError(L, "Turtle outside fence");
} /* testFence */
static void setTurtleXY(lua_State *L, lua_Number x, lua_Number y)
{
Turtle *turtle = getTurtle(L);
Feb 6, 2007
Feb 6, 2007
364
365
turtle->pos.x = x;
turtle->pos.y = y;
Jan 23, 2007
Jan 23, 2007
366
Feb 8, 2007
Feb 8, 2007
368
testFence(L, turtle);
Jan 23, 2007
Jan 23, 2007
369
370
371
372
373
374
375
} /* setTurtleXY */
static int luahook_setturtlexy(lua_State *L)
{
const lua_Number x = luaL_checknumber(L, 1);
const lua_Number y = luaL_checknumber(L, 2);
Feb 8, 2007
Feb 8, 2007
376
setTurtleXY(L, x, y);
Jan 23, 2007
Jan 23, 2007
377
378
379
380
381
382
return 0;
} /* luahook_setturtlexy */
static int luahook_hometurtle(lua_State *L)
{
Feb 8, 2007
Feb 8, 2007
383
setTurtleXY(L, N(500), N(500));
Jan 23, 2007
Jan 23, 2007
384
385
return 0;
} /* luahook_hometurtle */
Feb 8, 2007
Feb 8, 2007
388
static void driveTurtle(lua_State *L, lua_Number distance)
Feb 8, 2007
Feb 8, 2007
390
Turtle *turtle = getTurtle(L);
391
392
if (distance != N(0))
{
Feb 6, 2007
Feb 6, 2007
393
394
lua_Number x1 = turtle->pos.x;
lua_Number y1 = turtle->pos.y;
Feb 10, 2007
Feb 10, 2007
395
lua_Number unclipped_x2, unclipped_y2;
Jan 25, 2007
Jan 25, 2007
396
397
398
lua_Number x2, y2;
calculateLine(turtle->angle, distance, x1, y1, &x2, &y2);
Feb 10, 2007
Feb 10, 2007
399
400
unclipped_x2 = x2;
unclipped_y2 = y2;
401
402
if (turtle->penDown) /* draw the line covering path turtle took? */
{
Jan 25, 2007
Jan 25, 2007
403
/* only draw if SOMETHING is inside TurtleSpace... */
Feb 10, 2007
Feb 10, 2007
404
if (TOBY_clipLine(&x1, &y1, &x2, &y2, N(999), N(999)))
Jan 25, 2007
Jan 25, 2007
405
{
Feb 6, 2007
Feb 6, 2007
406
407
const TurtleRGB *pen = &turtle->pen;
TOBY_drawLine(x1, y1, x2, y2, pen->r, pen->g, pen->b);
Feb 26, 2007
Feb 26, 2007
408
turtleSpaceIsDirty = 1;
Jan 25, 2007
Jan 25, 2007
409
} /* if */
Jan 25, 2007
Jan 25, 2007
411
Feb 10, 2007
Feb 10, 2007
412
setTurtleXY(L, unclipped_x2, unclipped_y2);
413
414
415
416
417
418
} /* if */
} /* driveTurtle */
static int luahook_goforward(lua_State *L)
{
Feb 8, 2007
Feb 8, 2007
419
driveTurtle(L, luaL_checknumber(L, 1));
420
421
422
423
424
425
return 0;
} /* luahook_goforward */
static int luahook_gobackward(lua_State *L)
{
Feb 8, 2007
Feb 8, 2007
426
driveTurtle(L, -luaL_checknumber(L, 1));
427
428
429
430
return 0;
} /* luahook_gobackward */
Jan 23, 2007
Jan 23, 2007
431
static int luahook_getturtlex(lua_State *L)
Feb 8, 2007
Feb 8, 2007
433
lua_pushnumber(L, getTurtle(L)->pos.x);
Jan 23, 2007
Jan 23, 2007
434
435
return 1;
} /* luahook_getturtlex */
Jan 23, 2007
Jan 23, 2007
438
439
static int luahook_getturtley(lua_State *L)
{
Feb 8, 2007
Feb 8, 2007
440
lua_pushnumber(L, getTurtle(L)->pos.y);
Jan 23, 2007
Jan 23, 2007
441
442
return 1;
} /* luahook_getturtley */
Jan 23, 2007
Jan 23, 2007
445
static int luahook_getturtlespacewidth(lua_State *L)
Feb 26, 2007
Feb 26, 2007
447
lua_pushnumber(L, N(1000)); /* !!! FIXME: allow this to change? */
Jan 23, 2007
Jan 23, 2007
448
449
return 1;
} /* luahook_getturtlespacewidth */
Jan 23, 2007
Jan 23, 2007
452
static int luahook_getturtlespaceheight(lua_State *L)
Feb 26, 2007
Feb 26, 2007
454
lua_pushnumber(L, N(1000)); /* !!! FIXME: allow this to change? */
Jan 23, 2007
Jan 23, 2007
455
456
457
458
459
460
return 1;
} /* luahook_getturtlespaceheight */
static int luahook_setpenup(lua_State *L)
{
Feb 8, 2007
Feb 8, 2007
461
getTurtle(L)->penDown = 0;
Jan 23, 2007
Jan 23, 2007
463
} /* luahook_setpenup */
Jan 23, 2007
Jan 23, 2007
466
static int luahook_setpendown(lua_State *L)
Feb 8, 2007
Feb 8, 2007
468
getTurtle(L)->penDown = 1;
Jan 23, 2007
Jan 23, 2007
470
} /* luahook_setpendown */
Feb 8, 2007
Feb 8, 2007
473
static inline void setPenColorRGB(lua_State *L, int r, int g, int b)
Feb 8, 2007
Feb 8, 2007
475
TurtleRGB *pen = &(getTurtle(L)->pen);
Feb 6, 2007
Feb 6, 2007
476
477
478
pen->r = r;
pen->g = g;
pen->b = b;
479
480
481
482
483
484
485
486
487
488
} /* setPenColorRGB */
static int luahook_setpencolorrgb(lua_State *L)
{
const lua_Number r = luaL_checknumber(L, 1);
const lua_Number g = luaL_checknumber(L, 2);
const lua_Number b = luaL_checknumber(L, 3);
if ( (r < N(0)) || (r > N(1)) )
Feb 8, 2007
Feb 8, 2007
489
throwError(L, "Red value is not between 0.0 and 1.0");
490
else if ( (g < N(0)) || (g > N(1)) )
Feb 8, 2007
Feb 8, 2007
491
throwError(L, "Green value is not between 0.0 and 1.0");
492
else if ( (b < N(0)) || (b > N(1)) )
Feb 8, 2007
Feb 8, 2007
493
throwError(L, "Blue value is not between 0.0 and 1.0");
Feb 8, 2007
Feb 8, 2007
495
setPenColorRGB(L, to8bit(r), to8bit(g), to8bit(b));
496
497
498
499
500
501
502
503
504
505
506
507
508
509
return 0;
} /* luahook_setpencolorrgb */
static int luahook_setpencolor(lua_State *L)
{
/*
* How I got these numbers:
* These color choices are ripped directly from QuickBasic's
* COLOR command in text mode. So, (1) is dark blue, (2) is
* dark green, etc...Then I used the GIMP color tool
* (http://www.gimp.org/), to find the equivalents in RGB format.
*/
Feb 6, 2007
Feb 6, 2007
510
static const TurtleRGB colors[] =
Feb 26, 2007
Feb 26, 2007
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
{ 0, 0, 0 }, /* black */
{ 0, 26, 196 }, /* dark blue */
{ 0, 153, 45 }, /* dark green */
{ 0, 144, 138 }, /* dark cyan */
{ 160, 0, 0 }, /* dark red */
{ 197, 0, 202 }, /* dark magenta */
{ 129, 90, 16 }, /* brown */
{ 200, 200, 200 }, /* gray */
{ 90, 90, 90 }, /* dark gray */
{ 0, 200, 255 }, /* bright blue */
{ 0, 90, 38 }, /* bright green */
{ 91, 110, 255 }, /* bright cyan */
{ 255, 0, 0 }, /* bright red */
{ 255, 0, 255 }, /* bright pink */
{ 255, 255, 0 }, /* bright yellow */
{ 255, 255, 255 }, /* bright white */
528
529
530
531
};
const int color = checkWholeNum(L, 1);
if ( (color < 0) || (color >= (STATICARRAYLEN(colors))) )
Feb 8, 2007
Feb 8, 2007
532
throwError(L, "Color value is not between 0 and 15");
Feb 8, 2007
Feb 8, 2007
534
setPenColorRGB(L, colors[color].r, colors[color].g, colors[color].b);
535
536
537
538
return 0;
} /* luahook_setpencolor */
Jan 23, 2007
Jan 23, 2007
539
540
static int luahook_showturtle(lua_State *L)
{
Feb 8, 2007
Feb 8, 2007
541
Turtle *turtle = getTurtle(L);
Feb 27, 2007
Feb 27, 2007
542
543
544
545
546
if (!turtle->visible)
{
turtle->visible = 1;
turtleSpaceIsDirty = 1;
} /* if */
Jan 23, 2007
Jan 23, 2007
547
548
549
550
551
552
return 0;
} /* luahook_showturtle */
static int luahook_hideturtle(lua_State *L)
{
Feb 8, 2007
Feb 8, 2007
553
Turtle *turtle = getTurtle(L);
Feb 27, 2007
Feb 27, 2007
554
555
556
557
558
if (turtle->visible)
{
turtle->visible = 0;
turtleSpaceIsDirty = 1;
} /* if */
Jan 23, 2007
Jan 23, 2007
559
560
561
562
563
564
return 0;
} /* luahook_hideturtle */
static int luahook_enablefence(lua_State *L)
{
Feb 8, 2007
Feb 8, 2007
565
566
int i;
Jan 23, 2007
Jan 23, 2007
567
fenceEnabled = 1;
Feb 8, 2007
Feb 8, 2007
568
569
for (i = 0; i < totalTurtles; i++)
Feb 11, 2007
Feb 11, 2007
570
testFence(L, &turtles[i]);
Feb 8, 2007
Feb 8, 2007
571
Jan 23, 2007
Jan 23, 2007
572
573
574
575
576
577
578
579
580
581
582
583
584
return 0;
} /* luahook_enablefence */
static int luahook_disablefence(lua_State *L)
{
fenceEnabled = 0;
return 0;
} /* luahook_disablefence */
static int luahook_cleanupturtlespace(lua_State *L)
{
Feb 26, 2007
Feb 26, 2007
585
/* !!! FIXME: let user choose color? */
Jan 28, 2007
Jan 28, 2007
586
TOBY_cleanup(background.r, background.g, background.b);
Feb 26, 2007
Feb 26, 2007
587
turtleSpaceIsDirty = 1;
Jan 23, 2007
Jan 23, 2007
588
589
590
591
return 0;
} /* luahook_getturtlespaceheight */
Feb 26, 2007
Feb 26, 2007
592
/* !!! FIXME: all must handle utf8.... */
Feb 8, 2007
Feb 8, 2007
593
Jan 23, 2007
Jan 23, 2007
594
595
static int luahook_stringlength(lua_State *L)
{
Feb 26, 2007
Feb 26, 2007
596
/* !!! FIXME: this is doing bytes, not chars... */
Jan 23, 2007
Jan 23, 2007
597
598
599
600
601
lua_pushinteger(L, (lua_Integer) strlen(luaL_checklstring(L, 1, NULL)));
return 1;
} /* luahook_stringlength */
Feb 8, 2007
Feb 8, 2007
602
603
604
605
606
607
608
static int luahook_leftstring(lua_State *L)
{
const char *str = luaL_checklstring(L, 1, NULL);
const size_t origLen = strlen(str);
int charCount = checkWholeNum(L, 2);
if (charCount < 0)
throwError(L, "Negative string length");
Mar 18, 2008
Mar 18, 2008
609
else if ( ((size_t) charCount) > origLen )
Feb 8, 2007
Feb 8, 2007
610
611
charCount = origLen;
Feb 26, 2007
Feb 26, 2007
612
lua_pushlstring(L, str, charCount);
Feb 8, 2007
Feb 8, 2007
613
614
615
616
617
618
619
620
621
622
623
return 1;
} /* luahook_leftstring */
static int luahook_rightstring(lua_State *L)
{
const char *str = luaL_checklstring(L, 1, NULL);
const size_t origLen = strlen(str);
int charCount = checkWholeNum(L, 2);
if (charCount < 0)
throwError(L, "Negative string length");
Mar 18, 2008
Mar 18, 2008
624
else if ( ((size_t) charCount) > origLen)
Feb 8, 2007
Feb 8, 2007
625
626
627
628
629
630
631
632
633
charCount = origLen;
lua_pushstring(L, str + (origLen - charCount));
return 1;
} /* luahook_rightstring */
static int luahook_joinstrings(lua_State *L)
{
Feb 26, 2007
Feb 26, 2007
634
/* !!! FIXME: this code sucks. */
Feb 8, 2007
Feb 8, 2007
635
636
637
638
639
640
const char *str1 = luaL_checklstring(L, 1, NULL);
const char *str2 = luaL_checklstring(L, 2, NULL);
char *buf = (char *) malloc(strlen(str1) + strlen(str2) + 1);
if (buf == NULL)
throwError(L, "Out of memory");
strcpy(buf, str1);
Feb 26, 2007
Feb 26, 2007
641
strcat(buf, str2);
Feb 8, 2007
Feb 8, 2007
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
lua_pushstring(L, buf);
free(buf);
return 1;
} /* luahook_joinstrings */
static int luahook_substring(lua_State *L)
{
const char *str = luaL_checklstring(L, 1, NULL);
size_t origLen = strlen(str);
const int pos = checkWholeNum(L, 2);
int charCount = checkWholeNum(L, 3);
if (charCount < 0)
throwError(L, "Negative string length");
if (pos < 0)
Feb 26, 2007
Feb 26, 2007
659
throwError(L, "Negative string position"); /* !!! FIXME: just clamp instead? */
Feb 8, 2007
Feb 8, 2007
660
661
662
663
664
665
origLen -= pos;
if (origLen <= 0)
lua_pushstring(L, "");
else
{
Mar 18, 2008
Mar 18, 2008
666
667
if ( ((size_t) charCount) > origLen)
charCount = (int) origLen;
Feb 26, 2007
Feb 26, 2007
668
lua_pushlstring(L, str+pos, charCount);
Feb 8, 2007
Feb 8, 2007
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
} /* else */
return 1;
} /* luahook_substring */
static int luahook_uppercasestring(lua_State *L)
{
const char *str = luaL_checklstring(L, 1, NULL);
char *buf = (char *) alloca(strlen(str) + 1);
while (*str)
*(buf++) = toupper(*(str++));
*buf = '\0';
lua_pushstring(L, buf);
return 1;
} /* luahook_uppercasestring */
static int luahook_lowercasestring(lua_State *L)
{
const char *str = luaL_checklstring(L, 1, NULL);
char *buf = (char *) alloca(strlen(str) + 1);
while (*str)
*(buf++) = tolower(*(str++));
*buf = '\0';
lua_pushstring(L, buf);
return 1;
} /* luahook_lowercasestring */
Jan 23, 2007
Jan 23, 2007
699
700
static int luahook_drawstring(lua_State *L)
{
Feb 8, 2007
Feb 8, 2007
701
702
const Turtle *turtle = getTurtle(L);
const char *utf8str = luaL_checklstring(L, 1, NULL);
Feb 8, 2007
Feb 8, 2007
703
704
705
706
707
708
if (!TOBY_drawString(turtle->pos.x, turtle->pos.y, utf8str, turtle->angle,
turtle->pen.r, turtle->pen.g, turtle->pen.b))
{
throwError(L, "Platform doesn't support string drawing");
} /* if */
Feb 26, 2007
Feb 26, 2007
709
turtleSpaceIsDirty = 1;
Jan 23, 2007
Jan 23, 2007
710
711
712
713
714
715
return 0;
} /* luahook_drawstring */
static int luahook_random(lua_State *L)
{
Mar 18, 2008
Mar 18, 2008
716
717
718
#ifdef _MSC_VER
const long val = rand(); /* !!! FIXME: seed this. */
#else
Feb 26, 2007
Feb 26, 2007
719
const long val = random(); /* !!! FIXME: seed this. */
Mar 18, 2008
Mar 18, 2008
720
#endif
Feb 26, 2007
Feb 26, 2007
721
722
/* !!! FIXME: fixed point */
/* !!! FIXME: nasty double code. */
Feb 10, 2007
Feb 10, 2007
723
724
const lua_Number flt = (lua_Number) (((double)val) / ((double)RAND_MAX));
lua_pushnumber(L, flt);
Jan 23, 2007
Jan 23, 2007
725
726
727
728
729
730
return 1;
} /* luahook_random */
static int luahook_round(lua_State *L)
{
Feb 26, 2007
Feb 26, 2007
731
/* !!! FIXME: fixed point. */
Jan 24, 2007
Jan 24, 2007
732
lua_pushinteger(L, (lua_Integer) (luaL_checknumber(L, 1) + 0.5));
Jan 23, 2007
Jan 23, 2007
733
734
735
736
return 1;
} /* luahook_setpendown */
Feb 23, 2007
Feb 23, 2007
737
738
739
740
int TOBY_delay(long ms)
{
long now = TOBY_getTicks();
const long end = now + ms;
Feb 26, 2007
Feb 26, 2007
741
do
Feb 23, 2007
Feb 23, 2007
742
{
Feb 26, 2007
Feb 26, 2007
743
TOBY_pumpEvents();
Feb 23, 2007
Feb 23, 2007
744
745
746
747
748
749
750
now = TOBY_getTicks();
if (now < end)
{
const long ticks = end - now;
TOBY_yieldCPU((ticks > 50) ? 50 : ticks);
now = TOBY_getTicks();
} /* if */
Feb 26, 2007
Feb 26, 2007
751
} while (now < end);
Feb 23, 2007
Feb 23, 2007
752
Feb 26, 2007
Feb 26, 2007
753
return (TOBY_isRunning() && !TOBY_isStopping());
Feb 23, 2007
Feb 23, 2007
754
755
756
} /* TOBY_delay */
Jan 23, 2007
Jan 23, 2007
757
758
759
static int luahook_pause(lua_State *L)
{
const lua_Number secs = luaL_checknumber(L, 1);
Feb 23, 2007
Feb 23, 2007
760
if (!TOBY_delay(secsToMs(secs)))
Feb 6, 2007
Feb 6, 2007
761
haltProgram(L);
Jan 23, 2007
Jan 23, 2007
762
763
764
765
766
767
return 0;
} /* luahook_pause */
static int luahook_addturtle(lua_State *L)
{
Feb 8, 2007
Feb 8, 2007
768
allocateTurtle(L);
Jan 23, 2007
Jan 23, 2007
769
770
771
772
773
774
return 0;
} /* luahook_addturtle */
static int luahook_useturtle(lua_State *L)
{
Feb 8, 2007
Feb 8, 2007
775
776
777
778
779
const int newidx = checkWholeNum(L, 1);
if ((newidx < 0) || (newidx >= totalTurtles))
throwError(L, "Not a valid turtle");
currentTurtleIndex = newidx;
Jan 23, 2007
Jan 23, 2007
780
781
782
783
return 0;
} /* luahook_useturtle */
Jan 25, 2007
Jan 25, 2007
784
785
786
787
788
789
790
static int luahook_print(lua_State *L)
{
printf("%s\n", luaL_checklstring(L, 1, NULL));
return 0;
} /* luahook_print */
791
792
793
794
795
static void add_toby_functions(lua_State *L)
{
#define SET_LUAHOOK(sym) \
lua_pushcfunction(L, luahook_##sym); \
lua_setglobal(L, #sym);
Feb 8, 2007
Feb 8, 2007
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
SET_LUAHOOK(showturtle);
SET_LUAHOOK(hideturtle);
SET_LUAHOOK(hometurtle);
SET_LUAHOOK(enablefence);
SET_LUAHOOK(disablefence);
SET_LUAHOOK(drawstring);
SET_LUAHOOK(random);
SET_LUAHOOK(getturtlespacewidth);
SET_LUAHOOK(getturtlespaceheight);
SET_LUAHOOK(getturtlex);
SET_LUAHOOK(getturtley);
SET_LUAHOOK(cleanupturtlespace);
SET_LUAHOOK(setpencolorrgb);
SET_LUAHOOK(setpenup);
SET_LUAHOOK(setpendown);
SET_LUAHOOK(addturtle);
SET_LUAHOOK(useturtle);
SET_LUAHOOK(round);
SET_LUAHOOK(stringlength);
Feb 8, 2007
Feb 8, 2007
815
816
817
818
819
820
SET_LUAHOOK(rightstring);
SET_LUAHOOK(leftstring);
SET_LUAHOOK(substring);
SET_LUAHOOK(uppercasestring);
SET_LUAHOOK(lowercasestring);
SET_LUAHOOK(joinstrings);
Feb 8, 2007
Feb 8, 2007
821
822
SET_LUAHOOK(pause);
SET_LUAHOOK(setangle);
823
824
825
826
827
828
SET_LUAHOOK(goforward);
SET_LUAHOOK(gobackward);
SET_LUAHOOK(turnright);
SET_LUAHOOK(turnleft);
SET_LUAHOOK(setpencolor);
SET_LUAHOOK(setturtlexy);
Jan 25, 2007
Jan 25, 2007
829
SET_LUAHOOK(print);
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
#undef SET_LUAHOOK
}
static int luahook_stackwalk(lua_State *L)
{
const char *errstr = lua_tostring(L, 1);
#if 0
lua_Debug ldbg;
int i = 0;
if (errstr != NULL)
logDebug("%s\n", errstr);
logDebug("Lua stack backtrace:");
Feb 26, 2007
Feb 26, 2007
847
/* start at 1 to skip this function. */
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
for (i = 1; lua_getstack(L, i, &ldbg); i++)
{
char *ptr = (char *) scratchbuf_128k;
size_t len = sizeof (scratchbuf_128k);
int bw = snprintfcat(&ptr, &len, "#%d", i-1);
const int maxspacing = 4;
int spacing = maxspacing - bw;
while (spacing-- > 0)
snprintfcat(&ptr, &len, " ");
if (!lua_getinfo(L, "nSl", &ldbg))
{
snprintfcat(&ptr, &len, "???\n");
logDebug((const char *) scratchbuf_128k);
continue;
Feb 26, 2007
Feb 26, 2007
863
} /* if */
864
865
866
867
868
869
870
871
872
873
874
875
876
877
if (ldbg.namewhat[0])
snprintfcat(&ptr, &len, "%s ", ldbg.namewhat);
if ((ldbg.name) && (ldbg.name[0]))
snprintfcat(&ptr, &len, "function %s ()", ldbg.name);
else
{
if (strcmp(ldbg.what, "main") == 0)
snprintfcat(&ptr, &len, "mainline of chunk");
else if (strcmp(ldbg.what, "tail") == 0)
snprintfcat(&ptr, &len, "tail call");
else
snprintfcat(&ptr, &len, "unidentifiable function");
Feb 26, 2007
Feb 26, 2007
878
} /* if */
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
logDebug((const char *) scratchbuf_128k);
ptr = (char *) scratchbuf_128k;
len = sizeof (scratchbuf_128k);
for (spacing = 0; spacing < maxspacing; spacing++)
snprintfcat(&ptr, &len, " ");
if (strcmp(ldbg.what, "C") == 0)
snprintfcat(&ptr, &len, "in native code");
else if (strcmp(ldbg.what, "tail") == 0)
snprintfcat(&ptr, &len, "in Lua code");
else if ( (strcmp(ldbg.source, "=?") == 0) && (ldbg.currentline == 0) )
snprintfcat(&ptr, &len, "in Lua code (debug info stripped)");
else
{
snprintfcat(&ptr, &len, "in Lua code at %s", ldbg.short_src);
if (ldbg.currentline != -1)
snprintfcat(&ptr, &len, ":%d", ldbg.currentline);
Feb 26, 2007
Feb 26, 2007
898
} /* else */
899
logDebug((const char *) scratchbuf_128k);
Feb 26, 2007
Feb 26, 2007
900
} /* for */
901
902
903
904
#endif
lua_pushstring(L, errstr ? errstr : "");
return 1;
Feb 18, 2007
Feb 18, 2007
905
} /* luahook_stackwalk */
Feb 28, 2007
Feb 28, 2007
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
static int *breakpointLines = NULL;
static int breakpointLineCount = 0;
void TOBY_clearAllBreakpoints(void)
{
free(breakpointLines);
breakpointLines = NULL;
breakpointLineCount = 0;
} /* TOBY_clearAllBreakpoints */
int TOBY_addBreakpointLine(int line)
{
const size_t newSize = sizeof (int) * (breakpointLineCount + 1);
void *ptr = realloc(breakpointLines, newSize);
if (ptr == NULL)
return -1;
/* !!! FIXME: sort into array, don't append. */
/* !!! FIXME: make sure it's not already in the array. */
breakpointLines = (int *) ptr;
breakpointLines[breakpointLineCount++] = line;
return breakpointLineCount-1;
} /* TOBY_addBreakpointLine */
static int isBreakpointLine(int line)
{
int retval = -1;
if (breakpointLines != NULL)
{
int i; /* !!! FIXME: don't do a linear search here... */
for (i = 0; i < breakpointLineCount; i++)
{
if (breakpointLines[i] == line)
return i;
} /* for */
} /* if */
return retval;
} /* isBreakpointLine */
Jan 24, 2007
Jan 24, 2007
951
952
static void luaDebugHook(lua_State *L, lua_Debug *ar)
{
Feb 26, 2007
Feb 26, 2007
953
const int hook = ar->event;
Feb 28, 2007
Feb 28, 2007
954
const int line = ar->currentline;
Feb 26, 2007
Feb 26, 2007
955
956
const long startTicks = TOBY_getTicks();
long pauseTicks = -1;
Feb 28, 2007
Feb 28, 2007
957
int breakpoint = -1;
Feb 26, 2007
Feb 26, 2007
958
959
960
961
962
963
964
965
int shouldRedraw = (startTicks >= nextPumpTicks);
/*
* Should only break inside this function, and should block here until
* breakpoint ends and program continues.
*/
assert(!TOBY_isPaused());
Feb 26, 2007
Feb 26, 2007
966
/* If we hit a new line, see if this is a breakpoint. Pause here if so. */
Feb 26, 2007
Feb 26, 2007
967
968
969
if (hook == LUA_HOOKLINE)
{
const long mustDelay = TOBY_getDelayTicksPerLine();
Feb 28, 2007
Feb 28, 2007
970
/*printf("Now on line #%d\n", line);*/
Feb 26, 2007
Feb 26, 2007
971
972
if (mustDelay > 0)
pauseTicks = startTicks + mustDelay;
Feb 26, 2007
Feb 26, 2007
973
if (TOBY_isStepping()) /* single stepping? Break here. */
Feb 26, 2007
Feb 26, 2007
974
execState = EXEC_PAUSED;
Feb 28, 2007
Feb 28, 2007
975
976
977
978
979
980
981
982
983
984
985
986
987
if ((breakpoint = isBreakpointLine(line)) != -1)
execState = EXEC_PAUSED;
} /* if */
/* !!! FIXME: maybe later. */
#if 0
if (hook == LUA_HOOKCALL)
{
if (breakpoint == -1)
{
if ((breakpoint = isBreakpointFunc(ar)) != -1)
execState = EXEC_PAUSED;
} /* if */
Feb 26, 2007
Feb 26, 2007
988
} /* if */
Feb 28, 2007
Feb 28, 2007
989
#endif
Feb 26, 2007
Feb 26, 2007
990
Feb 28, 2007
Feb 28, 2007
991
if ((TOBY_isPaused()) || (pauseTicks > 0))
Feb 28, 2007
Feb 28, 2007
992
TOBY_pauseReached(line, TOBY_isPaused(), breakpoint, pauseTicks);
Feb 28, 2007
Feb 28, 2007
993
Feb 26, 2007
Feb 26, 2007
994
995
996
997
while ( (TOBY_isPaused()) || (pauseTicks > 0) || (shouldRedraw) )
{
if (shouldRedraw)
{
Feb 26, 2007
Feb 26, 2007
998
999
1000
/*
* Force repaint here...this means we will be clamped to 20fps,
* but the overall execution of the program will be much faster,