Initial commit of newLISP.
[newlisp.git] / nl-debug.c
blobbe1bb81066d4a7b5a2aa8778b321aa0c71ec32d7
1 /* nl-debug.c --- debugging functions for newLISP
3 Copyright (C) 2008 Lutz Mueller
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "newlisp.h"
22 #include "protos.h"
24 #ifdef WIN_32
25 #define fgets win32_fgets
26 #endif
28 extern FILE * IOchannel;
29 extern int evalSilent;
31 int matchString(char * buffer, char * string, int * length);
32 int stringComp(char * buffer, char * string);
33 int printFunction(CELL * cell);
34 void getDebuggerInput(char * msg);
35 void allocateDebugStack(void);
37 extern SYMBOL * currentFunc;
38 extern SYMBOL * timerEvent;
39 extern SYMBOL * symHandler[];
40 extern int currentSignal;
42 int currentLevel = 0;
43 int debugStackIdx = 0;
44 UINT * debugStack;
46 char preStr[8] = "#";
47 char postStr[8] = "#";
48 char headerStr[16] = "\n-----\n\n";
49 char footerStr[32] = " s|tep n|ext c|ont q|uit > ";
51 #define pushDebugStack(A) (*(debugStack + debugStackIdx++) = (UINT)(A))
52 #define popDebugStack() (*(debugStack + --debugStackIdx))
54 #define DEBUG_ENTRY "->"
55 #define DEBUG_EXIT "<-"
58 void openTrace(void)
60 if(traceFlag) return;
61 traceFlag = TRUE;
62 currentFunc = nilSymbol;
63 debugStackIdx = 0;
64 allocateDebugStack();
67 void closeTrace(void)
69 /* printf("closing trace\n"); */
70 traceFlag = 0;
71 if(debugStack) free(debugStack);
72 debugStack = NULL;
77 CELL * p_debug(CELL * params)
79 CELL * result;
81 openTrace();
82 result = copyCell(evaluateExpression(params));
83 closeTrace();
85 return(result);
89 CELL * p_trace(CELL * params)
91 if(params != nilCell)
93 if(getFlag(params))
94 openTrace();
95 else
96 closeTrace();
99 return((traceFlag == 0 ? nilCell : trueCell));
102 CELL * p_traceHighlight(CELL * params)
104 char * pre, * post, * header, * footer;
106 params = getString(params, &pre);
107 params = getString(params, &post);
109 strncpy(preStr, pre, 7);
110 strncpy(postStr, post, 7);
112 if(params != nilCell)
114 params = getString(params, &header);
115 strncpy(headerStr, header, 15);
118 if(params != nilCell)
120 getString(params, &footer);
121 strncpy(footerStr, footer, 31);
125 return(trueCell);
129 void traceEntry(CELL * cell, CELL * pCell, CELL * args)
131 int defaultFuncFlag = FALSE;
133 if(traceFlag & (TRACE_IN_ENTRY | TRACE_IN_EXIT | TRACE_DEBUG_NEXT)) return;
134 traceFlag |= TRACE_IN_ENTRY;
136 if(traceFlag & TRACE_SIGNAL)
138 traceFlag &= ~TRACE_SIGNAL;
139 executeSymbol(symHandler[currentSignal - 1], stuffInteger(currentSignal));
140 traceFlag &= ~TRACE_IN_ENTRY;
141 return;
144 if(traceFlag & TRACE_SIGINT)
146 traceFlag &= ~TRACE_SIGINT;
147 longjmp(errorJump, ERR_USER_RESET);
150 if(traceFlag & TRACE_TIMER)
152 traceFlag &= ~TRACE_TIMER;
153 executeSymbol(timerEvent, NULL);
154 traceFlag &= ~TRACE_IN_ENTRY;
155 return;
158 if(debugStackIdx > 1)
160 if(printFunction(cell))
161 getDebuggerInput(DEBUG_ENTRY);
162 if(!traceFlag) return;
165 if(traceFlag & TRACE_DEBUG_NEXT)
167 traceFlag &= ~TRACE_IN_ENTRY;
168 return;
171 if(pCell->type == CELL_CONTEXT)
173 defaultFuncFlag = TRUE;
174 currentFunc = translateCreateSymbol(
175 ((SYMBOL*)pCell->contents)->name,
176 CELL_NIL,
177 (SYMBOL*)pCell->contents,
178 TRUE);
180 pCell = (CELL *)currentFunc->contents;
183 if((pCell->type == CELL_LAMBDA || pCell->type == CELL_MACRO)
184 && args->type == CELL_SYMBOL)
186 if(debugStackIdx == 0) /* startup */
187 traceFlag &= ~TRACE_DEBUG_NEXT;
189 if(!defaultFuncFlag)
190 currentFunc = (SYMBOL *)args->contents;
191 pushDebugStack(recursionCount);
192 pushDebugStack(currentFunc);
195 traceFlag &= ~TRACE_IN_ENTRY;
199 void traceExit(CELL * result, CELL * cell, CELL * pCell, CELL * args)
201 if(traceFlag & (TRACE_IN_ENTRY | TRACE_IN_EXIT | TRACE_SIGNAL | TRACE_SIGINT | TRACE_TIMER)) return;
202 traceFlag |= TRACE_IN_EXIT;
204 if(traceFlag & TRACE_DEBUG_NEXT)
206 if(currentLevel >= recursionCount)
207 traceFlag &= ~TRACE_DEBUG_NEXT;
208 else
210 traceFlag &= ~TRACE_IN_EXIT;
211 return;
215 if( (pCell->type == CELL_LAMBDA || pCell->type == CELL_MACRO)
216 && args->type == CELL_SYMBOL)
218 if((UINT)recursionCount == *(debugStack + debugStackIdx - 2) )
220 debugStackIdx -= 2;
221 if(debugStackIdx > 0)
222 currentFunc = (SYMBOL *)*(debugStack + debugStackIdx - 1);
223 if(debugStackIdx == 0)
224 traceFlag &= ~TRACE_DEBUG_NEXT;
228 if(printFunction(cell))
230 varPrintf(OUT_CONSOLE, "\nRESULT: ");
231 printCell(result, TRUE, OUT_CONSOLE);
232 varPrintf(OUT_CONSOLE, "\n");
234 if(debugStackIdx > 0)
236 getDebuggerInput(DEBUG_EXIT);
237 if(!traceFlag) return;
241 if(traceFlag & TRACE_DEBUG_NEXT)
242 currentLevel = recursionCount;
244 traceFlag &= ~TRACE_IN_EXIT;
248 void getDebuggerInput(char * msg)
250 char command[MAX_LINE];
251 char * context;
252 jmp_buf errorJumpSave;
253 int resultStackIdxSave;
254 SYMBOL * contextSave;
256 while(TRUE)
259 if(currentContext != mainContext)
260 context = currentContext->name;
261 else context = "";
264 if(!evalSilent)
265 varPrintf(OUT_CONSOLE, "\n[%s %d %s]%s", msg, recursionCount, context, footerStr);
266 else evalSilent = FALSE;
268 fgets(command, MAX_LINE - 1, IOchannel);
270 if( (strcmp(command, "n\n") == 0) || (strcmp(command, "n\r\n") == 0))
272 traceFlag |= TRACE_DEBUG_NEXT;
273 currentLevel = recursionCount;
274 break;
276 else if( (strcmp(command, "s\n") == 0) || (strcmp(command, "s\r\n") == 0))
278 traceFlag &= ~TRACE_DEBUG_NEXT;
279 break;
281 else if( (strcmp(command, "q\n") == 0) || (strcmp(command, "q\r\n") == 0))
283 closeTrace();
284 longjmp(errorJump, ERR_USER_RESET);
286 else if( (strcmp(command, "c\n") == 0) || (strcmp(command, "c\r\n") == 0))
288 closeTrace();
289 break;
292 resultStackIdxSave = resultStackIdx;
293 memcpy(errorJumpSave, errorJump, sizeof(jmp_buf));
294 contextSave = currentContext;
295 currentContext = currentFunc->context;
296 if(setjmp(errorJump))
298 cleanupResults(resultStackIdxSave);
299 goto DEBUG_EVAL_END;
302 executeCommandLine(command, OUT_CONSOLE, NULL);
304 DEBUG_EVAL_END:
305 currentContext = contextSave;
306 memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
311 int printFunction(CELL * cell)
313 char * funcStr;
314 char * expStr;
315 int start, length;
316 STREAM strStream;
318 if(currentFunc == nilSymbol) return FALSE;
320 openStrStream(&strStream, MAX_STRING, 0);
321 printSymbol(currentFunc, (UINT)&strStream);
322 length = strlen(strStream.buffer);
323 funcStr = allocMemory(length + 1);
324 memcpy(funcStr, strStream.buffer, length + 1);
325 *(funcStr + length) = 0;
327 openStrStream(&strStream, MAX_STRING, 0);
328 printCell((CELL *)cell, TRUE, (UINT)&strStream);
329 expStr = strStream.buffer;
330 start = matchString(funcStr, expStr, &length);
331 closeStrStream(&strStream);
333 if(start == -1 || length == 0)
335 free(funcStr);
336 return FALSE;
339 varPrintf(OUT_CONSOLE, headerStr);
341 expStr = allocMemory(length + 1);
342 strncpy(expStr, funcStr + start, length);
343 *(expStr + length) = 0;
344 *(funcStr + start) = 0;
346 varPrintf(OUT_CONSOLE, "%s%s%s%s%s",
347 funcStr, preStr, expStr, postStr, funcStr + start + length);
349 free(funcStr);
351 return TRUE;
355 void allocateDebugStack(void)
357 debugStack = (UINT *)allocMemory(MAX_CPU_STACK * 2 * sizeof(UINT));
360 /* search for a string skipping white space
362 int matchString(char * buffer, char * string, int * length)
364 int position, flag;
366 /* strip leading white space */
367 while(*string <= ' ' && *string > 0) string++;
369 position = flag = 0;
371 while(*buffer)
373 if(*buffer > ' ')
374 if((*length = stringComp(buffer, string)) > 0)
376 flag = TRUE;
377 break;
379 position++;
380 buffer++;
383 if(!flag) return(-1);
384 return(position);
388 /* compare strings skipping white space
390 int stringComp(char * buffer, char * string)
392 char * start;
394 start = buffer;
395 while(*string && *buffer)
397 if(*string > ' ')
399 if(*buffer > ' ')
401 if(*string != *buffer) return(0);
402 string++;
403 buffer++;
405 else buffer++;
407 else string++;
410 if(*string == 0)
411 return(buffer - start);
413 return(0);
417 /* eof */