Rewording for "make an intervention".
[bpt/guile.git] / libguile / srcprop.c
1 /* Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002, 2006, 2008, 2009, 2010 Free Software Foundation
2 *
3 * This library is free software; you can redistribute it and/or
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.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
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
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
17 */
18
19
20 \f
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include <errno.h>
26
27 #include "libguile/_scm.h"
28 #include "libguile/async.h"
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"
37 #include "libguile/gc.h"
38
39 #include "libguile/validate.h"
40 #include "libguile/srcprop.h"
41 \f
42 /* {Source Properties}
43 *
44 * Properties of source list expressions.
45 * Four of these have special meaning:
46 *
47 * filename string The name of the source file.
48 * copy list A copy of the list expression.
49 * line integer The source code line number.
50 * column integer The source code column number.
51 *
52 * Most properties above can be set by the reader.
53 *
54 */
55
56 SCM_GLOBAL_SYMBOL (scm_sym_filename, "filename");
57 SCM_GLOBAL_SYMBOL (scm_sym_copy, "copy");
58 SCM_GLOBAL_SYMBOL (scm_sym_line, "line");
59 SCM_GLOBAL_SYMBOL (scm_sym_column, "column");
60 SCM scm_source_whash;
61
62
63
64 /*
65 * Source properties are stored as double cells with the
66 * following layout:
67
68 * car = tag
69 * cbr = pos
70 * ccr = copy
71 * cdr = alist
72 */
73
74 #define SRCPROPSP(p) (SCM_SMOB_PREDICATE (scm_tc16_srcprops, (p)))
75 #define SRCPROPPOS(p) (SCM_SMOB_DATA(p))
76 #define SRCPROPLINE(p) (SRCPROPPOS(p) >> 12)
77 #define SRCPROPCOL(p) (SRCPROPPOS(p) & 0x0fffL)
78 #define SRCPROPCOPY(p) (SCM_SMOB_OBJECT_2(p))
79 #define SRCPROPALIST(p) (SCM_SMOB_OBJECT_3(p))
80 #define SRCPROPMAKPOS(l, c) (((l) << 12) + (c))
81 #define SETSRCPROPPOS(p, l, c) (SCM_SET_SMOB_DATA_1 (p, SRCPROPMAKPOS (l, c)))
82 #define SETSRCPROPLINE(p, l) SETSRCPROPPOS (p, l, SRCPROPCOL (p))
83 #define SETSRCPROPCOL(p, c) SETSRCPROPPOS (p, SRCPROPLINE (p), c)
84 #define SETSRCPROPCOPY(p, c) (SCM_SET_SMOB_OBJECT_2 (p, c))
85 #define SETSRCPROPALIST(p, l) (SCM_SET_SMOB_OBJECT_3 (p, l))
86
87
88 static SCM scm_srcprops_to_alist (SCM obj);
89
90
91 scm_t_bits scm_tc16_srcprops;
92
93 static int
94 srcprops_print (SCM obj, SCM port, scm_print_state *pstate)
95 {
96 int writingp = SCM_WRITINGP (pstate);
97 scm_puts ("#<srcprops ", port);
98 SCM_SET_WRITINGP (pstate, 1);
99 scm_iprin1 (scm_srcprops_to_alist (obj), port, pstate);
100 SCM_SET_WRITINGP (pstate, writingp);
101 scm_putc ('>', port);
102 return 1;
103 }
104
105
106 /*
107 * We remember the last file name settings, so we can share that alist
108 * entry. This works because scm_set_source_property_x does not use
109 * assoc-set! for modifying the alist.
110 *
111 * This variable contains a protected cons, whose cdr is the cached
112 * alist
113 */
114 static SCM scm_last_alist_filename;
115
116 SCM
117 scm_make_srcprops (long line, int col, SCM filename, SCM copy, SCM alist)
118 {
119 if (!SCM_UNBNDP (filename))
120 {
121 SCM old_alist = alist;
122
123 /*
124 have to extract the acons, and operate on that, for
125 thread safety.
126 */
127 SCM last_acons = SCM_CDR (scm_last_alist_filename);
128 if (old_alist == SCM_EOL
129 && SCM_CDAR (last_acons) == filename)
130 {
131 alist = last_acons;
132 }
133 else
134 {
135 alist = scm_acons (scm_sym_filename, filename, alist);
136 if (old_alist == SCM_EOL)
137 SCM_SETCDR (scm_last_alist_filename, alist);
138 }
139 }
140
141 SCM_RETURN_NEWSMOB3 (scm_tc16_srcprops,
142 SRCPROPMAKPOS (line, col),
143 copy,
144 alist);
145 }
146
147
148 static SCM
149 scm_srcprops_to_alist (SCM obj)
150 {
151 SCM alist = SRCPROPALIST (obj);
152 if (!SCM_UNBNDP (SRCPROPCOPY (obj)))
153 alist = scm_acons (scm_sym_copy, SRCPROPCOPY (obj), alist);
154 alist = scm_acons (scm_sym_column, scm_from_int (SRCPROPCOL (obj)), alist);
155 alist = scm_acons (scm_sym_line, scm_from_int (SRCPROPLINE (obj)), alist);
156 return alist;
157 }
158
159 SCM_DEFINE (scm_source_properties, "source-properties", 1, 0, 0,
160 (SCM obj),
161 "Return the source property association list of @var{obj}.")
162 #define FUNC_NAME s_scm_source_properties
163 {
164 SCM p;
165 SCM_VALIDATE_NIM (1, obj);
166 p = scm_hashq_ref (scm_source_whash, obj, SCM_EOL);
167 if (SRCPROPSP (p))
168 return scm_srcprops_to_alist (p);
169 else
170 /* list from set-source-properties!, or SCM_EOL for not found */
171 return p;
172 }
173 #undef FUNC_NAME
174
175 /* Perhaps this procedure should look through an alist
176 and try to make a srcprops-object...? */
177 SCM_DEFINE (scm_set_source_properties_x, "set-source-properties!", 2, 0, 0,
178 (SCM obj, SCM alist),
179 "Install the association list @var{alist} as the source property\n"
180 "list for @var{obj}.")
181 #define FUNC_NAME s_scm_set_source_properties_x
182 {
183 SCM handle;
184 SCM_VALIDATE_NIM (1, obj);
185 handle = scm_hashq_create_handle_x (scm_source_whash, obj, alist);
186 SCM_SETCDR (handle, alist);
187 return alist;
188 }
189 #undef FUNC_NAME
190
191 SCM_DEFINE (scm_source_property, "source-property", 2, 0, 0,
192 (SCM obj, SCM key),
193 "Return the source property specified by @var{key} from\n"
194 "@var{obj}'s source property list.")
195 #define FUNC_NAME s_scm_source_property
196 {
197 SCM p;
198 SCM_VALIDATE_NIM (1, obj);
199 p = scm_hashq_ref (scm_source_whash, obj, SCM_EOL);
200 if (!SRCPROPSP (p))
201 goto alist;
202 if (scm_is_eq (scm_sym_line, key))
203 p = scm_from_int (SRCPROPLINE (p));
204 else if (scm_is_eq (scm_sym_column, key))
205 p = scm_from_int (SRCPROPCOL (p));
206 else if (scm_is_eq (scm_sym_copy, key))
207 p = SRCPROPCOPY (p);
208 else
209 {
210 p = SRCPROPALIST (p);
211 alist:
212 p = scm_assoc (key, p);
213 return (SCM_NIMP (p) ? SCM_CDR (p) : SCM_BOOL_F);
214 }
215 return SCM_UNBNDP (p) ? SCM_BOOL_F : p;
216 }
217 #undef FUNC_NAME
218
219 SCM_DEFINE (scm_set_source_property_x, "set-source-property!", 3, 0, 0,
220 (SCM obj, SCM key, SCM datum),
221 "Set the source property of object @var{obj}, which is specified by\n"
222 "@var{key} to @var{datum}. Normally, the key will be a symbol.")
223 #define FUNC_NAME s_scm_set_source_property_x
224 {
225 scm_whash_handle h;
226 SCM p;
227 SCM_VALIDATE_NIM (1, obj);
228 h = scm_whash_get_handle (scm_source_whash, obj);
229 if (SCM_WHASHFOUNDP (h))
230 p = SCM_WHASHREF (scm_source_whash, h);
231 else
232 {
233 h = scm_whash_create_handle (scm_source_whash, obj);
234 p = SCM_EOL;
235 }
236
237 if (scm_is_eq (scm_sym_line, key))
238 {
239 if (SRCPROPSP (p))
240 SETSRCPROPLINE (p, scm_to_int (datum));
241 else
242 SCM_WHASHSET (scm_source_whash, h,
243 scm_make_srcprops (scm_to_int (datum), 0,
244 SCM_UNDEFINED, SCM_UNDEFINED, p));
245 }
246 else if (scm_is_eq (scm_sym_column, key))
247 {
248 if (SRCPROPSP (p))
249 SETSRCPROPCOL (p, scm_to_int (datum));
250 else
251 SCM_WHASHSET (scm_source_whash, h,
252 scm_make_srcprops (0, scm_to_int (datum),
253 SCM_UNDEFINED, SCM_UNDEFINED, p));
254 }
255 else if (scm_is_eq (scm_sym_copy, key))
256 {
257 if (SRCPROPSP (p))
258 SETSRCPROPCOPY (p, datum);
259 else
260 SCM_WHASHSET (scm_source_whash, h, scm_make_srcprops (0, 0, SCM_UNDEFINED, datum, p));
261 }
262 else
263 {
264 if (SRCPROPSP (p))
265 SETSRCPROPALIST (p, scm_acons (key, datum, SRCPROPALIST (p)));
266 else
267 SCM_WHASHSET (scm_source_whash, h, scm_acons (key, datum, p));
268 }
269 return SCM_UNSPECIFIED;
270 }
271 #undef FUNC_NAME
272
273
274 SCM_DEFINE (scm_cons_source, "cons-source", 3, 0, 0,
275 (SCM xorig, SCM x, SCM y),
276 "Create and return a new pair whose car and cdr are @var{x} and @var{y}.\n"
277 "Any source properties associated with @var{xorig} are also associated\n"
278 "with the new pair.")
279 #define FUNC_NAME s_scm_cons_source
280 {
281 SCM p, z;
282 z = scm_cons (x, y);
283 /* Copy source properties possibly associated with xorig. */
284 p = scm_whash_lookup (scm_source_whash, xorig);
285 if (scm_is_true (p))
286 scm_whash_insert (scm_source_whash, z, p);
287 return z;
288 }
289 #undef FUNC_NAME
290
291
292 void
293 scm_init_srcprop ()
294 {
295 scm_tc16_srcprops = scm_make_smob_type ("srcprops", 0);
296 scm_set_smob_print (scm_tc16_srcprops, srcprops_print);
297
298 scm_source_whash = scm_make_weak_key_hash_table (scm_from_int (2047));
299 scm_c_define ("source-whash", scm_source_whash);
300
301 scm_last_alist_filename = scm_cons (SCM_EOL,
302 scm_acons (SCM_EOL, SCM_EOL, SCM_EOL));
303
304 #include "libguile/srcprop.x"
305 }
306
307
308 /*
309 Local Variables:
310 c-file-style: "gnu"
311 End:
312 */