CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

| Download

GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it

Path: gap4r8 / src / gvars.c
Views: 418346
1
/****************************************************************************
2
**
3
*W gvars.c GAP source Martin Schönert
4
**
5
**
6
*Y Copyright (C) 1996, Lehrstuhl D für Mathematik, RWTH Aachen, Germany
7
*Y (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland
8
*Y Copyright (C) 2002 The GAP Group
9
**
10
** This file contains the functions of the global variables package.
11
**
12
** The global variables package is the part of the kernel that manages
13
** global variables, i.e., the global namespace. A global variable binds an
14
** identifier to a value.
15
**
16
** A global variable can be automatic. That means that the global variable
17
** binds the identifier to a function and an argument. When the value of
18
** the global variable is needed, the function is called with the argument.
19
** This function call should, as a side-effect, execute an assignment of a
20
** value to the global variable, otherwise an error is signalled.
21
**
22
** A global variable can have a number of internal copies, i.e., C variables
23
** that always reference the same value as the global variable.
24
** It can also have a special type of internal copy (a fopy) only used for
25
** functions, where the internal copies
26
** only reference the same value as the global variable if it is a function.
27
** Otherwise the internal copies reference functions that signal an error.
28
*/
29
#include "system.h" /* Ints, UInts */
30
31
32
#include "gasman.h" /* garbage collector */
33
#include "objects.h" /* objects */
34
35
#include "scanner.h" /* scanner */
36
37
#include "gap.h" /* error handling, initialisation */
38
39
#include "code.h" /* coder */
40
41
#include "gvars.h" /* global variables */
42
43
#include "calls.h" /* generic call mechanism */
44
45
#include "records.h" /* generic records */
46
#include "precord.h" /* plain records */
47
48
#include "lists.h" /* generic lists */
49
50
#include "plist.h" /* plain lists */
51
#include "string.h" /* strings */
52
53
#include "bool.h" /* booleans */
54
55
#include "tls.h" /* thread-local storage */
56
#include "thread.h" /* threads */
57
#include "aobjects.h" /* atomic objects */
58
59
/****************************************************************************
60
**
61
*V ValGVars . . . . . . . . . . . . . . . . . . values of global variables
62
*V PtrGVars . . . . . . . . . . . . . pointer to values of global variables
63
**
64
** 'ValGVars' is the bag containing the values of the global variables.
65
**
66
** 'PtrGVars' is a pointer to the 'ValGVars' bag. This makes it faster to
67
** access global variables.
68
**
69
** Since a garbage collection may move this bag around, the pointer
70
** 'PtrGVars' must be revalculated afterwards. This should be done by a
71
** function in this package, but is still done in 'VarsAfterCollectBags'.
72
*/
73
Obj ValGVars;
74
75
Obj * PtrGVars;
76
77
78
/****************************************************************************
79
**
80
*F VAL_GVAR(<gvar>) . . . . . . . . . . . . . . . value of global variable
81
**
82
** 'VAL_GVAR' returns the value of the global variable <gvar>. If <gvar>
83
** has no assigned value, 'VAL_GVAR' returns 0. In this case <gvar> might
84
** be an automatic global variable, and one should call 'ValAutoGVar', which
85
** will return the value of <gvar> after evaluating <gvar>-s expression, or
86
** 0 if <gvar> was not an automatic variable.
87
**
88
** 'VAL_GVAR' is defined in the declaration part of this package as follows
89
**
90
#define VAL_GVAR(gvar) PtrGVars[ (gvar) ]
91
*/
92
93
94
/****************************************************************************
95
**
96
*V NameGVars . . . . . . . . . . . . . . . . . . . names of global variables
97
*V WriteGVars . . . . . . . . . . . . . writable flags of global variables
98
*V ExprGVars . . . . . . . . . . expressions for automatic global variables
99
*V CopiesGVars . . . . . . . . . . . . . internal copies of global variables
100
*V FopiesGVars . . . . . . . . internal function copies of global variables
101
*V CountGVars . . . . . . . . . . . . . . . . . number of global variables
102
*/
103
Obj NameGVars;
104
Obj WriteGVars;
105
Obj ExprGVars;
106
Obj CopiesGVars;
107
Obj FopiesGVars;
108
UInt CountGVars;
109
110
111
/****************************************************************************
112
**
113
*V TableGVars . . . . . . . . . . . . . . hashed table of global variables
114
*V SizeGVars . . . . . . . current size of hashed table of global variables
115
*/
116
Obj TableGVars;
117
UInt SizeGVars;
118
119
120
/****************************************************************************
121
**
122
*V ErrorMustEvalToFuncFunc . . . . . . . . . function that signals an error
123
*F ErrorMustEvalToFuncHandler(<self>,<args>) . handler that signals an error
124
**
125
** 'ErrorMustEvalToFuncFunc' is a (variable number of args) function that
126
** signals the error ``Function: <func> be a function''.
127
**
128
** 'ErrorMustEvalToFuncHandler' is the handler that signals the error
129
** ``Function: <func> must be a function''.
130
*/
131
Obj ErrorMustEvalToFuncFunc;
132
133
Obj ErrorMustEvalToFuncHandler (
134
Obj self,
135
Obj args )
136
{
137
ErrorQuit(
138
"Function Calls: <func> must be a function",
139
0L, 0L );
140
return 0;
141
}
142
143
144
/****************************************************************************
145
**
146
*V ErrorMustHaveAssObjFunc . . . . . . . . . function that signals an error
147
*F ErrorMustHaveAssObjHandler(<self>,<args>) . handler that signals an error
148
**
149
** 'ErrorMustHaveAssObjFunc' is a (variable number of args) function that
150
** signals the error ``Variable: <<unknown>> must have an assigned value''.
151
**
152
** 'ErrorMustHaveAssObjHandler' is the handler that signals the error
153
** ``Variable: <<unknown>> must have an assigned value''.
154
*/
155
Obj ErrorMustHaveAssObjFunc;
156
157
Obj ErrorMustHaveAssObjHandler (
158
Obj self,
159
Obj args )
160
{
161
ErrorQuit(
162
"Variable: <<unknown>> must have an assigned value",
163
0L, 0L );
164
return 0;
165
}
166
167
168
/****************************************************************************
169
**
170
*F AssGVar(<gvar>,<val>) . . . . . . . . . . . . assign to a global variable
171
**
172
** 'AssGVar' assigns the value <val> to the global variable <gvar>.
173
*/
174
175
static Obj REREADING; /* Copy of GAP global variable REREADING */
176
177
void AssGVar (
178
UInt gvar,
179
Obj val )
180
{
181
Obj cops; /* list of internal copies */
182
Obj * copy; /* one copy */
183
UInt i; /* loop variable */
184
Obj onam; /* object of <name> */
185
186
/* make certain that the variable is not read only */
187
while ( (REREADING != True) &&
188
(ELM_PLIST( WriteGVars, gvar ) == INTOBJ_INT(0)) ) {
189
ErrorReturnVoid(
190
"Variable: '%s' is read only",
191
(Int)CSTR_STRING( ELM_PLIST(NameGVars,gvar) ), 0L,
192
"you can 'return;' after making it writable" );
193
}
194
195
/* assign the value to the global variable */
196
VAL_GVAR(gvar) = val;
197
CHANGED_BAG( ValGVars );
198
199
/* if the global variable was automatic, convert it to normal */
200
SET_ELM_PLIST( ExprGVars, gvar, 0 );
201
202
/* assign the value to all the internal copies */
203
cops = ELM_PLIST( CopiesGVars, gvar );
204
if ( cops != 0 ) {
205
for ( i = 1; i <= LEN_PLIST(cops); i++ ) {
206
copy = (Obj*) ELM_PLIST(cops,i);
207
*copy = val;
208
}
209
}
210
211
/* if the value is a function, assign it to all the internal fopies */
212
cops = ELM_PLIST( FopiesGVars, gvar );
213
if ( cops != 0 && val != 0 && TNUM_OBJ(val) == T_FUNCTION ) {
214
for ( i = 1; i <= LEN_PLIST(cops); i++ ) {
215
copy = (Obj*) ELM_PLIST(cops,i);
216
*copy = val;
217
}
218
}
219
220
/* if the values is not a function, assign the error function */
221
else if ( cops != 0 && val != 0 /* && TNUM_OBJ(val) != T_FUNCTION */ ) {
222
for ( i = 1; i <= LEN_PLIST(cops); i++ ) {
223
copy = (Obj*) ELM_PLIST(cops,i);
224
*copy = ErrorMustEvalToFuncFunc;
225
}
226
}
227
228
/* if this was an unbind, assign the other error function */
229
else if ( cops != 0 /* && val == 0 */ ) {
230
for ( i = 1; i <= LEN_PLIST(cops); i++ ) {
231
copy = (Obj*) ELM_PLIST(cops,i);
232
*copy = ErrorMustHaveAssObjFunc;
233
}
234
}
235
236
/* assign name to a function */
237
if ( val != 0 && TNUM_OBJ(val) == T_FUNCTION && NAME_FUNC(val) == 0 ) {
238
onam = CopyToStringRep(NameGVarObj(gvar));
239
RESET_FILT_LIST( onam, FN_IS_MUTABLE );
240
NAME_FUNC(val) = onam;
241
CHANGED_BAG(val);
242
}
243
}
244
245
246
/****************************************************************************
247
**
248
*F ValAutoGVar(<gvar>) . . . . . . . . value of a automatic global variable
249
**
250
** 'ValAutoGVar' returns the value of the global variable <gvar>. This will
251
** be 0 if <gvar> has no assigned value. It will also cause a function
252
** call, if <gvar> is automatic.
253
*/
254
Obj ValAutoGVar (
255
UInt gvar )
256
{
257
Obj func; /* function to call for automatic */
258
Obj arg; /* argument to pass for automatic */
259
260
/* if this is an automatic variable, make the function call */
261
if ( VAL_GVAR(gvar) == 0 && ELM_PLIST( ExprGVars, gvar ) != 0 ) {
262
263
/* make the function call */
264
func = ELM_PLIST( ELM_PLIST( ExprGVars, gvar ), 1 );
265
arg = ELM_PLIST( ELM_PLIST( ExprGVars, gvar ), 2 );
266
CALL_1ARGS( func, arg );
267
268
/* if this is still an automatic variable, this is an error */
269
while ( VAL_GVAR(gvar) == 0 ) {
270
ErrorReturnVoid(
271
"Variable: automatic variable '%s' must get a value by function call",
272
(Int)CSTR_STRING( ELM_PLIST(NameGVars,gvar) ), 0L,
273
"you can 'return;' after assigning a value" );
274
}
275
276
}
277
278
/* return the value */
279
return VAL_GVAR(gvar);
280
}
281
282
283
/****************************************************************************
284
**
285
*F NameGVar(<gvar>) . . . . . . . . . . . . . . . name of a global variable
286
**
287
** 'NameGVar' returns the name of the global variable <gvar> as a C string.
288
*/
289
Char * NameGVar (
290
UInt gvar )
291
{
292
return CSTR_STRING( ELM_PLIST( NameGVars, gvar ) );
293
}
294
295
Obj NameGVarObj ( UInt gvar )
296
{
297
return ELM_PLIST( NameGVars, gvar );
298
}
299
300
#define NSCHAR '@'
301
302
Obj CurrNamespace = 0;
303
304
Obj FuncSET_NAMESPACE(Obj self, Obj str)
305
{
306
TLS(CurrNamespace) = str;
307
return 0;
308
}
309
310
Obj FuncGET_NAMESPACE(Obj self)
311
{
312
return TLS(CurrNamespace);
313
}
314
315
/****************************************************************************
316
**
317
*F GVarName(<name>) . . . . . . . . . . . . . . global variable for a name
318
**
319
** 'GVarName' returns the global variable with the name <name>.
320
*/
321
UInt GVarName (
322
const Char * name )
323
{
324
Obj gvar; /* global variable (as imm intval) */
325
Char gvarbuf[1024]; /* temporary copy for namespace */
326
Char * cns; /* Pointer to current namespace */
327
UInt pos; /* hash position */
328
Char namx [1024]; /* temporary copy of <name> */
329
Obj string; /* temporary string value <name> */
330
Obj table; /* temporary copy of <TableGVars> */
331
Obj gvar2; /* one element of <table> */
332
const Char * p; /* loop variable */
333
UInt i; /* loop variable */
334
Int len; /* length of name */
335
336
/* First see whether it could be namespace-local: */
337
cns = CSTR_STRING(TLS(CurrNamespace));
338
if (*cns) { /* only if a namespace is set */
339
len = strlen(name);
340
if (name[len-1] == NSCHAR) {
341
strlcpy(gvarbuf, name, 512);
342
strlcat(gvarbuf, cns, sizeof(gvarbuf));
343
name = gvarbuf;
344
}
345
}
346
347
/* start looking in the table at the following hash position */
348
pos = 0;
349
for ( p = name; *p != '\0'; p++ ) {
350
pos = 65599 * pos + *p;
351
}
352
pos = (pos % SizeGVars) + 1;
353
354
/* look through the table until we find a free slot or the global */
355
while ( (gvar = ELM_PLIST( TableGVars, pos )) != 0
356
&& strncmp( NameGVar( INT_INTOBJ(gvar) ), name, 1023 ) ) {
357
pos = (pos % SizeGVars) + 1;
358
}
359
360
/* if we did not find the global variable, make a new one and enter it */
361
/* (copy the name first, to avoid a stale pointer in case of a GC) */
362
if ( gvar == 0 ) {
363
CountGVars++;
364
gvar = INTOBJ_INT(CountGVars);
365
SET_ELM_PLIST( TableGVars, pos, gvar );
366
strlcpy(namx, name, sizeof(namx));
367
C_NEW_STRING_DYN(string, namx);
368
369
RESET_FILT_LIST( string, FN_IS_MUTABLE );
370
GROW_PLIST( ValGVars, CountGVars );
371
SET_LEN_PLIST( ValGVars, CountGVars );
372
SET_ELM_PLIST( ValGVars, CountGVars, 0 );
373
GROW_PLIST( NameGVars, CountGVars );
374
SET_LEN_PLIST( NameGVars, CountGVars );
375
SET_ELM_PLIST( NameGVars, CountGVars, string );
376
CHANGED_BAG( NameGVars );
377
GROW_PLIST( WriteGVars, CountGVars );
378
SET_LEN_PLIST( WriteGVars, CountGVars );
379
SET_ELM_PLIST( WriteGVars, CountGVars, INTOBJ_INT(1) );
380
GROW_PLIST( ExprGVars, CountGVars );
381
SET_LEN_PLIST( ExprGVars, CountGVars );
382
SET_ELM_PLIST( ExprGVars, CountGVars, 0 );
383
GROW_PLIST( CopiesGVars, CountGVars );
384
SET_LEN_PLIST( CopiesGVars, CountGVars );
385
SET_ELM_PLIST( CopiesGVars, CountGVars, 0 );
386
GROW_PLIST( FopiesGVars, CountGVars );
387
SET_LEN_PLIST( FopiesGVars, CountGVars );
388
SET_ELM_PLIST( FopiesGVars, CountGVars, 0 );
389
PtrGVars = ADDR_OBJ( ValGVars );
390
}
391
392
/* if the table is too crowed, make a larger one, rehash the names */
393
if ( SizeGVars < 3 * CountGVars / 2 ) {
394
table = TableGVars;
395
SizeGVars = 2 * SizeGVars + 1;
396
TableGVars = NEW_PLIST( T_PLIST, SizeGVars );
397
SET_LEN_PLIST( TableGVars, SizeGVars );
398
for ( i = 1; i <= (SizeGVars-1)/2; i++ ) {
399
gvar2 = ELM_PLIST( table, i );
400
if ( gvar2 == 0 ) continue;
401
pos = 0;
402
for ( p = NameGVar( INT_INTOBJ(gvar2) ); *p != '\0'; p++ ) {
403
pos = 65599 * pos + *p;
404
}
405
pos = (pos % SizeGVars) + 1;
406
while ( ELM_PLIST( TableGVars, pos ) != 0 ) {
407
pos = (pos % SizeGVars) + 1;
408
}
409
SET_ELM_PLIST( TableGVars, pos, gvar2 );
410
}
411
}
412
413
/* return the global variable */
414
return INT_INTOBJ(gvar);
415
}
416
417
/****************************************************************************
418
**
419
420
*V Tilde . . . . . . . . . . . . . . . . . . . . . . . . global variable '~'
421
**
422
** 'Tilde' is the global variable '~', the one used in expressions such as
423
** '[ [ 1, 2 ], ~[1] ]'.
424
**
425
** Actually when such expressions appear in functions, one should probably
426
** use a local variable. But for now this is good enough.
427
*/
428
UInt Tilde;
429
430
431
/****************************************************************************
432
**
433
*F MakeReadOnlyGVar( <gvar> ) . . . . . . make a global variable read only
434
*/
435
void MakeReadOnlyGVar (
436
UInt gvar )
437
{
438
SET_ELM_PLIST( WriteGVars, gvar, INTOBJ_INT(0) );
439
CHANGED_BAG(WriteGVars)
440
}
441
442
443
/****************************************************************************
444
**
445
*F MakeReadOnlyGVarHandler(<self>,<name>) make a global variable read only
446
**
447
** 'MakeReadOnlyGVarHandler' implements the function 'MakeReadOnlyGVar'.
448
**
449
** 'MakeReadOnlyGVar( <name> )'
450
**
451
** 'MakeReadOnlyGVar' make the global variable with the name <name> (which
452
** must be a GAP string) read only.
453
*/
454
Obj MakeReadOnlyGVarHandler (
455
Obj self,
456
Obj name )
457
{
458
/* check the argument */
459
while ( ! IsStringConv( name ) ) {
460
name = ErrorReturnObj(
461
"MakeReadOnlyGVar: <name> must be a string (not a %s)",
462
(Int)TNAM_OBJ(name), 0L,
463
"you can return a string for <name>" );
464
}
465
466
/* get the variable and make it read only */
467
MakeReadOnlyGVar(GVarName(CSTR_STRING(name)));
468
469
/* return void */
470
return 0;
471
}
472
473
474
/****************************************************************************
475
**
476
*F MakeReadWriteGVar( <gvar> ) . . . . . . make a global variable read write
477
*/
478
void MakeReadWriteGVar (
479
UInt gvar )
480
{
481
SET_ELM_PLIST( WriteGVars, gvar, INTOBJ_INT(1) );
482
CHANGED_BAG(WriteGVars)
483
}
484
485
486
/****************************************************************************
487
**
488
*F MakeReadWriteGVarHandler(<self>,<name>) make a global variable read write
489
**
490
** 'MakeReadWriteGVarHandler' implements the function 'MakeReadWriteGVar'.
491
**
492
** 'MakeReadWriteGVar( <name> )'
493
**
494
** 'MakeReadWriteGVar' make the global variable with the name <name> (which
495
** must be a GAP string) read and writable.
496
*/
497
Obj MakeReadWriteGVarHandler (
498
Obj self,
499
Obj name )
500
{
501
/* check the argument */
502
while ( ! IsStringConv( name ) ) {
503
name = ErrorReturnObj(
504
"MakeReadWriteGVar: <name> must be a string (not a %s)",
505
(Int)TNAM_OBJ(name), 0L,
506
"you can return a string for <name>" );
507
}
508
509
/* get the variable and make it read write */
510
MakeReadWriteGVar(GVarName(CSTR_STRING(name)));
511
512
/* return void */
513
return 0;
514
}
515
516
/****************************************************************************
517
**
518
*F IsReadOnlyGVar( <gvar> ) . . . . . . return status of a global variable
519
*/
520
Int IsReadOnlyGVar (
521
UInt gvar )
522
{
523
return !INT_INTOBJ(ELM_PLIST(WriteGVars, gvar));
524
}
525
526
527
/****************************************************************************
528
**
529
*F FuncIsReadOnlyGVar( <name> ) . . .handler for GAP function
530
**
531
*/
532
533
static Obj FuncIsReadOnlyGVar (
534
Obj self,
535
Obj name )
536
{
537
/* check the argument */
538
while ( ! IsStringConv( name ) ) {
539
name = ErrorReturnObj(
540
"IsReadOnlyGVar: <name> must be a string (not a %s)",
541
(Int)TNAM_OBJ(name), 0L,
542
"you can return a string for <name>" );
543
}
544
545
/* get the answer */
546
return IsReadOnlyGVar(GVarName(CSTR_STRING(name))) ? True : False;
547
}
548
549
550
/****************************************************************************
551
**
552
*F AUTOHandler() . . . . . . . . . . . . . make automatic global variables
553
**
554
** 'AUTOHandler' implements the internal function 'AUTO'.
555
**
556
** 'AUTO( <func>, <arg>, <name1>, ... )'
557
**
558
** 'AUTO' makes the global variables, whose names are given the strings
559
** <name1>, <name2>, ..., automatic. That means that when the value of one
560
** of those global variables is requested, then the function <func> is
561
** called and the argument <arg> is passed. This function call should,
562
** cause the execution of an assignment to that global variable, otherwise
563
** an error is signalled.
564
*/
565
Obj AUTOFunc;
566
567
Obj AUTOHandler (
568
Obj self,
569
Obj args )
570
{
571
Obj func; /* the function to call */
572
Obj arg; /* the argument to pass */
573
Obj list; /* function and argument list */
574
Obj name; /* one name (as a GAP string) */
575
UInt gvar; /* one global variable */
576
UInt i; /* loop variable */
577
578
/* check that there are enough arguments */
579
if ( LEN_LIST(args) < 2 ) {
580
ErrorQuit(
581
"usage: AUTO( <func>, <arg>, <name1>... )",
582
0L, 0L );
583
return 0;
584
}
585
586
/* get and check the function */
587
func = ELM_LIST( args, 1 );
588
while ( TNUM_OBJ(func) != T_FUNCTION ) {
589
func = ErrorReturnObj(
590
"AUTO: <func> must be a function (not a %s)",
591
(Int)TNAM_OBJ(func), 0L,
592
"you can return a function for <func>" );
593
}
594
595
/* get the argument */
596
arg = ELM_LIST( args, 2 );
597
598
/* make the list of function and argument */
599
list = NEW_PLIST( T_PLIST, 2 );
600
SET_LEN_PLIST( list, 2 );
601
SET_ELM_PLIST( list, 1, func );
602
SET_ELM_PLIST( list, 2, arg );
603
604
/* make the global variables automatic */
605
for ( i = 3; i <= LEN_LIST(args); i++ ) {
606
name = ELM_LIST( args, i );
607
while ( ! IsStringConv(name) ) {
608
name = ErrorReturnObj(
609
"AUTO: <name> must be a string (not a %s)",
610
(Int)TNAM_OBJ(name), 0L,
611
"you can return a string for <name>" );
612
}
613
gvar = GVarName( CSTR_STRING(name) );
614
SET_ELM_PLIST( ValGVars, gvar, 0 );
615
SET_ELM_PLIST( ExprGVars, gvar, list );
616
CHANGED_BAG( ExprGVars );
617
}
618
619
/* return void */
620
return 0;
621
}
622
623
624
/****************************************************************************
625
**
626
*F iscomplete( <name>, <len> ) . . . . . . . . find the completions of name
627
*F completion( <name>, <len> ) . . . . . . . . find the completions of name
628
*/
629
UInt iscomplete_gvar (
630
Char * name,
631
UInt len )
632
{
633
Char * curr;
634
UInt i, k;
635
636
for ( i = 1; i <= CountGVars; i++ ) {
637
curr = NameGVar( i );
638
for ( k = 0; name[k] != 0 && curr[k] == name[k]; k++ ) ;
639
if ( k == len && curr[k] == '\0' ) return 1;
640
}
641
return 0;
642
}
643
644
UInt completion_gvar (
645
Char * name,
646
UInt len )
647
{
648
Char * curr;
649
Char * next;
650
UInt i, k;
651
652
next = 0;
653
for ( i = 1; i <= CountGVars; i++ ) {
654
/* consider only variables which are currently bound for completion */
655
if ( VAL_GVAR( i ) || ELM_PLIST( ExprGVars, i )) {
656
curr = NameGVar( i );
657
for ( k = 0; name[k] != 0 && curr[k] == name[k]; k++ ) ;
658
if ( k < len || curr[k] <= name[k] ) continue;
659
if ( next != 0 ) {
660
for ( k = 0; curr[k] != '\0' && curr[k] == next[k]; k++ ) ;
661
if ( k < len || next[k] < curr[k] ) continue;
662
}
663
next = curr;
664
}
665
}
666
667
if ( next != 0 ) {
668
for ( k = 0; next[k] != '\0'; k++ )
669
name[k] = next[k];
670
name[k] = '\0';
671
}
672
673
return next != 0;
674
}
675
676
677
/****************************************************************************
678
**
679
*F FuncIDENTS_GVAR( <self> ) . . . . . . . . . . idents of global variables
680
*/
681
Obj FuncIDENTS_GVAR (
682
Obj self )
683
{
684
/*QQ extern Obj NameGVars; */
685
Obj copy;
686
UInt i;
687
688
copy = NEW_PLIST( T_PLIST+IMMUTABLE, LEN_PLIST(NameGVars) );
689
for ( i = 1; i <= LEN_PLIST(NameGVars); i++ ) {
690
SET_ELM_PLIST( copy, i, ELM_PLIST( NameGVars, i ) );
691
}
692
SET_LEN_PLIST( copy, LEN_PLIST(NameGVars) );
693
return copy;
694
}
695
696
Obj FuncIDENTS_BOUND_GVARS (
697
Obj self )
698
{
699
/*QQ extern Obj NameGVars; */
700
Obj copy;
701
UInt i, j;
702
703
copy = NEW_PLIST( T_PLIST+IMMUTABLE, LEN_PLIST(NameGVars) );
704
for ( i = 1, j = 1; i <= LEN_PLIST(NameGVars); i++ ) {
705
if ( VAL_GVAR( i ) || ELM_PLIST( ExprGVars, i )) {
706
SET_ELM_PLIST( copy, j, ELM_PLIST( NameGVars, i ) );
707
j++;
708
}
709
}
710
SET_LEN_PLIST( copy, j - 1 );
711
return copy;
712
}
713
714
/****************************************************************************
715
**
716
*F FuncASS_GVAR( <self>, <gvar>, <val> ) . . . . assign to a global variable
717
*/
718
Obj FuncASS_GVAR (
719
Obj self,
720
Obj gvar,
721
Obj val )
722
{
723
/* check the argument */
724
while ( ! IsStringConv( gvar ) ) {
725
gvar = ErrorReturnObj(
726
"READ: <gvar> must be a string (not a %s)",
727
(Int)TNAM_OBJ(gvar), 0L,
728
"you can return a string for <gvar>" );
729
}
730
731
AssGVar( GVarName( CSTR_STRING(gvar) ), val );
732
return 0L;
733
}
734
735
736
/****************************************************************************
737
**
738
*F FuncISB_GVAR( <self>, <gvar> ) . . check assignment of a global variable
739
*/
740
Obj FuncISB_GVAR (
741
Obj self,
742
Obj gvar )
743
{
744
UInt gv;
745
/* check the argument */
746
while ( ! IsStringConv( gvar ) ) {
747
gvar = ErrorReturnObj(
748
"ISB_GVAR: <gvar> must be a string (not a %s)",
749
(Int)TNAM_OBJ(gvar), 0L,
750
"you can return a string for <gvar>" );
751
}
752
753
gv = GVarName( CSTR_STRING(gvar) );
754
return ( VAL_GVAR( gv ) ||
755
ELM_PLIST( ExprGVars, gv )) ? True : False;
756
}
757
758
759
/****************************************************************************
760
**
761
*F FuncVAL_GVAR( <self>, <gvar> ) . . contents of a global variable
762
*/
763
764
Obj FuncVAL_GVAR (
765
Obj self,
766
Obj gvar )
767
{
768
Obj val;
769
/* check the argument */
770
while ( ! IsStringConv( gvar ) ) {
771
gvar = ErrorReturnObj(
772
"VAL_GVAR: <gvar> must be a string (not a %s)",
773
(Int)TNAM_OBJ(gvar), 0L,
774
"you can return a string for <gvar>" );
775
}
776
777
/* get the value */
778
val = ValAutoGVar( GVarName( CSTR_STRING(gvar) ) );
779
780
while (val == (Obj) 0)
781
val = ErrorReturnObj("VAL_GVAR: No value bound to %s",
782
(Int)CSTR_STRING(gvar), (Int) 0,
783
"you can return a value" );
784
return val;
785
}
786
787
/****************************************************************************
788
**
789
*F FuncUNB_GVAR( <self>, <gvar> ) . . unbind a global variable
790
*/
791
792
Obj FuncUNB_GVAR (
793
Obj self,
794
Obj gvar )
795
{
796
/* check the argument */
797
while ( ! IsStringConv( gvar ) ) {
798
gvar = ErrorReturnObj(
799
"UNB_GVAR: <gvar> must be a string (not a %s)",
800
(Int)TNAM_OBJ(gvar), 0L,
801
"you can return a string for <gvar>" );
802
}
803
804
/* */
805
AssGVar( GVarName( CSTR_STRING(gvar) ), (Obj)0 );
806
return (Obj) 0;
807
}
808
809
810
811
/****************************************************************************
812
**
813
814
*F * * * * * * * * * * * * * copies and fopies * * * * * * * * * * * * * * *
815
*/
816
817
818
/****************************************************************************
819
**
820
821
*V CopyAndFopyGVars . . . . . . kernel table of kernel copies and "fopies"
822
**
823
** This needs to be kept inside the kernel so that the copies can be updated
824
** after loading a workspace.
825
*/
826
typedef struct {
827
Obj * copy;
828
UInt isFopy;
829
const Char * name;
830
} StructCopyGVar;
831
832
#ifndef MAX_COPY_AND_FOPY_GVARS
833
#define MAX_COPY_AND_FOPY_GVARS 30000
834
#endif
835
836
static StructCopyGVar CopyAndFopyGVars[MAX_COPY_AND_FOPY_GVARS];
837
static Int NCopyAndFopyGVars;
838
839
840
/****************************************************************************
841
**
842
*F InitCopyGVar( <name>, <copy> ) . . declare C variable as copy of global
843
**
844
** 'InitCopyGVar' makes the C variable <cvar> at address <copy> a copy of
845
** the global variable named <name> (which must be a kernel string).
846
**
847
** The function only registers the information in <CopyAndFopyGVars>. At a
848
** latter stage one has to call 'UpdateCopyFopyInfo' to actually enter the
849
** information stored in <CopyAndFopyGVars> into a plain list.
850
**
851
** This is OK for garbage collection, but a real problem for saving in any
852
** event, this information does not really want to be saved because it is
853
** kernel centred rather than workspace centred.
854
**
855
** Accordingly we provide two functions `RemoveCopyFopyInfo' and
856
** `RestoreCopyFopyInfo' to remove or restore the information from the
857
** workspace. The Restore function is also intended to be used after
858
** loading a saved workspace
859
*/
860
void InitCopyGVar (
861
const Char * name ,
862
Obj * copy )
863
{
864
/* make a record in the kernel for saving and loading */
865
if ( NCopyAndFopyGVars >= MAX_COPY_AND_FOPY_GVARS ) {
866
Pr( "Panic, no room to record CopyGVar\n", 0L, 0L );
867
SyExit(1);
868
}
869
CopyAndFopyGVars[NCopyAndFopyGVars].copy = copy;
870
CopyAndFopyGVars[NCopyAndFopyGVars].isFopy = 0;
871
CopyAndFopyGVars[NCopyAndFopyGVars].name = name;
872
NCopyAndFopyGVars++;
873
}
874
875
876
/****************************************************************************
877
**
878
*F InitFopyGVar( <name>, <copy> ) . . declare C variable as copy of global
879
**
880
** 'InitFopyGVar' makes the C variable <cvar> at address <copy> a (function)
881
** copy of the global variable <gvar>, whose name is <name>. That means
882
** that whenever the value of <gvar> is a function, then <cvar> will
883
** reference the same value (i.e., will hold the same bag identifier). When
884
** the value of <gvar> is not a function, then <cvar> will reference a
885
** function that signals the error ``<func> must be a function''. When
886
** <gvar> has no assigned value, then <cvar> will reference a function that
887
** signals the error ``<gvar> must have an assigned value''.
888
*/
889
void InitFopyGVar (
890
const Char * name,
891
Obj * copy )
892
{
893
/* make a record in the kernel for saving and loading */
894
if ( NCopyAndFopyGVars >= MAX_COPY_AND_FOPY_GVARS ) {
895
Pr( "Panic, no room to record FopyGVar\n", 0L, 0L );
896
SyExit(1);
897
}
898
CopyAndFopyGVars[NCopyAndFopyGVars].copy = copy;
899
CopyAndFopyGVars[NCopyAndFopyGVars].isFopy = 1;
900
CopyAndFopyGVars[NCopyAndFopyGVars].name = name;
901
NCopyAndFopyGVars++;
902
}
903
904
905
/****************************************************************************
906
**
907
*F UpdateCopyFopyInfo() . . . . . . . . . . convert kernel info into plist
908
*/
909
static Int NCopyAndFopyDone;
910
911
void UpdateCopyFopyInfo ( void )
912
{
913
Obj cops; /* copies list */
914
UInt ncop; /* number of copies */
915
UInt gvar;
916
const Char * name; /* name of the variable */
917
Obj * copy; /* address of the copy */
918
919
/* loop over new copies and fopies */
920
for ( ; NCopyAndFopyDone < NCopyAndFopyGVars; NCopyAndFopyDone++ ) {
921
name = CopyAndFopyGVars[NCopyAndFopyDone].name;
922
copy = CopyAndFopyGVars[NCopyAndFopyDone].copy;
923
gvar = GVarName(name);
924
925
/* get the copies list and its length */
926
if ( CopyAndFopyGVars[NCopyAndFopyDone].isFopy ) {
927
if ( ELM_PLIST( FopiesGVars, gvar ) != 0 ) {
928
cops = ELM_PLIST( FopiesGVars, gvar );
929
}
930
else {
931
cops = NEW_PLIST( T_PLIST, 0 );
932
SET_ELM_PLIST( FopiesGVars, gvar, cops );
933
CHANGED_BAG(FopiesGVars);
934
}
935
}
936
else {
937
if ( ELM_PLIST( CopiesGVars, gvar ) != 0 ) {
938
cops = ELM_PLIST( CopiesGVars, gvar );
939
}
940
else {
941
cops = NEW_PLIST( T_PLIST, 0 );
942
SET_ELM_PLIST( CopiesGVars, gvar, cops );
943
CHANGED_BAG(CopiesGVars);
944
}
945
}
946
ncop = LEN_PLIST(cops);
947
948
/* append the copy to the copies list */
949
GROW_PLIST( cops, ncop+1 );
950
SET_LEN_PLIST( cops, ncop+1 );
951
SET_ELM_PLIST( cops, ncop+1, (Obj)copy );
952
CHANGED_BAG(cops);
953
954
/* now copy the value of <gvar> to <cvar> */
955
if ( CopyAndFopyGVars[NCopyAndFopyDone].isFopy ) {
956
if ( VAL_GVAR(gvar) != 0 && IS_FUNC(VAL_GVAR(gvar)) ) {
957
*copy = VAL_GVAR(gvar);
958
}
959
else if ( VAL_GVAR(gvar) != 0 ) {
960
*copy = ErrorMustEvalToFuncFunc;
961
}
962
else {
963
*copy = ErrorMustHaveAssObjFunc;
964
}
965
}
966
else {
967
*copy = VAL_GVAR(gvar);
968
}
969
}
970
}
971
972
973
/****************************************************************************
974
**
975
*F RemoveCopyFopyInfo() . . . remove the info about copies of gvars from ws
976
*/
977
void RemoveCopyFopyInfo( void )
978
{
979
UInt i, l;
980
981
l = LEN_PLIST(CopiesGVars);
982
for ( i = 1; i <= l; i++ )
983
SET_ELM_PLIST( CopiesGVars, i, 0 );
984
l = LEN_PLIST(FopiesGVars);
985
for ( i = 1; i <= l; i++ )
986
SET_ELM_PLIST( FopiesGVars, i, 0 );
987
NCopyAndFopyDone = 0;
988
return;
989
}
990
991
992
/****************************************************************************
993
**
994
*F RestoreCopyFopyInfo() . . . restore the info from the copy in the kernel
995
*/
996
void RestoreCopyFopyInfo( void )
997
{
998
NCopyAndFopyDone = 0;
999
UpdateCopyFopyInfo();
1000
}
1001
1002
1003
/****************************************************************************
1004
**
1005
1006
*F * * * * * * * * * * * * * initialize package * * * * * * * * * * * * * * *
1007
*/
1008
1009
1010
/****************************************************************************
1011
**
1012
1013
*V GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export
1014
*/
1015
static StructGVarFunc GVarFuncs [] = {
1016
1017
{ "MakeReadOnlyGVar", 1, "name",
1018
MakeReadOnlyGVarHandler, "src/gap.c:MakeReadOnlyGVar" },
1019
1020
{ "MakeReadWriteGVar", 1, "name",
1021
MakeReadWriteGVarHandler, "src/gap.c:MakeReadWriteGVar" },
1022
1023
{ "IsReadOnlyGVar", 1, "name",
1024
FuncIsReadOnlyGVar, "src/gap.c:IsReadOnlyGVar" },
1025
1026
{ "AUTO", -1, "args",
1027
AUTOHandler, "src/gap.c:AUTO" },
1028
1029
{ "IDENTS_GVAR", 0L, "",
1030
FuncIDENTS_GVAR, "src/gap.c:IDENTS_GVAR" },
1031
1032
{ "IDENTS_BOUND_GVARS", 0L, "",
1033
FuncIDENTS_BOUND_GVARS, "src/gap.c:IDENTS_BOUND_GVARS" },
1034
1035
{ "ISB_GVAR", 1L, "gvar",
1036
FuncISB_GVAR, "src/gap.c:ISB_GVAR" },
1037
1038
{ "ASS_GVAR", 2L, "gvar, value",
1039
FuncASS_GVAR, "src/gap.c:ASS_GVAR" },
1040
1041
{ "VAL_GVAR", 1L, "gvar",
1042
FuncVAL_GVAR, "src/gap.c:VAL_GVAR" },
1043
1044
{ "UNB_GVAR", 1L, "gvar",
1045
FuncUNB_GVAR, "src/gap.c:UNB_GVAR" },
1046
1047
{ "SET_NAMESPACE", 1L, "str",
1048
FuncSET_NAMESPACE, "src/gvars.c:SET_NAMESPACE" },
1049
1050
{ "GET_NAMESPACE", 0L, "",
1051
FuncGET_NAMESPACE, "src/gvars.c:GET_NAMESPACE" },
1052
1053
{ 0 }
1054
1055
};
1056
1057
1058
/****************************************************************************
1059
**
1060
1061
*F InitKernel( <module> ) . . . . . . . . initialise kernel data structures
1062
*/
1063
static Int InitKernel (
1064
StructInitInfo * module )
1065
{
1066
ValGVars = (Obj) 0;
1067
NCopyAndFopyGVars = 0;
1068
NCopyAndFopyDone = 0;
1069
InitHandlerRegistration();
1070
1071
/* init global bags and handler */
1072
InitGlobalBag( &ErrorMustEvalToFuncFunc,
1073
"src/gvars.c:ErrorMustEvalToFuncFunc" );
1074
InitGlobalBag( &ErrorMustHaveAssObjFunc,
1075
"src/gvars.c:ErrorMustHaveAssObjFunc" );
1076
InitGlobalBag( &ValGVars,
1077
"src/gvars.c:ValGVars" );
1078
InitGlobalBag( &NameGVars,
1079
"src/gvars.c:NameGVars" );
1080
InitGlobalBag( &WriteGVars,
1081
"src/gvars.c:WriteGVars" );
1082
InitGlobalBag( &ExprGVars,
1083
"src/gvars.c:ExprGVars" );
1084
InitGlobalBag( &CopiesGVars,
1085
"src/gvars.c:CopiesGVars" );
1086
InitGlobalBag( &FopiesGVars,
1087
"src/gvars.c:FopiesGVars" );
1088
InitGlobalBag( &TableGVars,
1089
"src/gvars.c:TableGVars" );
1090
InitGlobalBag( &CurrNamespace,
1091
"src/gvars.c:CurrNamespace" );
1092
1093
InitHandlerFunc( ErrorMustEvalToFuncHandler,
1094
"src/gvars.c:ErrorMustEvalToFuncHandler" );
1095
InitHandlerFunc( ErrorMustHaveAssObjHandler,
1096
"src/gvars.c:ErrorMustHaveAssObjHandler" );
1097
1098
/* init filters and functions */
1099
InitHdlrFuncsFromTable( GVarFuncs );
1100
1101
/* Get a copy of REREADING */
1102
ImportGVarFromLibrary("REREADING", &REREADING);
1103
1104
1105
/* return success */
1106
return 0;
1107
}
1108
1109
1110
/****************************************************************************
1111
**
1112
*F PostRestore( <module> ) . . . . . . . . . . . . . after restore workspace
1113
*/
1114
1115
static Int PostRestore (
1116
StructInitInfo * module )
1117
{
1118
/* make the lists for global variables */
1119
CountGVars = LEN_PLIST( ValGVars );
1120
PtrGVars = ADDR_OBJ( ValGVars );
1121
SizeGVars = LEN_PLIST( TableGVars );
1122
1123
/* create the global variable '~' */
1124
Tilde = GVarName( "~" );
1125
1126
1127
/* update fopies and copies */
1128
UpdateCopyFopyInfo();
1129
1130
/* return success */
1131
return 0;
1132
}
1133
1134
/****************************************************************************
1135
**
1136
*F PreSave( <module> ) . . . . . . . . . . . . . before save workspace
1137
*/
1138
static Int PreSave (
1139
StructInitInfo * module )
1140
{
1141
RemoveCopyFopyInfo();
1142
return 0;
1143
}
1144
1145
/****************************************************************************
1146
**
1147
*F PostSave( <module> ) . . . . . . . . . . . . . aftersave workspace
1148
*/
1149
static Int PostSave (
1150
StructInitInfo * module )
1151
{
1152
UpdateCopyFopyInfo();
1153
return 0;
1154
}
1155
1156
1157
/****************************************************************************
1158
**
1159
*F InitLibrary( <module> ) . . . . . . . initialise library data structures
1160
*/
1161
static Int InitLibrary (
1162
StructInitInfo * module )
1163
{
1164
/* make the error functions for 'AssGVar' */
1165
ErrorMustEvalToFuncFunc = NewFunctionC(
1166
"ErrorMustEvalToFunc", -1,"args", ErrorMustEvalToFuncHandler );
1167
1168
ErrorMustHaveAssObjFunc = NewFunctionC(
1169
"ErrorMustHaveAssObj", -1L,"args", ErrorMustHaveAssObjHandler );
1170
1171
/* make the lists for global variables */
1172
ValGVars = NEW_PLIST( T_PLIST, 0 );
1173
SET_LEN_PLIST( ValGVars, 0 );
1174
1175
NameGVars = NEW_PLIST( T_PLIST, 0 );
1176
SET_LEN_PLIST( NameGVars, 0 );
1177
1178
WriteGVars = NEW_PLIST( T_PLIST, 0 );
1179
SET_LEN_PLIST( WriteGVars, 0 );
1180
1181
ExprGVars = NEW_PLIST( T_PLIST, 0 );
1182
SET_LEN_PLIST( ExprGVars, 0 );
1183
1184
CopiesGVars = NEW_PLIST( T_PLIST, 0 );
1185
SET_LEN_PLIST( CopiesGVars, 0 );
1186
1187
FopiesGVars = NEW_PLIST( T_PLIST, 0 );
1188
SET_LEN_PLIST( FopiesGVars, 0 );
1189
1190
/* make the list of global variables */
1191
SizeGVars = 997;
1192
TableGVars = NEW_PLIST( T_PLIST, SizeGVars );
1193
SET_LEN_PLIST( TableGVars, SizeGVars );
1194
1195
/* Create the current namespace: */
1196
TLS(CurrNamespace) = NEW_STRING(0);
1197
SET_LEN_STRING(TLS(CurrNamespace),0);
1198
1199
/* fix C vars */
1200
PostRestore( module );
1201
1202
/* init filters and functions */
1203
InitGVarFuncsFromTable( GVarFuncs );
1204
1205
/* return success */
1206
return 0;
1207
}
1208
1209
1210
/****************************************************************************
1211
**
1212
*F CheckInit( <module> ) . . . . . . . . . . . . . . . check initialisation
1213
*/
1214
static Int CheckInit (
1215
StructInitInfo * module )
1216
{
1217
Int success = 1;
1218
1219
if ( NCopyAndFopyGVars != NCopyAndFopyDone ) {
1220
success = 0;
1221
Pr( "#W failed to updated copies and fopies\n", 0L, 0L );
1222
}
1223
1224
/* return success */
1225
return ! success;
1226
}
1227
1228
1229
/****************************************************************************
1230
**
1231
*F InitInfoGVars() . . . . . . . . . . . . . . . . . table of init functions
1232
*/
1233
static StructInitInfo module = {
1234
MODULE_BUILTIN, /* type */
1235
"gvars", /* name */
1236
0, /* revision entry of c file */
1237
0, /* revision entry of h file */
1238
0, /* version */
1239
0, /* crc */
1240
InitKernel, /* initKernel */
1241
InitLibrary, /* initLibrary */
1242
CheckInit, /* checkInit */
1243
PreSave, /* preSave */
1244
PostSave, /* postSave */
1245
PostRestore /* postRestore */
1246
};
1247
1248
StructInitInfo * InitInfoGVars ( void )
1249
{
1250
return &module;
1251
}
1252
1253
1254
/****************************************************************************
1255
**
1256
1257
*E gvars.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here
1258
*/
1259
1260