a very big commit cleaning up structs & goops. also applicable structs.
[bpt/guile.git] / libguile / procprop.c
1 /* Copyright (C) 1995,1996,1998,2000,2001,2003,2004, 2006, 2008, 2009 Free Software Foundation, Inc.
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 "libguile/_scm.h"
26
27 #include "libguile/alist.h"
28 #include "libguile/eval.h"
29 #include "libguile/procs.h"
30 #include "libguile/gsubr.h"
31 #include "libguile/smob.h"
32 #include "libguile/root.h"
33 #include "libguile/vectors.h"
34 #include "libguile/hashtab.h"
35 #include "libguile/programs.h"
36
37 #include "libguile/validate.h"
38 #include "libguile/procprop.h"
39 \f
40
41 SCM_GLOBAL_SYMBOL (scm_sym_system_procedure, "system-procedure");
42 SCM_GLOBAL_SYMBOL (scm_sym_arity, "arity");
43
44 static SCM non_closure_props;
45 static scm_i_pthread_mutex_t non_closure_props_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER;
46
47 SCM
48 scm_i_procedure_arity (SCM proc)
49 {
50 int a = 0, o = 0, r = 0;
51 if (SCM_IMP (proc))
52 return SCM_BOOL_F;
53 loop:
54 switch (SCM_TYP7 (proc))
55 {
56 case scm_tc7_subr_1o:
57 o = 1;
58 case scm_tc7_subr_0:
59 break;
60 case scm_tc7_subr_2o:
61 o = 1;
62 case scm_tc7_subr_1:
63 case scm_tc7_dsubr:
64 case scm_tc7_cxr:
65 a += 1;
66 break;
67 case scm_tc7_subr_2:
68 a += 2;
69 break;
70 case scm_tc7_subr_3:
71 a += 3;
72 break;
73 case scm_tc7_asubr:
74 case scm_tc7_rpsubr:
75 case scm_tc7_lsubr:
76 r = 1;
77 break;
78 case scm_tc7_program:
79 if (scm_i_program_arity (proc, &a, &o, &r))
80 break;
81 else
82 return SCM_BOOL_F;
83 case scm_tc7_lsubr_2:
84 a += 2;
85 r = 1;
86 break;
87 case scm_tc7_smob:
88 if (SCM_SMOB_APPLICABLE_P (proc))
89 {
90 int type = SCM_SMOB_DESCRIPTOR (proc).gsubr_type;
91 a += SCM_GSUBR_REQ (type);
92 o = SCM_GSUBR_OPT (type);
93 r = SCM_GSUBR_REST (type);
94 break;
95 }
96 else
97 {
98 return SCM_BOOL_F;
99 }
100 case scm_tc7_gsubr:
101 {
102 unsigned int type = SCM_GSUBR_TYPE (proc);
103 a = SCM_GSUBR_REQ (type);
104 o = SCM_GSUBR_OPT (type);
105 r = SCM_GSUBR_REST (type);
106 break;
107 }
108 case scm_tc7_pws:
109 proc = SCM_PROCEDURE (proc);
110 goto loop;
111 case scm_tcs_closures:
112 proc = SCM_CLOSURE_FORMALS (proc);
113 if (scm_is_null (proc))
114 break;
115 while (scm_is_pair (proc))
116 {
117 ++a;
118 proc = SCM_CDR (proc);
119 }
120 if (!scm_is_null (proc))
121 r = 1;
122 break;
123 case scm_tcs_struct:
124 if (SCM_OBJ_CLASS_FLAGS (proc) & SCM_CLASSF_PURE_GENERIC)
125 {
126 r = 1;
127 break;
128 }
129 else if (!SCM_STRUCT_APPLICABLE_P (proc))
130 return SCM_BOOL_F;
131 proc = SCM_STRUCT_PROCEDURE (proc);
132 goto loop;
133 default:
134 return SCM_BOOL_F;
135 }
136 return scm_list_3 (scm_from_int (a), scm_from_int (o), scm_from_bool(r));
137 }
138
139 /* FIXME: instead of the weak hash, perhaps for some kinds of procedures, use
140 other means; for example subrs have their own property slot, which is unused
141 at present. */
142
143 SCM_DEFINE (scm_procedure_properties, "procedure-properties", 1, 0, 0,
144 (SCM proc),
145 "Return @var{obj}'s property list.")
146 #define FUNC_NAME s_scm_procedure_properties
147 {
148 SCM props;
149
150 SCM_VALIDATE_PROC (1, proc);
151 if (SCM_CLOSUREP (proc))
152 props = SCM_PROCPROPS (proc);
153 else
154 {
155 scm_i_pthread_mutex_lock (&non_closure_props_lock);
156 props = scm_hashq_ref (non_closure_props, proc, SCM_EOL);
157 scm_i_pthread_mutex_unlock (&non_closure_props_lock);
158 }
159 return scm_acons (scm_sym_arity, scm_i_procedure_arity (proc), props);
160 }
161 #undef FUNC_NAME
162
163 SCM_DEFINE (scm_set_procedure_properties_x, "set-procedure-properties!", 2, 0, 0,
164 (SCM proc, SCM alist),
165 "Set @var{proc}'s property list to @var{alist}.")
166 #define FUNC_NAME s_scm_set_procedure_properties_x
167 {
168 SCM_VALIDATE_PROC (1, proc);
169
170 if (SCM_CLOSUREP (proc))
171 SCM_SETPROCPROPS (proc, alist);
172 else
173 {
174 scm_i_pthread_mutex_lock (&non_closure_props_lock);
175 scm_hashq_set_x (non_closure_props, proc, alist);
176 scm_i_pthread_mutex_unlock (&non_closure_props_lock);
177 }
178 return SCM_UNSPECIFIED;
179 }
180 #undef FUNC_NAME
181
182 SCM_DEFINE (scm_procedure_property, "procedure-property", 2, 0, 0,
183 (SCM proc, SCM key),
184 "Return the property of @var{proc} with name @var{key}.")
185 #define FUNC_NAME s_scm_procedure_property
186 {
187 SCM_VALIDATE_PROC (1, proc);
188
189 if (scm_is_eq (key, scm_sym_arity))
190 /* avoid a cons in this case */
191 return scm_i_procedure_arity (proc);
192 else
193 {
194 SCM props;
195 if (SCM_CLOSUREP (proc))
196 props = SCM_PROCPROPS (proc);
197 else
198 {
199 scm_i_pthread_mutex_lock (&non_closure_props_lock);
200 props = scm_hashq_ref (non_closure_props, proc, SCM_EOL);
201 scm_i_pthread_mutex_unlock (&non_closure_props_lock);
202 }
203 return scm_assq_ref (props, key);
204 }
205 }
206 #undef FUNC_NAME
207
208 SCM_DEFINE (scm_set_procedure_property_x, "set-procedure-property!", 3, 0, 0,
209 (SCM proc, SCM key, SCM val),
210 "In @var{proc}'s property list, set the property named @var{key} to\n"
211 "@var{val}.")
212 #define FUNC_NAME s_scm_set_procedure_property_x
213 {
214 SCM_VALIDATE_PROC (1, proc);
215
216 if (scm_is_eq (key, scm_sym_arity))
217 SCM_MISC_ERROR ("arity is a read-only property", SCM_EOL);
218
219 if (SCM_CLOSUREP (proc))
220 SCM_SETPROCPROPS (proc,
221 scm_assq_set_x (SCM_PROCPROPS (proc), key, val));
222 else
223 {
224 scm_i_pthread_mutex_lock (&non_closure_props_lock);
225 scm_hashq_set_x (non_closure_props, proc,
226 scm_assq_set_x (scm_hashq_ref (non_closure_props, proc,
227 SCM_EOL),
228 key, val));
229 scm_i_pthread_mutex_unlock (&non_closure_props_lock);
230 }
231
232 return SCM_UNSPECIFIED;
233 }
234 #undef FUNC_NAME
235
236 \f
237
238
239 void
240 scm_init_procprop ()
241 {
242 non_closure_props = scm_make_weak_key_hash_table (SCM_UNDEFINED);
243 #include "libguile/procprop.x"
244 }
245
246
247 /*
248 Local Variables:
249 c-file-style: "gnu"
250 End:
251 */