1 /*
2  * Copyright (c) 2003
3  *      David Leonard.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of David Leonard nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #if HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34 
35 #if STDC_HEADERS
36 # include <stdio.h>
37 #endif
38 
39 #include <see/try.h>
40 #include <see/value.h>
41 #include <see/object.h>
42 #include <see/string.h>
43 #include <see/debug.h>
44 #include <see/interpreter.h>
45 #include "function.h"
46 
47 static void print_traceback(struct SEE_interpreter *interp,
48 	struct SEE_traceback *traceback, FILE *f);
49 
50 /*
51  * Print the contents of a value, without raising an exception
52  */
53 void
SEE_PrintValue(interp,v,f)54 SEE_PrintValue(interp, v, f)
55 	struct SEE_interpreter *interp;
56 	const struct SEE_value *v;
57 	FILE *f;
58 {
59 	if (!f) f=stderr;
60 	if (v == NULL) {
61 	    fprintf(f, "NULL");
62 	    return;
63 	}
64 	switch (SEE_VALUE_GET_TYPE(v)) {
65 	case SEE_UNDEFINED:
66 	    fprintf(f, "undefined");
67 	    break;
68 	case SEE_NULL:
69 	    fprintf(f, "null");
70 	    break;
71 	case SEE_BOOLEAN:
72 	    fprintf(f, v->u.boolean ? "true" : "false");
73 	    break;
74 	case SEE_NUMBER:
75 	    fprintf(f, "%.30g", v->u.number);
76 	    break;
77 	case SEE_STRING:
78 	    SEE_PrintString(interp, v->u.string, f);
79 	    break;
80 	case SEE_OBJECT:
81 	    SEE_PrintObject(interp, v->u.object, f);
82 	    break;
83 	case SEE_REFERENCE:
84 	    fprintf(f, "<ref base=<object %p> prop=",
85 	    	(void *)v->u.reference.base);
86 	    SEE_string_fputs(v->u.reference.property, f);
87 	    fprintf(f, ">");
88 	    break;
89 	case SEE_COMPLETION:
90 	    switch (v->u.completion.type) {
91 	    case SEE_COMPLETION_NORMAL:
92 		fprintf(f, "<normal");
93 		if (v->u.completion.value) {
94 		    fprintf(f, " ");
95 		    SEE_PrintValue(interp, v->u.completion.value, f);
96 		}
97 		fprintf(f, ">");
98 		break;
99 	    case SEE_COMPLETION_BREAK:
100 		fprintf(f, "<break %u>", v->u.completion.target);
101 		break;
102 	    case SEE_COMPLETION_CONTINUE:
103 		fprintf(f, "<continue %u>", v->u.completion.target);
104 		break;
105 	    case SEE_COMPLETION_RETURN:
106 		fprintf(f, "<return ");
107 		SEE_PrintValue(interp, v->u.completion.value, f);
108 		fprintf(f, ">");
109 		break;
110 	    case SEE_COMPLETION_THROW:
111 		fprintf(f, "<throw ");
112 		SEE_PrintValue(interp, v->u.completion.value, f);
113 		fprintf(f, ">");
114 		break;
115 	    default:
116 		fprintf(f, "<BAD completion %d>", v->u.completion.type);
117 	    }
118 	    break;
119 	default:
120 	    fprintf(f, "<BAD value %d>", SEE_VALUE_GET_TYPE(v));
121 	}
122 }
123 
124 /*
125  * Print an object without raising an exception.
126  * The object's class is shown in quotes.
127  * If the object is known to the interpreter (eg Object, Array.prototype, etc.)
128  * then its original name is shown in parentheses.
129  */
130 void
SEE_PrintObject(interp,o,f)131 SEE_PrintObject(interp, o, f)
132 	struct SEE_interpreter *interp;
133 	const struct SEE_object *o;
134 	FILE *f;
135 {
136 	const char *known;
137 
138 	if (!f) f=stderr;
139 	if (o == NULL)				known = "NULL";
140 	else if (interp == NULL)		known = NULL;
141 	else if (o == interp->Global)		known = "Global";
142 	else if (o == interp->Object)		known = "Object";
143 	else if (o == interp->Object_prototype)	known = "Object.prototype";
144 	else if (o == interp->Error)		known = "Error";
145 	else if (o == interp->EvalError)	known = "EvalError";
146 	else if (o == interp->RangeError)	known = "RangeError";
147 	else if (o == interp->ReferenceError)	known = "ReferenceError";
148 	else if (o == interp->SyntaxError)	known = "SyntaxError";
149 	else if (o == interp->TypeError)	known = "TypeError";
150 	else if (o == interp->URIError)		known = "URIError";
151 	else if (o == interp->String)		known = "String";
152 	else if (o == interp->String_prototype)	known = "String.prototype";
153 	else if (o == interp->Function)		known = "Function";
154 	else if (o == interp->Function_prototype)known = "Function.prototype";
155 	else if (o == interp->Array)		known = "Array";
156 	else if (o == interp->Array_prototype)	known = "Array.prototype";
157 	else if (o == interp->Number)		known = "Number";
158 	else if (o == interp->Number_prototype)	known = "Number.prototype";
159 	else if (o == interp->Boolean)		known = "Boolean";
160 	else if (o == interp->Boolean_prototype)known = "Boolean.prototype";
161 	else if (o == interp->Math)		known = "Math";
162 	else if (o == interp->RegExp)		known = "RegExp";
163 	else if (o == interp->RegExp_prototype)	known = "RegExp.prototype";
164 	else if (o == interp->Date)		known = "Date";
165 	else if (o == interp->Date_prototype)	known = "Date.prototype";
166 	else					known = NULL;
167 
168 	fprintf(f, "<object %p", (void *)o);
169 	if (known)
170 		fprintf(f, " (%s)", known);
171 	if (o && o->objectclass && !known) {
172 		fprintf(f, " \"%s\"", o->objectclass->Class);
173 	}
174 	if (o->host_data)
175 		fprintf(f, " %p", o->host_data);
176 	fprintf(f, ">");
177 }
178 
179 /*
180  * Print a string, in 'literal' form to the given stdio file.
181  */
182 void
SEE_PrintString(interp,s,f)183 SEE_PrintString(interp, s, f)
184 	struct SEE_interpreter *interp;
185 	const struct SEE_string *s;
186 	FILE *f;
187 {
188 	unsigned int i;
189 
190 	if (!f) f=stderr;
191 	if (s == NULL)
192 	    fprintf(f, "<NULL>");
193 	else {
194 	    /* NB Replicates most of SEE_string_literal(). */
195 	    fprintf(f, "\"");
196 	    for (i = 0; i < s->length; i++) {
197 		SEE_char_t c = s->data[i];
198 		if (c == '\\') fprintf(f, "\\\\");
199 		else if (c == '\"') fprintf(f, "\\\"");
200 		else if (c == '\n') fprintf(f, "\\n");
201 		else if (c == '\t') fprintf(f, "\\t");
202 		else if (c >= ' ' && c <= '~')
203 			fputc(c & 0x7f, f);
204 		else if (c < 0x100)
205 			fprintf(f, "\\x%02x", c);
206 		else
207 			fprintf(f, "\\u%04x", c);
208 		if (i < s->length && i >= 1024) {
209 			fprintf(f, "\\(...len=%u)", s->length);
210 			break;
211 		}
212 	    }
213 	    fprintf(f, "\"<%s%p>",
214 		    s->flags & SEE_STRING_FLAG_INTERNED ? "i" : "",
215 		    (void *)s);
216 	}
217 }
218 
219 static void
print_traceback(interp,traceback,f)220 print_traceback(interp, traceback, f)
221 	struct SEE_interpreter *interp;
222 	struct SEE_traceback *traceback;
223 	FILE *f;
224 {
225 	struct SEE_traceback *tb;
226 	struct SEE_string *locstr, *fname;
227 	struct SEE_object *fo;
228 
229 	if (!f) f=stderr;
230 	if (!traceback)
231 		return;
232 	fprintf(f, "traceback:\n");
233 	for (tb = traceback; tb; tb = tb->prev) {
234 		locstr = SEE_location_string(interp, tb->call_location);
235 		fprintf(f, "\t");
236 		SEE_string_fputs(locstr, f);
237 		fo = tb->callee;
238 		if (tb->call_type == SEE_CALLTYPE_THROW)
239 		    fprintf(f, "<throw>");
240 		else if (fo == NULL)
241 		    fprintf(f, "?");
242 		else if (tb->call_type == SEE_CALLTYPE_CONSTRUCT)
243 		    fprintf(f, "new %s", fo->objectclass->Class
244 			    ? fo->objectclass->Class
245 			    : "?");
246 		else if (tb->call_type == SEE_CALLTYPE_CALL) {
247 		    fprintf(f, "call ");
248 		    /* XXX is fo == interp->Global_eval case handled OK? */
249 		    fname = SEE_function_getname(interp, fo);
250 		    if (fname) {
251 		        SEE_string_fputs(fname, f);
252 			fprintf(f, "()");
253 		    } else
254 		        fprintf(f, "<anonymous function>");
255 		} else
256 		    SEE_PrintObject(interp, fo, f);
257 		fprintf(f, "\n");
258 	}
259 }
260 
261 void
SEE_PrintTraceback(interp,f)262 SEE_PrintTraceback(interp, f)
263 	struct SEE_interpreter *interp;
264 	FILE *f;
265 {
266 	print_traceback(interp, interp->traceback, f);
267 }
268 
269 void
SEE_PrintContextTraceback(interp,ctxt,f)270 SEE_PrintContextTraceback(interp, ctxt, f)
271 	struct SEE_interpreter *interp;
272 	volatile struct SEE_try_context *ctxt;
273 	FILE *f;
274 {
275 	print_traceback(interp, ctxt->traceback, f);
276 }
277