Fix set-source-properties so that the special source properties work
[bpt/guile.git] / libguile / srcprop.c
CommitLineData
dbb605f5 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002, 2006, 2008 Free Software Foundation
575888bd 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
575888bd 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
575888bd 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
1bbd0b84 18
1bbd0b84 19
575888bd 20\f
dbb605f5
LC
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
575888bd 24
e6e2e95a
MD
25#include <errno.h>
26
a0599745 27#include "libguile/_scm.h"
4e047c3e 28#include "libguile/async.h"
a0599745
MD
29#include "libguile/smob.h"
30#include "libguile/alist.h"
31#include "libguile/debug.h"
32#include "libguile/hashtab.h"
33#include "libguile/hash.h"
34#include "libguile/ports.h"
35#include "libguile/root.h"
36#include "libguile/weaks.h"
575888bd 37
a0599745
MD
38#include "libguile/validate.h"
39#include "libguile/srcprop.h"
575888bd
MD
40\f
41/* {Source Properties}
42 *
43 * Properties of source list expressions.
b0763985 44 * Five of these have special meaning:
575888bd
MD
45 *
46 * filename string The name of the source file.
47 * copy list A copy of the list expression.
48 * line integer The source code line number.
49 * column integer The source code column number.
50 * breakpoint boolean Sets a breakpoint on this form.
51 *
52 * Most properties above can be set by the reader.
53 *
54 */
55
85db4a2c
DH
56SCM_GLOBAL_SYMBOL (scm_sym_filename, "filename");
57SCM_GLOBAL_SYMBOL (scm_sym_copy, "copy");
58SCM_GLOBAL_SYMBOL (scm_sym_line, "line");
59SCM_GLOBAL_SYMBOL (scm_sym_column, "column");
60SCM_GLOBAL_SYMBOL (scm_sym_breakpoint, "breakpoint");
575888bd 61
575888bd 62
1cc91f1b 63
b0763985 64/*
d00a0704
HWN
65 * Source properties are stored as double cells with the
66 * following layout:
b0763985 67
d00a0704
HWN
68 * car = tag
69 * cbr = pos
70 * ccr = copy
67a96734 71 * cdr = alist
d00a0704 72 */
b0763985
HWN
73
74#define SRCPROPSP(p) (SCM_SMOB_PREDICATE (scm_tc16_srcprops, (p)))
75#define SRCPROPBRK(p) (SCM_SMOB_FLAGS (p) & SCM_SOURCE_PROPERTY_FLAG_BREAK)
76#define SRCPROPPOS(p) (SCM_CELL_WORD(p,1))
77#define SRCPROPLINE(p) (SRCPROPPOS(p) >> 12)
78#define SRCPROPCOL(p) (SRCPROPPOS(p) & 0x0fffL)
79#define SRCPROPCOPY(p) (SCM_CELL_OBJECT(p,2))
67a96734 80#define SRCPROPALIST(p) (SCM_CELL_OBJECT_3(p))
b0763985
HWN
81#define SETSRCPROPBRK(p) \
82 (SCM_SET_SMOB_FLAGS ((p), \
83 SCM_SMOB_FLAGS (p) | SCM_SOURCE_PROPERTY_FLAG_BREAK))
84#define CLEARSRCPROPBRK(p) \
85 (SCM_SET_SMOB_FLAGS ((p), \
86 SCM_SMOB_FLAGS (p) & ~SCM_SOURCE_PROPERTY_FLAG_BREAK))
87#define SRCPROPMAKPOS(l, c) (((l) << 12) + (c))
88#define SETSRCPROPPOS(p, l, c) (SCM_SET_CELL_WORD(p,1, SRCPROPMAKPOS (l, c)))
89#define SETSRCPROPLINE(p, l) SETSRCPROPPOS (p, l, SRCPROPCOL (p))
90#define SETSRCPROPCOL(p, c) SETSRCPROPPOS (p, SRCPROPLINE (p), c)
80237dcc 91#define SETSRCPROPCOPY(p, c) (SCM_SET_CELL_WORD(p, 2, c))
67a96734 92#define SETSRCPROPALIST(p, l) (SCM_SET_CELL_WORD(p, 3, l))
b0763985
HWN
93
94
67a96734
NJ
95static SCM scm_srcprops_to_alist (SCM obj);
96
b0763985
HWN
97
98scm_t_bits scm_tc16_srcprops;
99
575888bd 100static SCM
e841c3e0 101srcprops_mark (SCM obj)
575888bd 102{
575888bd 103 scm_gc_mark (SRCPROPCOPY (obj));
67a96734 104 return SRCPROPALIST (obj);
575888bd
MD
105}
106
575888bd 107static int
e841c3e0 108srcprops_print (SCM obj, SCM port, scm_print_state *pstate)
575888bd 109{
19402679 110 int writingp = SCM_WRITINGP (pstate);
b7f3516f 111 scm_puts ("#<srcprops ", port);
19402679 112 SCM_SET_WRITINGP (pstate, 1);
67a96734 113 scm_iprin1 (scm_srcprops_to_alist (obj), port, pstate);
19402679 114 SCM_SET_WRITINGP (pstate, writingp);
b7f3516f 115 scm_putc ('>', port);
575888bd
MD
116 return 1;
117}
118
1cc91f1b 119
bc76d628
DH
120int
121scm_c_source_property_breakpoint_p (SCM form)
122{
123 SCM obj = scm_whash_lookup (scm_source_whash, form);
124 return SRCPROPSP (obj) && SRCPROPBRK (obj);
125}
126
127
b0763985 128/*
67a96734 129 * We remember the last file name settings, so we can share that alist
d00a0704 130 * entry. This works because scm_set_source_property_x does not use
67a96734 131 * assoc-set! for modifying the alist.
d00a0704
HWN
132 *
133 * This variable contains a protected cons, whose cdr is the cached
67a96734 134 * alist
b0763985 135 */
67a96734 136static SCM scm_last_alist_filename;
b0763985 137
575888bd 138SCM
67a96734 139scm_make_srcprops (long line, int col, SCM filename, SCM copy, SCM alist)
575888bd 140{
b0763985 141 if (!SCM_UNBNDP (filename))
575888bd 142 {
67a96734 143 SCM old_alist = alist;
b0763985
HWN
144
145 /*
146 have to extract the acons, and operate on that, for
147 thread safety.
148 */
67a96734
NJ
149 SCM last_acons = SCM_CDR (scm_last_alist_filename);
150 if (old_alist == SCM_EOL
b0763985
HWN
151 && SCM_CDAR (last_acons) == filename)
152 {
67a96734 153 alist = last_acons;
b0763985
HWN
154 }
155 else
156 {
67a96734
NJ
157 alist = scm_acons (scm_sym_filename, filename, alist);
158 if (old_alist == SCM_EOL)
159 SCM_SETCDR (scm_last_alist_filename, alist);
b0763985 160 }
575888bd 161 }
b0763985
HWN
162
163 SCM_RETURN_NEWSMOB3 (scm_tc16_srcprops,
164 SRCPROPMAKPOS (line, col),
165 copy,
67a96734 166 alist);
575888bd
MD
167}
168
1cc91f1b 169
67a96734
NJ
170static SCM
171scm_srcprops_to_alist (SCM obj)
575888bd 172{
67a96734 173 SCM alist = SRCPROPALIST (obj);
575888bd 174 if (!SCM_UNBNDP (SRCPROPCOPY (obj)))
67a96734
NJ
175 alist = scm_acons (scm_sym_copy, SRCPROPCOPY (obj), alist);
176 alist = scm_acons (scm_sym_column, scm_from_int (SRCPROPCOL (obj)), alist);
177 alist = scm_acons (scm_sym_line, scm_from_int (SRCPROPLINE (obj)), alist);
178 alist = scm_acons (scm_sym_breakpoint, scm_from_bool (SRCPROPBRK (obj)), alist);
179 return alist;
575888bd
MD
180}
181
a1ec6916 182SCM_DEFINE (scm_source_properties, "source-properties", 1, 0, 0,
1bbd0b84 183 (SCM obj),
e3239868 184 "Return the source property association list of @var{obj}.")
1bbd0b84 185#define FUNC_NAME s_scm_source_properties
575888bd
MD
186{
187 SCM p;
34d19ef6 188 SCM_VALIDATE_NIM (1, obj);
575888bd 189 if (SCM_MEMOIZEDP (obj))
a4645b97 190 obj = SCM_MEMOIZED_EXP (obj);
d2e53ed6 191 else if (!scm_is_pair (obj))
1bbd0b84 192 SCM_WRONG_TYPE_ARG (1, obj);
f5003c13 193 p = scm_hashq_ref (scm_source_whash, obj, SCM_EOL);
230d095f 194 if (SRCPROPSP (p))
67a96734 195 return scm_srcprops_to_alist (p);
f5003c13
KR
196 else
197 /* list from set-source-properties!, or SCM_EOL for not found */
198 return p;
575888bd 199}
1bbd0b84 200#undef FUNC_NAME
575888bd
MD
201
202/* Perhaps this procedure should look through an alist
203 and try to make a srcprops-object...? */
a1ec6916 204SCM_DEFINE (scm_set_source_properties_x, "set-source-properties!", 2, 0, 0,
67a96734
NJ
205 (SCM obj, SCM alist),
206 "Install the association list @var{alist} as the source property\n"
e3239868 207 "list for @var{obj}.")
1bbd0b84 208#define FUNC_NAME s_scm_set_source_properties_x
575888bd
MD
209{
210 SCM handle;
1b872adf
NJ
211 long line = 0, col = 0;
212 SCM fname = SCM_UNDEFINED, copy = SCM_UNDEFINED, breakpoint = SCM_BOOL_F;
213 SCM others = SCM_EOL;
214 SCM *others_cdrloc = &others;
215 int need_srcprops = 0;
216 SCM tail, key;
217
34d19ef6 218 SCM_VALIDATE_NIM (1, obj);
575888bd 219 if (SCM_MEMOIZEDP (obj))
a4645b97 220 obj = SCM_MEMOIZED_EXP (obj);
d2e53ed6 221 else if (!scm_is_pair (obj))
1bbd0b84 222 SCM_WRONG_TYPE_ARG(1, obj);
1b872adf
NJ
223
224 tail = alist;
225 while (!scm_is_null (tail))
226 {
227 key = SCM_CAAR (tail);
228 if (scm_is_eq (key, scm_sym_line))
229 {
230 line = scm_to_long (SCM_CDAR (tail));
231 need_srcprops = 1;
232 }
233 else if (scm_is_eq (key, scm_sym_column))
234 {
235 col = scm_to_long (SCM_CDAR (tail));
236 need_srcprops = 1;
237 }
238 else if (scm_is_eq (key, scm_sym_filename))
239 {
240 fname = SCM_CDAR (tail);
241 need_srcprops = 1;
242 }
243 else if (scm_is_eq (key, scm_sym_copy))
244 {
245 copy = SCM_CDAR (tail);
246 need_srcprops = 1;
247 }
248 else if (scm_is_eq (key, scm_sym_breakpoint))
249 {
250 breakpoint = SCM_CDAR (tail);
251 need_srcprops = 1;
252 }
253 else
254 {
255 /* Do we allocate here, or clobber the caller's alist?
256
257 Source properties aren't supposed to be used for anything
258 except the special properties above, so the mainline case
259 is that we never execute this else branch, and hence it
260 doesn't matter much.
261
262 We choose allocation here, as that seems safer.
263 */
264 *others_cdrloc = scm_cons (scm_cons (key, SCM_CDAR (tail)),
265 SCM_EOL);
266 others_cdrloc = SCM_CDRLOC (*others_cdrloc);
267 }
268 tail = SCM_CDR (tail);
269 }
270 if (need_srcprops)
271 {
272 alist = scm_make_srcprops (line, col, fname, copy, others);
273 if (scm_is_true (breakpoint))
274 SETSRCPROPBRK (alist);
275 }
276 else
277 alist = others;
278
67a96734
NJ
279 handle = scm_hashq_create_handle_x (scm_source_whash, obj, alist);
280 SCM_SETCDR (handle, alist);
281 return alist;
575888bd 282}
1bbd0b84 283#undef FUNC_NAME
575888bd 284
a1ec6916 285SCM_DEFINE (scm_source_property, "source-property", 2, 0, 0,
1bbd0b84 286 (SCM obj, SCM key),
e3239868
DH
287 "Return the source property specified by @var{key} from\n"
288 "@var{obj}'s source property list.")
1bbd0b84 289#define FUNC_NAME s_scm_source_property
575888bd
MD
290{
291 SCM p;
34d19ef6 292 SCM_VALIDATE_NIM (1, obj);
575888bd 293 if (SCM_MEMOIZEDP (obj))
a4645b97 294 obj = SCM_MEMOIZED_EXP (obj);
d2e53ed6 295 else if (!scm_is_pair (obj))
1bbd0b84 296 SCM_WRONG_TYPE_ARG (1, obj);
575888bd 297 p = scm_hashq_ref (scm_source_whash, obj, SCM_EOL);
24933780 298 if (!SRCPROPSP (p))
67a96734 299 goto alist;
bc36d050
MV
300 if (scm_is_eq (scm_sym_breakpoint, key)) p = scm_from_bool (SRCPROPBRK (p));
301 else if (scm_is_eq (scm_sym_line, key)) p = scm_from_int (SRCPROPLINE (p));
302 else if (scm_is_eq (scm_sym_column, key)) p = scm_from_int (SRCPROPCOL (p));
bc36d050 303 else if (scm_is_eq (scm_sym_copy, key)) p = SRCPROPCOPY (p);
575888bd
MD
304 else
305 {
67a96734
NJ
306 p = SRCPROPALIST (p);
307 alist:
575888bd
MD
308 p = scm_assoc (key, p);
309 return (SCM_NIMP (p) ? SCM_CDR (p) : SCM_BOOL_F);
310 }
311 return SCM_UNBNDP (p) ? SCM_BOOL_F : p;
312}
1bbd0b84 313#undef FUNC_NAME
575888bd 314
a1ec6916 315SCM_DEFINE (scm_set_source_property_x, "set-source-property!", 3, 0, 0,
1bbd0b84 316 (SCM obj, SCM key, SCM datum),
e3239868
DH
317 "Set the source property of object @var{obj}, which is specified by\n"
318 "@var{key} to @var{datum}. Normally, the key will be a symbol.")
1bbd0b84 319#define FUNC_NAME s_scm_set_source_property_x
575888bd
MD
320{
321 scm_whash_handle h;
322 SCM p;
34d19ef6 323 SCM_VALIDATE_NIM (1, obj);
575888bd 324 if (SCM_MEMOIZEDP (obj))
a4645b97 325 obj = SCM_MEMOIZED_EXP (obj);
d2e53ed6 326 else if (!scm_is_pair (obj))
1bbd0b84 327 SCM_WRONG_TYPE_ARG (1, obj);
575888bd
MD
328 h = scm_whash_get_handle (scm_source_whash, obj);
329 if (SCM_WHASHFOUNDP (h))
330 p = SCM_WHASHREF (scm_source_whash, h);
331 else
332 {
333 h = scm_whash_create_handle (scm_source_whash, obj);
334 p = SCM_EOL;
335 }
bc36d050 336 if (scm_is_eq (scm_sym_breakpoint, key))
cda139a7 337 {
62850ef3
DH
338 if (SRCPROPSP (p))
339 {
7888309b 340 if (scm_is_false (datum))
62850ef3
DH
341 CLEARSRCPROPBRK (p);
342 else
343 SETSRCPROPBRK (p);
344 }
cda139a7 345 else
62850ef3
DH
346 {
347 SCM sp = scm_make_srcprops (0, 0, SCM_UNDEFINED, SCM_UNDEFINED, p);
348 SCM_WHASHSET (scm_source_whash, h, sp);
7888309b 349 if (scm_is_false (datum))
62850ef3
DH
350 CLEARSRCPROPBRK (sp);
351 else
352 SETSRCPROPBRK (sp);
353 }
cda139a7 354 }
bc36d050 355 else if (scm_is_eq (scm_sym_line, key))
575888bd 356 {
0c95b57d 357 if (SRCPROPSP (p))
a55c2b68 358 SETSRCPROPLINE (p, scm_to_int (datum));
575888bd
MD
359 else
360 SCM_WHASHSET (scm_source_whash, h,
a55c2b68 361 scm_make_srcprops (scm_to_int (datum), 0,
a9dbb9fd 362 SCM_UNDEFINED, SCM_UNDEFINED, p));
575888bd 363 }
bc36d050 364 else if (scm_is_eq (scm_sym_column, key))
575888bd 365 {
0c95b57d 366 if (SRCPROPSP (p))
a55c2b68 367 SETSRCPROPCOL (p, scm_to_int (datum));
575888bd
MD
368 else
369 SCM_WHASHSET (scm_source_whash, h,
a55c2b68 370 scm_make_srcprops (0, scm_to_int (datum),
a9dbb9fd 371 SCM_UNDEFINED, SCM_UNDEFINED, p));
575888bd 372 }
bc36d050 373 else if (scm_is_eq (scm_sym_copy, key))
575888bd 374 {
0c95b57d 375 if (SRCPROPSP (p))
80237dcc 376 SETSRCPROPCOPY (p, datum);
575888bd 377 else
5c5549cb 378 SCM_WHASHSET (scm_source_whash, h, scm_make_srcprops (0, 0, SCM_UNDEFINED, datum, p));
575888bd
MD
379 }
380 else
58d233cc
NJ
381 {
382 if (SRCPROPSP (p))
67a96734 383 SETSRCPROPALIST (p, scm_acons (key, datum, SRCPROPALIST (p)));
58d233cc
NJ
384 else
385 SCM_WHASHSET (scm_source_whash, h, scm_acons (key, datum, p));
386 }
575888bd
MD
387 return SCM_UNSPECIFIED;
388}
1bbd0b84 389#undef FUNC_NAME
575888bd 390
1cc91f1b 391
575888bd
MD
392void
393scm_init_srcprop ()
575888bd 394{
e841c3e0
KN
395 scm_tc16_srcprops = scm_make_smob_type ("srcprops", 0);
396 scm_set_smob_mark (scm_tc16_srcprops, srcprops_mark);
e841c3e0
KN
397 scm_set_smob_print (scm_tc16_srcprops, srcprops_print);
398
e11e83f3 399 scm_source_whash = scm_make_weak_key_hash_table (scm_from_int (2047));
86d31dfe 400 scm_c_define ("source-whash", scm_source_whash);
85db4a2c 401
67a96734 402 scm_last_alist_filename
b0763985
HWN
403 = scm_permanent_object (scm_cons (SCM_EOL,
404 scm_acons (SCM_EOL, SCM_EOL, SCM_EOL)));
405
a0599745 406#include "libguile/srcprop.x"
575888bd
MD
407}
408
89e00824
ML
409
410/*
411 Local Variables:
412 c-file-style: "gnu"
413 End:
414*/