Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

Testing latest pari + WASM + node.js... and it works?! Wow.

28494 views
License: GPL3
ubuntu2004
1
/* Copyright (C) 2006 The PARI group.
2
3
This file is part of the PARI package.
4
5
PARI/GP is free software; you can redistribute it and/or modify it under the
6
terms of the GNU General Public License as published by the Free Software
7
Foundation; either version 2 of the License, or (at your option) any later
8
version. It is distributed in the hope that it will be useful, but WITHOUT
9
ANY WARRANTY WHATSOEVER.
10
11
Check the License for details. You should have received a copy of it, along
12
with the package; see the file 'COPYING'. If not, write to the Free Software
13
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
14
15
#include "pari.h"
16
#include "paripriv.h"
17
#include "anal.h"
18
#include "tree.h"
19
#include "opcode.h"
20
21
#define DEBUGLEVEL DEBUGLEVEL_compiler
22
23
#define tree pari_tree
24
25
enum COflags {COsafelex=1, COsafedyn=2};
26
27
/***************************************************************************
28
** **
29
** String constant expansion **
30
** **
31
***************************************************************************/
32
33
static char *
34
translate(const char **src, char *s)
35
{
36
const char *t = *src;
37
while (*t)
38
{
39
while (*t == '\\')
40
{
41
switch(*++t)
42
{
43
case 'e': *s='\033'; break; /* escape */
44
case 'n': *s='\n'; break;
45
case 't': *s='\t'; break;
46
default: *s=*t; if (!*t) { *src=s; return NULL; }
47
}
48
t++; s++;
49
}
50
if (*t == '"')
51
{
52
if (t[1] != '"') break;
53
t += 2; continue;
54
}
55
*s++ = *t++;
56
}
57
*s=0; *src=t; return s;
58
}
59
60
static void
61
matchQ(const char *s, char *entry)
62
{
63
if (*s != '"')
64
pari_err(e_SYNTAX,"expected character: '\"' instead of",s,entry);
65
}
66
67
/* Read a "string" from src. Format then copy it, starting at s. Return
68
* pointer to char following the end of the input string */
69
char *
70
pari_translate_string(const char *src, char *s, char *entry)
71
{
72
matchQ(src, entry); src++; s = translate(&src, s);
73
if (!s) pari_err(e_SYNTAX,"run-away string",src,entry);
74
matchQ(src, entry); return (char*)src+1;
75
}
76
77
static GEN
78
strntoGENexp(const char *str, long len)
79
{
80
long n = nchar2nlong(len-1);
81
GEN z = cgetg(1+n, t_STR);
82
const char *t = str+1;
83
z[n] = 0;
84
if (!translate(&t, GSTR(z))) compile_err("run-away string",str);
85
return z;
86
}
87
88
/***************************************************************************
89
** **
90
** Byte-code compiler **
91
** **
92
***************************************************************************/
93
94
typedef enum {Llocal, Lmy} Ltype;
95
96
struct vars_s
97
{
98
Ltype type; /*Only Llocal and Lmy are allowed */
99
int inl;
100
entree *ep;
101
};
102
103
struct frame_s
104
{
105
long pc;
106
GEN frame;
107
};
108
109
static THREAD pari_stack s_opcode, s_operand, s_data, s_lvar;
110
static THREAD pari_stack s_dbginfo, s_frame, s_accesslex;
111
static THREAD char *opcode;
112
static THREAD long *operand;
113
static THREAD long *accesslex;
114
static THREAD GEN *data;
115
static THREAD long offset, nblex;
116
static THREAD struct vars_s *localvars;
117
static THREAD const char **dbginfo, *dbgstart;
118
static THREAD struct frame_s *frames;
119
120
void
121
pari_init_compiler(void)
122
{
123
pari_stack_init(&s_opcode,sizeof(*opcode),(void **)&opcode);
124
pari_stack_init(&s_operand,sizeof(*operand),(void **)&operand);
125
pari_stack_init(&s_accesslex,sizeof(*operand),(void **)&accesslex);
126
pari_stack_init(&s_data,sizeof(*data),(void **)&data);
127
pari_stack_init(&s_lvar,sizeof(*localvars),(void **)&localvars);
128
pari_stack_init(&s_dbginfo,sizeof(*dbginfo),(void **)&dbginfo);
129
pari_stack_init(&s_frame,sizeof(*frames),(void **)&frames);
130
offset=-1; nblex=0;
131
}
132
void
133
pari_close_compiler(void)
134
{
135
pari_stack_delete(&s_opcode);
136
pari_stack_delete(&s_operand);
137
pari_stack_delete(&s_accesslex);
138
pari_stack_delete(&s_data);
139
pari_stack_delete(&s_lvar);
140
pari_stack_delete(&s_dbginfo);
141
pari_stack_delete(&s_frame);
142
}
143
144
struct codepos
145
{
146
long opcode, data, localvars, frames, accesslex;
147
long offset, nblex;
148
const char *dbgstart;
149
};
150
151
static void
152
getcodepos(struct codepos *pos)
153
{
154
pos->opcode=s_opcode.n;
155
pos->accesslex=s_accesslex.n;
156
pos->data=s_data.n;
157
pos->offset=offset;
158
pos->nblex=nblex;
159
pos->localvars=s_lvar.n;
160
pos->dbgstart=dbgstart;
161
pos->frames=s_frame.n;
162
offset=s_data.n-1;
163
}
164
165
void
166
compilestate_reset(void)
167
{
168
s_opcode.n=0;
169
s_operand.n=0;
170
s_accesslex.n=0;
171
s_dbginfo.n=0;
172
s_data.n=0;
173
s_lvar.n=0;
174
s_frame.n=0;
175
offset=-1;
176
nblex=0;
177
dbgstart=NULL;
178
}
179
180
void
181
compilestate_save(struct pari_compilestate *comp)
182
{
183
comp->opcode=s_opcode.n;
184
comp->operand=s_operand.n;
185
comp->accesslex=s_accesslex.n;
186
comp->data=s_data.n;
187
comp->offset=offset;
188
comp->nblex=nblex;
189
comp->localvars=s_lvar.n;
190
comp->dbgstart=dbgstart;
191
comp->dbginfo=s_dbginfo.n;
192
comp->frames=s_frame.n;
193
}
194
195
void
196
compilestate_restore(struct pari_compilestate *comp)
197
{
198
s_opcode.n=comp->opcode;
199
s_operand.n=comp->operand;
200
s_accesslex.n=comp->accesslex;
201
s_data.n=comp->data;
202
offset=comp->offset;
203
nblex=comp->nblex;
204
s_lvar.n=comp->localvars;
205
dbgstart=comp->dbgstart;
206
s_dbginfo.n=comp->dbginfo;
207
s_frame.n=comp->frames;
208
}
209
210
static GEN
211
gcopyunclone(GEN x) { GEN y = gcopy(x); gunclone(x); return y; }
212
213
static void
214
access_push(long x)
215
{
216
long a = pari_stack_new(&s_accesslex);
217
accesslex[a] = x;
218
}
219
220
static GEN
221
genctx(long nbmvar, long paccesslex)
222
{
223
GEN acc = const_vec(nbmvar,gen_1);
224
long i, lvl = 1 + nbmvar;
225
for (i = paccesslex; i<s_accesslex.n; i++)
226
{
227
long a = accesslex[i];
228
if (a > 0) { lvl+=a; continue; }
229
a += lvl;
230
if (a <= 0) pari_err_BUG("genctx");
231
if (a <= nbmvar)
232
gel(acc, a) = gen_0;
233
}
234
s_accesslex.n = paccesslex;
235
for (i = 1; i<=nbmvar; i++)
236
if (signe(gel(acc,i))==0)
237
access_push(i-nbmvar-1);
238
return acc;
239
}
240
241
static GEN
242
getfunction(const struct codepos *pos, long arity, long nbmvar, GEN text,
243
long gap)
244
{
245
long lop = s_opcode.n+1 - pos->opcode;
246
long ldat = s_data.n+1 - pos->data;
247
long lfram = s_frame.n+1 - pos->frames;
248
GEN cl = cgetg(nbmvar && text? 8: (text? 7: 6), t_CLOSURE);
249
GEN frpc, fram, dbg, op, dat;
250
char *s;
251
long i;
252
253
cl[1] = arity;
254
gel(cl,2) = cgetg(nchar2nlong(lop)+1, t_STR);
255
gel(cl,3) = op = cgetg(lop, t_VECSMALL);
256
gel(cl,4) = dat = cgetg(ldat, t_VEC);
257
dbg = cgetg(lop, t_VECSMALL);
258
frpc = cgetg(lfram, t_VECSMALL);
259
fram = cgetg(lfram, t_VEC);
260
gel(cl,5) = mkvec3(dbg, frpc, fram);
261
if (text) gel(cl,6) = text;
262
s = GSTR(gel(cl,2)) - 1;
263
for (i = 1; i < lop; i++)
264
{
265
long j = i+pos->opcode-1;
266
s[i] = opcode[j];
267
op[i] = operand[j];
268
dbg[i] = dbginfo[j] - dbgstart;
269
if (dbg[i] < 0) dbg[i] += gap;
270
}
271
s[i] = 0;
272
s_opcode.n = pos->opcode;
273
s_operand.n = pos->opcode;
274
s_dbginfo.n = pos->opcode;
275
if (lg(cl)==8)
276
gel(cl,7) = genctx(nbmvar, pos->accesslex);
277
else if (nbmvar==0)
278
s_accesslex.n = pos->accesslex;
279
else
280
{
281
pari_sp av = avma;
282
(void) genctx(nbmvar, pos->accesslex);
283
set_avma(av);
284
}
285
for (i = 1; i < ldat; i++)
286
if (data[i+pos->data-1]) gel(dat,i) = gcopyunclone(data[i+pos->data-1]);
287
s_data.n = pos->data;
288
while (s_lvar.n > pos->localvars && !localvars[s_lvar.n-1].inl)
289
{
290
if (localvars[s_lvar.n-1].type==Lmy) nblex--;
291
s_lvar.n--;
292
}
293
for (i = 1; i < lfram; i++)
294
{
295
long j = i+pos->frames-1;
296
frpc[i] = frames[j].pc - pos->opcode+1;
297
gel(fram, i) = gcopyunclone(frames[j].frame);
298
}
299
s_frame.n = pos->frames;
300
offset = pos->offset;
301
dbgstart = pos->dbgstart;
302
return cl;
303
}
304
305
static GEN
306
getclosure(struct codepos *pos, long nbmvar)
307
{
308
return getfunction(pos, 0, nbmvar, NULL, 0);
309
}
310
311
static void
312
op_push_loc(op_code o, long x, const char *loc)
313
{
314
long n=pari_stack_new(&s_opcode);
315
long m=pari_stack_new(&s_operand);
316
long d=pari_stack_new(&s_dbginfo);
317
opcode[n]=o;
318
operand[m]=x;
319
dbginfo[d]=loc;
320
}
321
322
static void
323
op_push(op_code o, long x, long n)
324
{
325
op_push_loc(o,x,tree[n].str);
326
}
327
328
static void
329
op_insert_loc(long k, op_code o, long x, const char *loc)
330
{
331
long i;
332
long n=pari_stack_new(&s_opcode);
333
(void) pari_stack_new(&s_operand);
334
(void) pari_stack_new(&s_dbginfo);
335
for (i=n-1; i>=k; i--)
336
{
337
opcode[i+1] = opcode[i];
338
operand[i+1]= operand[i];
339
dbginfo[i+1]= dbginfo[i];
340
}
341
opcode[k] = o;
342
operand[k] = x;
343
dbginfo[k] = loc;
344
}
345
346
static long
347
data_push(GEN x)
348
{
349
long n=pari_stack_new(&s_data);
350
data[n] = x?gclone(x):x;
351
return n-offset;
352
}
353
354
static void
355
var_push(entree *ep, Ltype type)
356
{
357
long n=pari_stack_new(&s_lvar);
358
localvars[n].ep = ep;
359
localvars[n].inl = 0;
360
localvars[n].type = type;
361
if (type == Lmy) nblex++;
362
}
363
364
static void
365
frame_push(GEN x)
366
{
367
long n=pari_stack_new(&s_frame);
368
frames[n].pc = s_opcode.n-1;
369
frames[n].frame = gclone(x);
370
}
371
372
static GEN
373
pack_localvars(void)
374
{
375
GEN pack=cgetg(3,t_VEC);
376
long i, l=s_lvar.n;
377
GEN t=cgetg(1+l,t_VECSMALL);
378
GEN e=cgetg(1+l,t_VECSMALL);
379
gel(pack,1)=t;
380
gel(pack,2)=e;
381
for(i=1;i<=l;i++)
382
{
383
t[i]=localvars[i-1].type;
384
e[i]=(long)localvars[i-1].ep;
385
}
386
for(i=1;i<=nblex;i++)
387
access_push(-i);
388
return pack;
389
}
390
391
void
392
push_frame(GEN C, long lpc, long dummy)
393
{
394
const char *code=closure_codestr(C);
395
GEN oper=closure_get_oper(C);
396
GEN dbg=closure_get_dbg(C);
397
GEN frpc=gel(dbg,2);
398
GEN fram=gel(dbg,3);
399
long pc, j=1, lfr = lg(frpc);
400
if (lpc==-1)
401
{
402
long k;
403
GEN e = gel(fram, 1);
404
for(k=1; k<lg(e); k++)
405
var_push(dummy?NULL:(entree*)e[k], Lmy);
406
return;
407
}
408
if (lg(C)<8) while (j<lfr && frpc[j]==0) j++;
409
for(pc=0; pc<lpc; pc++) /* do not assume lpc was completed */
410
{
411
if (pc>0 && (code[pc]==OClocalvar || code[pc]==OClocalvar0))
412
var_push((entree*)oper[pc],Llocal);
413
if (j<lfr && pc==frpc[j])
414
{
415
long k;
416
GEN e = gel(fram,j);
417
for(k=1; k<lg(e); k++)
418
var_push(dummy?NULL:(entree*)e[k], Lmy);
419
j++;
420
}
421
}
422
}
423
424
void
425
debug_context(void)
426
{
427
long i;
428
for(i=0;i<s_lvar.n;i++)
429
{
430
entree *ep = localvars[i].ep;
431
Ltype type = localvars[i].type;
432
err_printf("%ld: %s: %s\n",i,(type==Lmy?"my":"local"),(ep?ep->name:"NULL"));
433
}
434
}
435
436
GEN
437
localvars_read_str(const char *x, GEN pack)
438
{
439
pari_sp av = avma;
440
GEN code;
441
long l=0, nbmvar=nblex;
442
if (pack)
443
{
444
GEN t=gel(pack,1);
445
GEN e=gel(pack,2);
446
long i;
447
l=lg(t)-1;
448
for(i=1;i<=l;i++)
449
var_push((entree*)e[i],(Ltype)t[i]);
450
}
451
code = compile_str(x);
452
s_lvar.n -= l;
453
nblex = nbmvar;
454
return gerepileupto(av, closure_evalres(code));
455
}
456
457
long
458
localvars_find(GEN pack, entree *ep)
459
{
460
GEN t=gel(pack,1);
461
GEN e=gel(pack,2);
462
long i;
463
long vn=0;
464
for(i=lg(e)-1;i>=1;i--)
465
{
466
if(t[i]==Lmy)
467
vn--;
468
if(e[i]==(long)ep)
469
return t[i]==Lmy?vn:0;
470
}
471
return 0;
472
}
473
474
/*
475
Flags for copy optimisation:
476
-- Freturn: The result will be returned.
477
-- FLsurvive: The result must survive the closure.
478
-- FLnocopy: The result will never be updated nor part of a user variable.
479
-- FLnocopylex: The result will never be updated nor part of dynamic variable.
480
*/
481
enum FLflag {FLreturn=1, FLsurvive=2, FLnocopy=4, FLnocopylex=8};
482
483
static void
484
addcopy(long n, long mode, long flag, long mask)
485
{
486
if (mode==Ggen && !(flag&mask))
487
{
488
op_push(OCcopy,0,n);
489
if (!(flag&FLsurvive) && DEBUGLEVEL)
490
pari_warn(warner,"compiler generates copy for `%.*s'",
491
tree[n].len,tree[n].str);
492
}
493
}
494
495
static void compilenode(long n, int mode, long flag);
496
497
typedef enum {PPend,PPstd,PPdefault,PPdefaultmulti,PPstar,PPauto} PPproto;
498
499
static PPproto
500
parseproto(char const **q, char *c, const char *str)
501
{
502
char const *p=*q;
503
long i;
504
switch(*p)
505
{
506
case 0:
507
case '\n':
508
return PPend;
509
case 'D':
510
switch(p[1])
511
{
512
case 'G':
513
case '&':
514
case 'W':
515
case 'V':
516
case 'I':
517
case 'E':
518
case 'J':
519
case 'n':
520
case 'P':
521
case 'r':
522
case 's':
523
*c=p[1]; *q=p+2; return PPdefault;
524
default:
525
for(i=0;*p && i<2;p++) i+=*p==',';
526
/* assert(i>=2) because check_proto validated the protototype */
527
*c=p[-2]; *q=p; return PPdefaultmulti;
528
}
529
break;
530
case 'C':
531
case 'p':
532
case 'b':
533
case 'P':
534
case 'f':
535
*c=*p; *q=p+1; return PPauto;
536
case '&':
537
*c='*'; *q=p+1; return PPstd;
538
case 'V':
539
if (p[1]=='=')
540
{
541
if (p[2]!='G')
542
compile_err("function prototype is not supported",str);
543
*c='='; p+=2;
544
}
545
else
546
*c=*p;
547
*q=p+1; return PPstd;
548
case 'E':
549
case 's':
550
if (p[1]=='*') { *c=*p++; *q=p+1; return PPstar; }
551
/*fall through*/
552
}
553
*c=*p; *q=p+1; return PPstd;
554
}
555
556
static long
557
detag(long n)
558
{
559
while (tree[n].f==Ftag)
560
n=tree[n].x;
561
return n;
562
}
563
564
/* return type for GP functions */
565
static op_code
566
get_ret_type(const char **p, long arity, Gtype *t, long *flag)
567
{
568
*flag = 0;
569
if (**p == 'v') { (*p)++; *t=Gvoid; return OCcallvoid; }
570
else if (**p == 'i') { (*p)++; *t=Gsmall; return OCcallint; }
571
else if (**p == 'l') { (*p)++; *t=Gsmall; return OCcalllong; }
572
else if (**p == 'u') { (*p)++; *t=Gusmall; return OCcalllong; }
573
else if (**p == 'm') { (*p)++; *flag = FLnocopy; }
574
*t=Ggen; return arity==2?OCcallgen2:OCcallgen;
575
}
576
577
/*supported types:
578
* type: Gusmall, Gsmall, Ggen, Gvoid, Gvec, Gclosure
579
* mode: Gusmall, Gsmall, Ggen, Gvar, Gvoid
580
*/
581
static void
582
compilecast_loc(int type, int mode, const char *loc)
583
{
584
if (type==mode) return;
585
switch (mode)
586
{
587
case Gusmall:
588
if (type==Ggen) op_push_loc(OCitou,-1,loc);
589
else if (type==Gvoid) op_push_loc(OCpushlong,0,loc);
590
else if (type!=Gsmall)
591
compile_err("this should be a small integer >=0",loc);
592
break;
593
case Gsmall:
594
if (type==Ggen) op_push_loc(OCitos,-1,loc);
595
else if (type==Gvoid) op_push_loc(OCpushlong,0,loc);
596
else if (type!=Gusmall)
597
compile_err("this should be a small integer",loc);
598
break;
599
case Ggen:
600
if (type==Gsmall) op_push_loc(OCstoi,0,loc);
601
else if (type==Gusmall)op_push_loc(OCutoi,0,loc);
602
else if (type==Gvoid) op_push_loc(OCpushgnil,0,loc);
603
break;
604
case Gvoid:
605
op_push_loc(OCpop, 1,loc);
606
break;
607
case Gvar:
608
if (type==Ggen) op_push_loc(OCvarn,-1,loc);
609
else compile_varerr(loc);
610
break;
611
default:
612
pari_err_BUG("compilecast [unknown type]");
613
}
614
}
615
616
static void
617
compilecast(long n, int type, int mode) { compilecast_loc(type, mode, tree[n].str); }
618
619
static entree *
620
fetch_member_raw(const char *s, long len)
621
{
622
pari_sp av = avma;
623
char *t = stack_malloc(len+2);
624
entree *ep;
625
t[0] = '_'; strncpy(t+1, s, len); t[++len] = 0; /* prepend '_' */
626
ep = fetch_entry_raw(t, len);
627
set_avma(av); return ep;
628
}
629
static entree *
630
getfunc(long n)
631
{
632
long x=tree[n].x;
633
if (tree[x].x==CSTmember) /* str-1 points to '.' */
634
return do_alias(fetch_member_raw(tree[x].str - 1, tree[x].len + 1));
635
else
636
return do_alias(fetch_entry_raw(tree[x].str, tree[x].len));
637
}
638
639
static entree *
640
getentry(long n)
641
{
642
n = detag(n);
643
if (tree[n].f!=Fentry)
644
{
645
if (tree[n].f==Fseq)
646
compile_err("unexpected character: ';'", tree[tree[n].y].str-1);
647
compile_varerr(tree[n].str);
648
}
649
return getfunc(n);
650
}
651
652
static entree *
653
getvar(long n)
654
{ return getentry(n); }
655
656
/* match Fentry that are not actually EpSTATIC functions called without parens*/
657
static entree *
658
getvardyn(long n)
659
{
660
entree *ep = getentry(n);
661
if (EpSTATIC(do_alias(ep)))
662
compile_varerr(tree[n].str);
663
return ep;
664
}
665
666
static long
667
getmvar(entree *ep)
668
{
669
long i;
670
long vn=0;
671
for(i=s_lvar.n-1;i>=0;i--)
672
{
673
if(localvars[i].type==Lmy)
674
vn--;
675
if(localvars[i].ep==ep)
676
return localvars[i].type==Lmy?vn:0;
677
}
678
return 0;
679
}
680
681
static void
682
ctxmvar(long n)
683
{
684
pari_sp av=avma;
685
GEN ctx;
686
long i;
687
if (n==0) return;
688
ctx = cgetg(n+1,t_VECSMALL);
689
for(n=0, i=0; i<s_lvar.n; i++)
690
if(localvars[i].type==Lmy)
691
ctx[++n]=(long)localvars[i].ep;
692
frame_push(ctx);
693
set_avma(av);
694
}
695
696
INLINE int
697
is_func_named(entree *ep, const char *s)
698
{
699
return !strcmp(ep->name, s);
700
}
701
702
INLINE int
703
is_node_zero(long n)
704
{
705
n = detag(n);
706
return (tree[n].f==Fsmall && tree[n].x==0);
707
}
708
709
static void
710
str_defproto(const char *p, const char *q, const char *loc)
711
{
712
long len = p-4-q;
713
if (q[1]!='"' || q[len]!='"')
714
compile_err("default argument must be a string",loc);
715
op_push_loc(OCpushgen,data_push(strntoGENexp(q+1,len)),loc);
716
}
717
718
static long
719
countmatrixelts(long n)
720
{
721
long x,i;
722
if (n==-1 || tree[n].f==Fnoarg) return 0;
723
for(x=n, i=0; tree[x].f==Fmatrixelts; x=tree[x].x)
724
if (tree[tree[x].y].f!=Fnoarg) i++;
725
if (tree[x].f!=Fnoarg) i++;
726
return i;
727
}
728
729
static long
730
countlisttogen(long n, Ffunc f)
731
{
732
long x,i;
733
if (n==-1 || tree[n].f==Fnoarg) return 0;
734
for(x=n, i=0; tree[x].f==f ;x=tree[x].x, i++);
735
return i+1;
736
}
737
738
static GEN
739
listtogen(long n, Ffunc f)
740
{
741
long x,i,nb = countlisttogen(n, f);
742
GEN z=cgetg(nb+1, t_VECSMALL);
743
if (nb)
744
{
745
for (x=n, i = nb-1; i>0; z[i+1]=tree[x].y, x=tree[x].x, i--);
746
z[1]=x;
747
}
748
return z;
749
}
750
751
static long
752
first_safe_arg(GEN arg, long mask)
753
{
754
long lnc, l=lg(arg);
755
for (lnc=l-1; lnc>0 && (tree[arg[lnc]].flags&mask)==mask; lnc--);
756
return lnc;
757
}
758
759
static void
760
checkdups(GEN arg, GEN vep)
761
{
762
long l=vecsmall_duplicate(vep);
763
if (l!=0) compile_err("variable declared twice",tree[arg[l]].str);
764
}
765
766
enum {MAT_range,MAT_std,MAT_line,MAT_column,VEC_std};
767
768
static int
769
matindex_type(long n)
770
{
771
long x = tree[n].x, y = tree[n].y;
772
long fxx = tree[tree[x].x].f, fxy = tree[tree[x].y].f;
773
if (y==-1)
774
{
775
if (fxy!=Fnorange) return MAT_range;
776
if (fxx==Fnorange) compile_err("missing index",tree[n].str);
777
return VEC_std;
778
}
779
else
780
{
781
long fyx = tree[tree[y].x].f, fyy = tree[tree[y].y].f;
782
if (fxy!=Fnorange || fyy!=Fnorange) return MAT_range;
783
if (fxx==Fnorange && fyx==Fnorange)
784
compile_err("missing index",tree[n].str);
785
if (fxx==Fnorange) return MAT_column;
786
if (fyx==Fnorange) return MAT_line;
787
return MAT_std;
788
}
789
}
790
791
static entree *
792
getlvalue(long n)
793
{
794
while ((tree[n].f==Fmatcoeff && matindex_type(tree[n].y)!=MAT_range) || tree[n].f==Ftag)
795
n=tree[n].x;
796
return getvar(n);
797
}
798
799
INLINE void
800
compilestore(long vn, entree *ep, long n)
801
{
802
if (vn)
803
op_push(OCstorelex,vn,n);
804
else
805
{
806
if (EpSTATIC(do_alias(ep)))
807
compile_varerr(tree[n].str);
808
op_push(OCstoredyn,(long)ep,n);
809
}
810
}
811
812
INLINE void
813
compilenewptr(long vn, entree *ep, long n)
814
{
815
if (vn)
816
{
817
access_push(vn);
818
op_push(OCnewptrlex,vn,n);
819
}
820
else
821
op_push(OCnewptrdyn,(long)ep,n);
822
}
823
824
static void
825
compilelvalue(long n)
826
{
827
n = detag(n);
828
if (tree[n].f==Fentry)
829
return;
830
else
831
{
832
long x = tree[n].x, y = tree[n].y;
833
long yx = tree[y].x, yy = tree[y].y;
834
long m = matindex_type(y);
835
if (m == MAT_range)
836
compile_err("not an lvalue",tree[n].str);
837
if (m == VEC_std && tree[x].f==Fmatcoeff)
838
{
839
int mx = matindex_type(tree[x].y);
840
if (mx==MAT_line)
841
{
842
int xy = tree[x].y, xyx = tree[xy].x;
843
compilelvalue(tree[x].x);
844
compilenode(tree[xyx].x,Gsmall,0);
845
compilenode(tree[yx].x,Gsmall,0);
846
op_push(OCcompo2ptr,0,y);
847
return;
848
}
849
}
850
compilelvalue(x);
851
switch(m)
852
{
853
case VEC_std:
854
compilenode(tree[yx].x,Gsmall,0);
855
op_push(OCcompo1ptr,0,y);
856
break;
857
case MAT_std:
858
compilenode(tree[yx].x,Gsmall,0);
859
compilenode(tree[yy].x,Gsmall,0);
860
op_push(OCcompo2ptr,0,y);
861
break;
862
case MAT_line:
863
compilenode(tree[yx].x,Gsmall,0);
864
op_push(OCcompoLptr,0,y);
865
break;
866
case MAT_column:
867
compilenode(tree[yy].x,Gsmall,0);
868
op_push(OCcompoCptr,0,y);
869
break;
870
}
871
}
872
}
873
874
static void
875
compilematcoeff(long n, int mode)
876
{
877
long x=tree[n].x, y=tree[n].y;
878
long yx=tree[y].x, yy=tree[y].y;
879
long m=matindex_type(y);
880
compilenode(x,Ggen,FLnocopy);
881
switch(m)
882
{
883
case VEC_std:
884
compilenode(tree[yx].x,Gsmall,0);
885
op_push(OCcompo1,mode,y);
886
return;
887
case MAT_std:
888
compilenode(tree[yx].x,Gsmall,0);
889
compilenode(tree[yy].x,Gsmall,0);
890
op_push(OCcompo2,mode,y);
891
return;
892
case MAT_line:
893
compilenode(tree[yx].x,Gsmall,0);
894
op_push(OCcompoL,0,y);
895
compilecast(n,Gvec,mode);
896
return;
897
case MAT_column:
898
compilenode(tree[yy].x,Gsmall,0);
899
op_push(OCcompoC,0,y);
900
compilecast(n,Gvec,mode);
901
return;
902
case MAT_range:
903
compilenode(tree[yx].x,Gsmall,0);
904
compilenode(tree[yx].y,Gsmall,0);
905
if (yy==-1)
906
op_push(OCcallgen,(long)is_entry("_[_.._]"),n);
907
else
908
{
909
compilenode(tree[yy].x,Gsmall,0);
910
compilenode(tree[yy].y,Gsmall,0);
911
op_push(OCcallgen,(long)is_entry("_[_.._,_.._]"),n);
912
}
913
compilecast(n,Gvec,mode);
914
return;
915
default:
916
pari_err_BUG("compilematcoeff");
917
}
918
}
919
920
static void
921
compilesmall(long n, long x, long mode)
922
{
923
if (mode==Ggen)
924
op_push(OCpushstoi, x, n);
925
else
926
{
927
if (mode==Gusmall && x < 0)
928
compile_err("this should be a small integer >=0",tree[n].str);
929
op_push(OCpushlong, x, n);
930
compilecast(n,Gsmall,mode);
931
}
932
}
933
934
static void
935
compilevec(long n, long mode, op_code op)
936
{
937
pari_sp ltop=avma;
938
long x=tree[n].x;
939
long i;
940
GEN arg=listtogen(x,Fmatrixelts);
941
long l=lg(arg);
942
op_push(op,l,n);
943
for (i=1;i<l;i++)
944
{
945
if (tree[arg[i]].f==Fnoarg)
946
compile_err("missing vector element",tree[arg[i]].str);
947
compilenode(arg[i],Ggen,FLsurvive);
948
op_push(OCstackgen,i,n);
949
}
950
set_avma(ltop);
951
op_push(OCpop,1,n);
952
compilecast(n,Gvec,mode);
953
}
954
955
static void
956
compilemat(long n, long mode)
957
{
958
pari_sp ltop=avma;
959
long x=tree[n].x;
960
long i,j;
961
GEN line=listtogen(x,Fmatrixlines);
962
long lglin = lg(line), lgcol=0;
963
op_push(OCpushlong, lglin,n);
964
if (lglin==1)
965
op_push(OCmat,1,n);
966
for(i=1;i<lglin;i++)
967
{
968
GEN col=listtogen(line[i],Fmatrixelts);
969
long l=lg(col), k;
970
if (i==1)
971
{
972
lgcol=l;
973
op_push(OCmat,lgcol,n);
974
}
975
else if (l!=lgcol)
976
compile_err("matrix must be rectangular",tree[line[i]].str);
977
k=i;
978
for(j=1;j<lgcol;j++)
979
{
980
k-=lglin;
981
if (tree[col[j]].f==Fnoarg)
982
compile_err("missing matrix element",tree[col[j]].str);
983
compilenode(col[j], Ggen, FLsurvive);
984
op_push(OCstackgen,k,n);
985
}
986
}
987
set_avma(ltop);
988
op_push(OCpop,1,n);
989
compilecast(n,Gvec,mode);
990
}
991
992
static GEN
993
cattovec(long n, long fnum)
994
{
995
long x=n, y, i=0, nb;
996
GEN stack;
997
if (tree[n].f==Fnoarg) return cgetg(1,t_VECSMALL);
998
while(1)
999
{
1000
long xx=tree[x].x;
1001
long xy=tree[x].y;
1002
if (tree[x].f!=Ffunction || xx!=fnum) break;
1003
x=tree[xy].x;
1004
y=tree[xy].y;
1005
if (tree[y].f==Fnoarg)
1006
compile_err("unexpected character: ", tree[y].str);
1007
i++;
1008
}
1009
if (tree[x].f==Fnoarg)
1010
compile_err("unexpected character: ", tree[x].str);
1011
nb=i+1;
1012
stack=cgetg(nb+1,t_VECSMALL);
1013
for(x=n;i>0;i--)
1014
{
1015
long y=tree[x].y;
1016
x=tree[y].x;
1017
stack[i+1]=tree[y].y;
1018
}
1019
stack[1]=x;
1020
return stack;
1021
}
1022
1023
static GEN
1024
compilelambda(long y, GEN vep, long nbmvar, struct codepos *pos)
1025
{
1026
long lev = vep ? lg(vep)-1 : 0;
1027
GEN text=cgetg(3,t_VEC);
1028
gel(text,1)=strtoGENstr(lev? ((entree*) vep[1])->name: "");
1029
gel(text,2)=strntoGENstr(tree[y].str,tree[y].len);
1030
dbgstart = tree[y].str;
1031
compilenode(y,Ggen,FLsurvive|FLreturn);
1032
return getfunction(pos,lev,nbmvar,text,2);
1033
}
1034
1035
static void
1036
compilecall(long n, int mode, entree *ep)
1037
{
1038
pari_sp ltop=avma;
1039
long j;
1040
long x=tree[n].x, tx = tree[x].x;
1041
long y=tree[n].y;
1042
GEN arg=listtogen(y,Flistarg);
1043
long nb=lg(arg)-1;
1044
long lnc=first_safe_arg(arg, COsafelex|COsafedyn);
1045
long lnl=first_safe_arg(arg, COsafelex);
1046
long fl = lnl==0? (lnc==0? FLnocopy: FLnocopylex): 0;
1047
if (ep==NULL)
1048
compilenode(x, Ggen, fl);
1049
else
1050
{
1051
long vn=getmvar(ep);
1052
if (vn)
1053
{
1054
access_push(vn);
1055
op_push(OCpushlex,vn,n);
1056
}
1057
else
1058
op_push(OCpushdyn,(long)ep,n);
1059
}
1060
for (j=1;j<=nb;j++)
1061
{
1062
long x = tree[arg[j]].x, f = tree[arg[j]].f;
1063
if (f==Fseq)
1064
compile_err("unexpected ';'", tree[x].str+tree[x].len);
1065
else if (f==Findarg)
1066
{
1067
compilenode(tree[arg[j]].x, Ggen,FLnocopy);
1068
op_push(OClock,0,n);
1069
} else if (tx==CSTmember)
1070
{
1071
compilenode(arg[j], Ggen,FLnocopy);
1072
op_push(OClock,0,n);
1073
}
1074
else if (f!=Fnoarg)
1075
compilenode(arg[j], Ggen,j>=lnl?FLnocopylex:0);
1076
else
1077
op_push(OCpushlong,0,n);
1078
}
1079
op_push(OCcalluser,nb,x);
1080
compilecast(n,Ggen,mode);
1081
set_avma(ltop);
1082
}
1083
1084
static GEN
1085
compilefuncinline(long n, long c, long a, long flag, long isif, long lev, long *ev)
1086
{
1087
struct codepos pos;
1088
int type=c=='I'?Gvoid:Ggen;
1089
long rflag=c=='I'?0:FLsurvive;
1090
long nbmvar = nblex;
1091
GEN vep = NULL;
1092
if (isif && (flag&FLreturn)) rflag|=FLreturn;
1093
getcodepos(&pos);
1094
if (c=='J') ctxmvar(nbmvar);
1095
if (lev)
1096
{
1097
long i;
1098
GEN varg=cgetg(lev+1,t_VECSMALL);
1099
vep=cgetg(lev+1,t_VECSMALL);
1100
for(i=0;i<lev;i++)
1101
{
1102
entree *ve;
1103
if (ev[i]<0)
1104
compile_err("missing variable name", tree[a].str-1);
1105
ve = getvar(ev[i]);
1106
vep[i+1]=(long)ve;
1107
varg[i+1]=ev[i];
1108
var_push(ve,Lmy);
1109
}
1110
checkdups(varg,vep);
1111
if (c=='J')
1112
op_push(OCgetargs,lev,n);
1113
access_push(lg(vep)-1);
1114
frame_push(vep);
1115
}
1116
if (c=='J')
1117
return compilelambda(a,vep,nbmvar,&pos);
1118
if (tree[a].f==Fnoarg)
1119
compilecast(a,Gvoid,type);
1120
else
1121
compilenode(a,type,rflag);
1122
return getclosure(&pos, nbmvar);
1123
}
1124
1125
static long
1126
countvar(GEN arg)
1127
{
1128
long i, l = lg(arg);
1129
long n = l-1;
1130
for(i=1; i<l; i++)
1131
{
1132
long a=arg[i];
1133
if (tree[a].f==Fassign)
1134
{
1135
long x = detag(tree[a].x);
1136
if (tree[x].f==Fvec && tree[x].x>=0)
1137
n += countmatrixelts(tree[x].x)-1;
1138
}
1139
}
1140
return n;
1141
}
1142
1143
static void
1144
compileuninline(GEN arg)
1145
{
1146
long j;
1147
if (lg(arg) > 1)
1148
compile_err("too many arguments",tree[arg[1]].str);
1149
for(j=0; j<s_lvar.n; j++)
1150
if(!localvars[j].inl)
1151
pari_err(e_MISC,"uninline is only valid at top level");
1152
s_lvar.n = 0; nblex = 0;
1153
}
1154
1155
static void
1156
compilemy(GEN arg, const char *str, int inl)
1157
{
1158
long i, j, k, l = lg(arg);
1159
long n = countvar(arg);
1160
GEN vep = cgetg(n+1,t_VECSMALL);
1161
GEN ver = cgetg(n+1,t_VECSMALL);
1162
if (inl)
1163
{
1164
for(j=0; j<s_lvar.n; j++)
1165
if(!localvars[j].inl)
1166
pari_err(e_MISC,"inline is only valid at top level");
1167
}
1168
for(k=0, i=1; i<l; i++)
1169
{
1170
long a=arg[i];
1171
if (tree[a].f==Fassign)
1172
{
1173
long x = detag(tree[a].x);
1174
if (tree[x].f==Fvec && tree[x].x>=0)
1175
{
1176
GEN vars = listtogen(tree[x].x,Fmatrixelts);
1177
long nv = lg(vars)-1;
1178
for (j=1; j<=nv; j++)
1179
if (tree[vars[j]].f!=Fnoarg)
1180
{
1181
ver[++k] = vars[j];
1182
vep[k] = (long)getvar(ver[k]);
1183
}
1184
continue;
1185
} else ver[++k] = x;
1186
} else ver[++k] = a;
1187
vep[k] = (long)getvar(ver[k]);
1188
}
1189
checkdups(ver,vep);
1190
for(i=1; i<=n; i++) var_push(NULL,Lmy);
1191
op_push_loc(OCnewframe,inl?-n:n,str);
1192
access_push(lg(vep)-1);
1193
frame_push(vep);
1194
for (k=0, i=1; i<l; i++)
1195
{
1196
long a=arg[i];
1197
if (tree[a].f==Fassign)
1198
{
1199
long x = detag(tree[a].x);
1200
if (tree[x].f==Fvec && tree[x].x>=0)
1201
{
1202
GEN vars = listtogen(tree[x].x,Fmatrixelts);
1203
long nv = lg(vars)-1, m = nv;
1204
compilenode(tree[a].y,Ggen,FLnocopy);
1205
for (j=1; j<=nv; j++)
1206
if (tree[vars[j]].f==Fnoarg) m--;
1207
if (m > 1) op_push(OCdup,m-1,x);
1208
for (j=1; j<=nv; j++)
1209
if (tree[vars[j]].f!=Fnoarg)
1210
{
1211
long v = detag(vars[j]);
1212
op_push(OCpushlong,j,v);
1213
op_push(OCcompo1,Ggen,v);
1214
k++;
1215
op_push(OCstorelex,-n+k-1,a);
1216
localvars[s_lvar.n-n+k-1].ep=(entree*)vep[k];
1217
localvars[s_lvar.n-n+k-1].inl=inl;
1218
}
1219
continue;
1220
}
1221
else if (!is_node_zero(tree[a].y))
1222
{
1223
compilenode(tree[a].y,Ggen,FLnocopy);
1224
op_push(OCstorelex,-n+k,a);
1225
}
1226
}
1227
k++;
1228
localvars[s_lvar.n-n+k-1].ep=(entree*)vep[k];
1229
localvars[s_lvar.n-n+k-1].inl=inl;
1230
}
1231
}
1232
1233
static long
1234
localpush(op_code op, long a)
1235
{
1236
entree *ep = getvardyn(a);
1237
long vep = (long) ep;
1238
op_push(op,vep,a);
1239
var_push(ep,Llocal);
1240
return vep;
1241
}
1242
1243
static void
1244
compilelocal(GEN arg)
1245
{
1246
long i, j, k, l = lg(arg);
1247
long n = countvar(arg);
1248
GEN vep = cgetg(n+1,t_VECSMALL);
1249
GEN ver = cgetg(n+1,t_VECSMALL);
1250
for(k=0, i=1; i<l; i++)
1251
{
1252
long a=arg[i];
1253
if (tree[a].f==Fassign)
1254
{
1255
long x = detag(tree[a].x);
1256
if (tree[x].f==Fvec && tree[x].x>=0)
1257
{
1258
GEN vars = listtogen(tree[x].x,Fmatrixelts);
1259
long nv = lg(vars)-1, m = nv;
1260
compilenode(tree[a].y,Ggen,FLnocopy);
1261
for (j=1; j<=nv; j++)
1262
if (tree[vars[j]].f==Fnoarg) m--;
1263
if (m > 1) op_push(OCdup,m-1,x);
1264
for (j=1; j<=nv; j++)
1265
if (tree[vars[j]].f!=Fnoarg)
1266
{
1267
long v = detag(vars[j]);
1268
op_push(OCpushlong,j,v);
1269
op_push(OCcompo1,Ggen,v);
1270
vep[++k] = localpush(OClocalvar, v);
1271
ver[k] = v;
1272
}
1273
continue;
1274
} else if (!is_node_zero(tree[a].y))
1275
{
1276
compilenode(tree[a].y,Ggen,FLnocopy);
1277
ver[++k] = x;
1278
vep[k] = localpush(OClocalvar, ver[k]);
1279
continue;
1280
}
1281
else
1282
ver[++k] = x;
1283
} else
1284
ver[++k] = a;
1285
vep[k] = localpush(OClocalvar0, ver[k]);
1286
}
1287
checkdups(ver,vep);
1288
}
1289
1290
static void
1291
compileexport(GEN arg)
1292
{
1293
long i, l = lg(arg);
1294
for (i=1; i<l; i++)
1295
{
1296
long a=arg[i];
1297
if (tree[a].f==Fassign)
1298
{
1299
long x = detag(tree[a].x);
1300
long v = (long) getvardyn(x);
1301
compilenode(tree[a].y,Ggen,FLnocopy);
1302
op_push(OCexportvar,v,x);
1303
} else
1304
{
1305
long x = detag(a);
1306
long v = (long) getvardyn(x);
1307
op_push(OCpushdyn,v,x);
1308
op_push(OCexportvar,v,x);
1309
}
1310
}
1311
}
1312
1313
static void
1314
compileunexport(GEN arg)
1315
{
1316
long i, l = lg(arg);
1317
for (i=1; i<l; i++)
1318
{
1319
long a = arg[i];
1320
long x = detag(a);
1321
long v = (long) getvardyn(x);
1322
op_push(OCunexportvar,v,x);
1323
}
1324
}
1325
1326
static void
1327
compilefunc(entree *ep, long n, int mode, long flag)
1328
{
1329
pari_sp ltop=avma;
1330
long j;
1331
long x=tree[n].x, y=tree[n].y;
1332
op_code ret_op;
1333
long ret_flag;
1334
Gtype ret_typ;
1335
char const *p,*q;
1336
char c;
1337
const char *flags = NULL;
1338
const char *str;
1339
PPproto mod;
1340
GEN arg=listtogen(y,Flistarg);
1341
long lnc=first_safe_arg(arg, COsafelex|COsafedyn);
1342
long lnl=first_safe_arg(arg, COsafelex);
1343
long nbpointers=0, nbopcodes;
1344
long nb=lg(arg)-1, lev=0;
1345
long ev[20];
1346
if (x>=OPnboperator)
1347
str=tree[x].str;
1348
else
1349
{
1350
if (nb==2)
1351
str=tree[arg[1]].str+tree[arg[1]].len;
1352
else if (nb==1)
1353
str=tree[arg[1]].str;
1354
else
1355
str=tree[n].str;
1356
while(*str==')') str++;
1357
}
1358
if (tree[n].f==Fassign)
1359
{
1360
nb=2; lnc=2; lnl=2; arg=mkvecsmall2(x,y);
1361
}
1362
else if (is_func_named(ep,"if"))
1363
{
1364
if (nb>=4)
1365
ep=is_entry("_multi_if");
1366
else if (mode==Gvoid)
1367
ep=is_entry("_void_if");
1368
}
1369
else if (is_func_named(ep,"return") && (flag&FLreturn) && nb<=1)
1370
{
1371
if (nb==0) op_push(OCpushgnil,0,n);
1372
else compilenode(arg[1],Ggen,FLsurvive|FLreturn);
1373
set_avma(ltop);
1374
return;
1375
}
1376
else if (is_func_named(ep,"inline"))
1377
{
1378
compilemy(arg, str, 1);
1379
compilecast(n,Gvoid,mode);
1380
set_avma(ltop);
1381
return;
1382
}
1383
else if (is_func_named(ep,"uninline"))
1384
{
1385
compileuninline(arg);
1386
compilecast(n,Gvoid,mode);
1387
set_avma(ltop);
1388
return;
1389
}
1390
else if (is_func_named(ep,"my"))
1391
{
1392
compilemy(arg, str, 0);
1393
compilecast(n,Gvoid,mode);
1394
set_avma(ltop);
1395
return;
1396
}
1397
else if (is_func_named(ep,"local"))
1398
{
1399
compilelocal(arg);
1400
compilecast(n,Gvoid,mode);
1401
set_avma(ltop);
1402
return;
1403
}
1404
else if (is_func_named(ep,"export"))
1405
{
1406
compileexport(arg);
1407
compilecast(n,Gvoid,mode);
1408
set_avma(ltop);
1409
return;
1410
}
1411
else if (is_func_named(ep,"unexport"))
1412
{
1413
compileunexport(arg);
1414
compilecast(n,Gvoid,mode);
1415
set_avma(ltop);
1416
return;
1417
}
1418
/*We generate dummy code for global() for compatibility with gp2c*/
1419
else if (is_func_named(ep,"global"))
1420
{
1421
long i;
1422
for (i=1;i<=nb;i++)
1423
{
1424
long a=arg[i];
1425
long en;
1426
if (tree[a].f==Fassign)
1427
{
1428
compilenode(tree[a].y,Ggen,0);
1429
a=tree[a].x;
1430
en=(long)getvardyn(a);
1431
op_push(OCstoredyn,en,a);
1432
}
1433
else
1434
{
1435
en=(long)getvardyn(a);
1436
op_push(OCpushdyn,en,a);
1437
op_push(OCpop,1,a);
1438
}
1439
}
1440
compilecast(n,Gvoid,mode);
1441
set_avma(ltop);
1442
return;
1443
}
1444
else if (is_func_named(ep,"O"))
1445
{
1446
if (nb!=1)
1447
compile_err("wrong number of arguments", tree[n].str+tree[n].len-1);
1448
ep=is_entry("O(_^_)");
1449
if (tree[arg[1]].f==Ffunction && tree[arg[1]].x==OPpow)
1450
{
1451
arg = listtogen(tree[arg[1]].y,Flistarg);
1452
nb = lg(arg)-1;
1453
lnc = first_safe_arg(arg,COsafelex|COsafedyn);
1454
lnl = first_safe_arg(arg,COsafelex);
1455
}
1456
}
1457
else if (x==OPn && tree[y].f==Fsmall)
1458
{
1459
set_avma(ltop);
1460
compilesmall(y, -tree[y].x, mode);
1461
return;
1462
}
1463
else if (x==OPtrans && tree[y].f==Fvec)
1464
{
1465
set_avma(ltop);
1466
compilevec(y, mode, OCcol);
1467
return;
1468
}
1469
else if (x==OPpow && nb==2 && tree[arg[2]].f==Fsmall)
1470
ep=is_entry("_^s");
1471
else if (x==OPcat)
1472
compile_err("expected character: ',' or ')' instead of",
1473
tree[arg[1]].str+tree[arg[1]].len);
1474
p=ep->code;
1475
if (!ep->value)
1476
compile_err("unknown function",tree[n].str);
1477
nbopcodes = s_opcode.n;
1478
ret_op = get_ret_type(&p, ep->arity, &ret_typ, &ret_flag);
1479
j=1;
1480
if (*p)
1481
{
1482
q=p;
1483
while((mod=parseproto(&p,&c,tree[n].str))!=PPend)
1484
{
1485
if (j<=nb && tree[arg[j]].f!=Fnoarg
1486
&& (mod==PPdefault || mod==PPdefaultmulti))
1487
mod=PPstd;
1488
switch(mod)
1489
{
1490
case PPstd:
1491
if (j>nb) compile_err("too few arguments", tree[n].str+tree[n].len-1);
1492
if (c!='I' && c!='E' && c!='J')
1493
{
1494
long x = tree[arg[j]].x, f = tree[arg[j]].f;
1495
if (f==Fnoarg)
1496
compile_err("missing mandatory argument", tree[arg[j]].str);
1497
if (f==Fseq)
1498
compile_err("unexpected ';'", tree[x].str+tree[x].len);
1499
}
1500
switch(c)
1501
{
1502
case 'G':
1503
compilenode(arg[j],Ggen,j>=lnl?(j>=lnc?FLnocopy:FLnocopylex):0);
1504
j++;
1505
break;
1506
case 'W':
1507
{
1508
long a = tree[arg[j]].f==Findarg ? tree[arg[j]].x: arg[j];
1509
entree *ep = getlvalue(a);
1510
long vn = getmvar(ep);
1511
if (vn)
1512
{
1513
access_push(vn);
1514
op_push(OCcowvarlex, vn, a);
1515
}
1516
else op_push(OCcowvardyn, (long)ep, a);
1517
compilenode(a, Ggen,FLnocopy);
1518
j++;
1519
break;
1520
}
1521
case 'M':
1522
if (tree[arg[j]].f!=Fsmall)
1523
{
1524
if (!flags) flags = ep->code;
1525
flags = strchr(flags, '\n'); /* Skip to the following '\n' */
1526
if (!flags)
1527
compile_err("missing flag in string function signature",
1528
tree[n].str);
1529
flags++;
1530
if (tree[arg[j]].f==Fconst && tree[arg[j]].x==CSTstr)
1531
{
1532
GEN str=strntoGENexp(tree[arg[j]].str,tree[arg[j]].len);
1533
op_push(OCpushlong, eval_mnemonic(str, flags),n);
1534
j++;
1535
} else
1536
{
1537
compilenode(arg[j++],Ggen,0);
1538
op_push(OCpushlong,(long)flags,n);
1539
op_push(OCcallgen2,(long)is_entry("_eval_mnemonic"),n);
1540
}
1541
break;
1542
}
1543
case 'P': case 'L':
1544
compilenode(arg[j++],Gsmall,0);
1545
break;
1546
case 'U':
1547
compilenode(arg[j++],Gusmall,0);
1548
break;
1549
case 'n':
1550
compilenode(arg[j++],Gvar,0);
1551
break;
1552
case '&': case '*':
1553
{
1554
long vn, a=arg[j++];
1555
entree *ep;
1556
if (c=='&')
1557
{
1558
if (tree[a].f!=Frefarg)
1559
compile_err("expected character: '&'", tree[a].str);
1560
a=tree[a].x;
1561
}
1562
a=detag(a);
1563
ep=getlvalue(a);
1564
vn=getmvar(ep);
1565
if (tree[a].f==Fentry)
1566
{
1567
if (vn)
1568
{
1569
access_push(vn);
1570
op_push(OCsimpleptrlex, vn,n);
1571
}
1572
else
1573
op_push(OCsimpleptrdyn, (long)ep,n);
1574
}
1575
else
1576
{
1577
compilenewptr(vn, ep, a);
1578
compilelvalue(a);
1579
op_push(OCpushptr, 0, a);
1580
}
1581
nbpointers++;
1582
break;
1583
}
1584
case 'I':
1585
case 'E':
1586
case 'J':
1587
{
1588
long a = arg[j++];
1589
GEN d = compilefuncinline(n, c, a, flag, is_func_named(ep,"if"), lev, ev);
1590
op_push(OCpushgen, data_push(d), a);
1591
if (lg(d)==8) op_push(OCsaveframe,FLsurvive,n);
1592
break;
1593
}
1594
case 'V':
1595
{
1596
long a = arg[j++];
1597
(void)getvar(a);
1598
ev[lev++] = a;
1599
break;
1600
}
1601
case '=':
1602
{
1603
long a = arg[j++];
1604
ev[lev++] = tree[a].x;
1605
compilenode(tree[a].y, Ggen, FLnocopy);
1606
}
1607
break;
1608
case 'r':
1609
{
1610
long a=arg[j++];
1611
if (tree[a].f==Fentry)
1612
{
1613
op_push(OCpushgen, data_push(strntoGENstr(tree[tree[a].x].str,
1614
tree[tree[a].x].len)),n);
1615
op_push(OCtostr, -1,n);
1616
}
1617
else
1618
{
1619
compilenode(a,Ggen,FLnocopy);
1620
op_push(OCtostr, -1,n);
1621
}
1622
break;
1623
}
1624
case 's':
1625
{
1626
long a = arg[j++];
1627
GEN g = cattovec(a, OPcat);
1628
long l, nb = lg(g)-1;
1629
if (nb==1)
1630
{
1631
compilenode(g[1], Ggen, FLnocopy);
1632
op_push(OCtostr, -1, a);
1633
} else
1634
{
1635
op_push(OCvec, nb+1, a);
1636
for(l=1; l<=nb; l++)
1637
{
1638
compilenode(g[l], Ggen, FLsurvive);
1639
op_push(OCstackgen,l, a);
1640
}
1641
op_push(OCpop, 1, a);
1642
op_push(OCcallgen,(long)is_entry("Str"), a);
1643
op_push(OCtostr, -1, a);
1644
}
1645
break;
1646
}
1647
default:
1648
pari_err(e_MISC,"Unknown prototype code `%c' for `%.*s'",c,
1649
tree[x].len, tree[x].str);
1650
}
1651
break;
1652
case PPauto:
1653
switch(c)
1654
{
1655
case 'p':
1656
op_push(OCprecreal,0,n);
1657
break;
1658
case 'b':
1659
op_push(OCbitprecreal,0,n);
1660
break;
1661
case 'P':
1662
op_push(OCprecdl,0,n);
1663
break;
1664
case 'C':
1665
op_push(OCpushgen,data_push(pack_localvars()),n);
1666
break;
1667
case 'f':
1668
{
1669
static long foo;
1670
op_push(OCpushlong,(long)&foo,n);
1671
break;
1672
}
1673
}
1674
break;
1675
case PPdefault:
1676
j++;
1677
switch(c)
1678
{
1679
case 'G':
1680
case '&':
1681
case 'E':
1682
case 'I':
1683
case 'r':
1684
case 's':
1685
op_push(OCpushlong,0,n);
1686
break;
1687
case 'n':
1688
op_push(OCpushlong,-1,n);
1689
break;
1690
case 'V':
1691
ev[lev++] = -1;
1692
break;
1693
case 'P':
1694
op_push(OCprecdl,0,n);
1695
break;
1696
default:
1697
pari_err(e_MISC,"Unknown prototype code `%c' for `%.*s'",c,
1698
tree[x].len, tree[x].str);
1699
}
1700
break;
1701
case PPdefaultmulti:
1702
j++;
1703
switch(c)
1704
{
1705
case 'G':
1706
op_push(OCpushstoi,strtol(q+1,NULL,10),n);
1707
break;
1708
case 'L':
1709
case 'M':
1710
op_push(OCpushlong,strtol(q+1,NULL,10),n);
1711
break;
1712
case 'U':
1713
op_push(OCpushlong,(long)strtoul(q+1,NULL,10),n);
1714
break;
1715
case 'r':
1716
case 's':
1717
str_defproto(p, q, tree[n].str);
1718
op_push(OCtostr, -1, n);
1719
break;
1720
default:
1721
pari_err(e_MISC,"Unknown prototype code `%c' for `%.*s'",c,
1722
tree[x].len, tree[x].str);
1723
}
1724
break;
1725
case PPstar:
1726
switch(c)
1727
{
1728
case 'E':
1729
{
1730
long k, n=nb+1-j;
1731
GEN g=cgetg(n+1,t_VEC);
1732
int ismif = is_func_named(ep,"_multi_if");
1733
for(k=1; k<=n; k++)
1734
gel(g, k) = compilefuncinline(n, c, arg[j+k-1], flag,
1735
ismif && (k==n || odd(k)), lev, ev);
1736
op_push(OCpushgen, data_push(g), arg[j]);
1737
j=nb+1;
1738
break;
1739
}
1740
case 's':
1741
{
1742
long n=nb+1-j;
1743
long k,l,l1,m;
1744
GEN g=cgetg(n+1,t_VEC);
1745
for(l1=0,k=1;k<=n;k++)
1746
{
1747
gel(g,k)=cattovec(arg[j+k-1],OPcat);
1748
l1+=lg(gel(g,k))-1;
1749
}
1750
op_push_loc(OCvec, l1+1, str);
1751
for(m=1,k=1;k<=n;k++)
1752
for(l=1;l<lg(gel(g,k));l++,m++)
1753
{
1754
compilenode(mael(g,k,l),Ggen,FLsurvive);
1755
op_push(OCstackgen,m,mael(g,k,l));
1756
}
1757
op_push_loc(OCpop, 1, str);
1758
j=nb+1;
1759
break;
1760
}
1761
default:
1762
pari_err(e_MISC,"Unknown prototype code `%c*' for `%.*s'",c,
1763
tree[x].len, tree[x].str);
1764
}
1765
break;
1766
default:
1767
pari_err_BUG("compilefunc [unknown PPproto]");
1768
}
1769
q=p;
1770
}
1771
}
1772
if (j<=nb)
1773
compile_err("too many arguments",tree[arg[j]].str);
1774
op_push_loc(ret_op, (long) ep, str);
1775
if ((ret_flag&FLnocopy) && !(flag&FLnocopy))
1776
op_push_loc(OCcopy,0,str);
1777
if (ret_typ==Ggen && nbpointers==0 && s_opcode.n>nbopcodes+128)
1778
{
1779
op_insert_loc(nbopcodes,OCavma,0,str);
1780
op_push_loc(OCgerepile,0,str);
1781
}
1782
compilecast(n,ret_typ,mode);
1783
if (nbpointers) op_push_loc(OCendptr,nbpointers, str);
1784
set_avma(ltop);
1785
}
1786
1787
static void
1788
genclosurectx(const char *loc, long nbdata)
1789
{
1790
long i;
1791
GEN vep = cgetg(nbdata+1,t_VECSMALL);
1792
for(i = 1; i <= nbdata; i++)
1793
{
1794
vep[i] = 0;
1795
op_push_loc(OCpushlex,-i,loc);
1796
}
1797
frame_push(vep);
1798
}
1799
1800
static GEN
1801
genclosure(entree *ep, const char *loc, long nbdata, int check)
1802
{
1803
struct codepos pos;
1804
long nb=0;
1805
const char *code=ep->code,*p,*q;
1806
char c;
1807
GEN text;
1808
long index=ep->arity;
1809
long arity=0, maskarg=0, maskarg0=0, stop=0, dovararg=0;
1810
PPproto mod;
1811
Gtype ret_typ;
1812
long ret_flag;
1813
op_code ret_op=get_ret_type(&code,ep->arity,&ret_typ,&ret_flag);
1814
p=code;
1815
while ((mod=parseproto(&p,&c,NULL))!=PPend)
1816
{
1817
if (mod==PPauto)
1818
stop=1;
1819
else
1820
{
1821
if (stop) return NULL;
1822
if (c=='V') continue;
1823
maskarg<<=1; maskarg0<<=1; arity++;
1824
switch(mod)
1825
{
1826
case PPstd:
1827
maskarg|=1L;
1828
break;
1829
case PPdefault:
1830
switch(c)
1831
{
1832
case '&':
1833
case 'E':
1834
case 'I':
1835
maskarg0|=1L;
1836
break;
1837
}
1838
break;
1839
default:
1840
break;
1841
}
1842
}
1843
}
1844
if (check && EpSTATIC(ep) && maskarg==0)
1845
return gen_0;
1846
getcodepos(&pos);
1847
dbgstart = loc;
1848
if (nbdata > arity)
1849
pari_err(e_MISC,"too many parameters for closure `%s'", ep->name);
1850
if (nbdata) genclosurectx(loc, nbdata);
1851
text = strtoGENstr(ep->name);
1852
arity -= nbdata;
1853
if (maskarg) op_push_loc(OCcheckargs,maskarg,loc);
1854
if (maskarg0) op_push_loc(OCcheckargs0,maskarg0,loc);
1855
p=code;
1856
while ((mod=parseproto(&p,&c,NULL))!=PPend)
1857
{
1858
switch(mod)
1859
{
1860
case PPauto:
1861
switch(c)
1862
{
1863
case 'p':
1864
op_push_loc(OCprecreal,0,loc);
1865
break;
1866
case 'b':
1867
op_push_loc(OCbitprecreal,0,loc);
1868
break;
1869
case 'P':
1870
op_push_loc(OCprecdl,0,loc);
1871
break;
1872
case 'C':
1873
op_push_loc(OCpushgen,data_push(pack_localvars()),loc);
1874
break;
1875
case 'f':
1876
{
1877
static long foo;
1878
op_push_loc(OCpushlong,(long)&foo,loc);
1879
break;
1880
}
1881
}
1882
default:
1883
break;
1884
}
1885
}
1886
q = p = code;
1887
while ((mod=parseproto(&p,&c,NULL))!=PPend)
1888
{
1889
switch(mod)
1890
{
1891
case PPstd:
1892
switch(c)
1893
{
1894
case 'G':
1895
break;
1896
case 'M':
1897
case 'L':
1898
op_push_loc(OCitos,-index,loc);
1899
break;
1900
case 'U':
1901
op_push_loc(OCitou,-index,loc);
1902
break;
1903
case 'n':
1904
op_push_loc(OCvarn,-index,loc);
1905
break;
1906
case '&': case '*':
1907
case 'I':
1908
case 'E':
1909
case 'V':
1910
case '=':
1911
return NULL;
1912
case 'r':
1913
case 's':
1914
op_push_loc(OCtostr,-index,loc);
1915
break;
1916
}
1917
break;
1918
case PPauto:
1919
break;
1920
case PPdefault:
1921
switch(c)
1922
{
1923
case 'G':
1924
case '&':
1925
case 'E':
1926
case 'I':
1927
case 'V':
1928
break;
1929
case 'r':
1930
case 's':
1931
op_push_loc(OCtostr,-index,loc);
1932
break;
1933
case 'n':
1934
op_push_loc(OCvarn,-index,loc);
1935
break;
1936
case 'P':
1937
op_push_loc(OCprecdl,0,loc);
1938
op_push_loc(OCdefaultlong,-index,loc);
1939
break;
1940
default:
1941
pari_err(e_MISC,"Unknown prototype code `D%c' for `%s'",c,ep->name);
1942
}
1943
break;
1944
case PPdefaultmulti:
1945
switch(c)
1946
{
1947
case 'G':
1948
op_push_loc(OCpushstoi,strtol(q+1,NULL,10),loc);
1949
op_push_loc(OCdefaultgen,-index,loc);
1950
break;
1951
case 'L':
1952
case 'M':
1953
op_push_loc(OCpushlong,strtol(q+1,NULL,10),loc);
1954
op_push_loc(OCdefaultlong,-index,loc);
1955
break;
1956
case 'U':
1957
op_push_loc(OCpushlong,(long)strtoul(q+1,NULL,10),loc);
1958
op_push_loc(OCdefaultulong,-index,loc);
1959
break;
1960
case 'r':
1961
case 's':
1962
str_defproto(p, q, loc);
1963
op_push_loc(OCdefaultgen,-index,loc);
1964
op_push_loc(OCtostr,-index,loc);
1965
break;
1966
default:
1967
pari_err(e_MISC,
1968
"Unknown prototype code `D...,%c,' for `%s'",c,ep->name);
1969
}
1970
break;
1971
case PPstar:
1972
switch(c)
1973
{
1974
case 's':
1975
dovararg = 1;
1976
break;
1977
case 'E':
1978
return NULL;
1979
default:
1980
pari_err(e_MISC,"Unknown prototype code `%c*' for `%s'",c,ep->name);
1981
}
1982
break;
1983
default:
1984
return NULL;
1985
}
1986
index--;
1987
q = p;
1988
}
1989
op_push_loc(ret_op, (long) ep, loc);
1990
if (ret_flag==FLnocopy) op_push_loc(OCcopy,0,loc);
1991
compilecast_loc(ret_typ, Ggen, loc);
1992
if (dovararg) nb|=VARARGBITS;
1993
return getfunction(&pos,nb+arity,nbdata,text,0);
1994
}
1995
1996
GEN
1997
snm_closure(entree *ep, GEN data)
1998
{
1999
long i, n = data ? lg(data)-1: 0;
2000
GEN C = genclosure(ep,ep->name,n,0);
2001
for(i = 1; i <= n; i++) gmael(C,7,i) = gel(data,i);
2002
return C;
2003
}
2004
2005
GEN
2006
strtoclosure(const char *s, long n, ...)
2007
{
2008
pari_sp av = avma;
2009
entree *ep = is_entry(s);
2010
GEN C;
2011
if (!ep) pari_err(e_NOTFUNC, strtoGENstr(s));
2012
ep = do_alias(ep);
2013
if ((!EpSTATIC(ep) && EpVALENCE(ep)!=EpINSTALL) || !ep->value)
2014
pari_err(e_MISC,"not a built-in/install'ed function: \"%s\"",s);
2015
C = genclosure(ep,ep->name,n,0);
2016
if (!C) pari_err(e_MISC,"function prototype unsupported: \"%s\"",s);
2017
else
2018
{
2019
va_list ap;
2020
long i;
2021
va_start(ap,n);
2022
for(i = 1; i <= n; i++) gmael(C,7,i) = va_arg(ap, GEN);
2023
va_end(ap);
2024
}
2025
return gerepilecopy(av, C);
2026
}
2027
2028
GEN
2029
strtofunction(const char *s) { return strtoclosure(s, 0); }
2030
2031
GEN
2032
call0(GEN fun, GEN args)
2033
{
2034
if (!is_vec_t(typ(args))) pari_err_TYPE("call",args);
2035
switch(typ(fun))
2036
{
2037
case t_STR:
2038
fun = strtofunction(GSTR(fun));
2039
case t_CLOSURE: /* fall through */
2040
return closure_callgenvec(fun, args);
2041
default:
2042
pari_err_TYPE("call", fun);
2043
return NULL; /* LCOV_EXCL_LINE */
2044
}
2045
}
2046
2047
static void
2048
closurefunc(entree *ep, long n, long mode)
2049
{
2050
pari_sp ltop=avma;
2051
GEN C;
2052
if (!ep->value) compile_err("unknown function",tree[n].str);
2053
C = genclosure(ep,tree[n].str,0,1);
2054
if (!C) compile_err("sorry, closure not implemented",tree[n].str);
2055
if (C==gen_0)
2056
{
2057
compilefunc(ep,n,mode,0);
2058
return;
2059
}
2060
op_push(OCpushgen, data_push(C), n);
2061
compilecast(n,Gclosure,mode);
2062
set_avma(ltop);
2063
}
2064
2065
static void
2066
compileseq(long n, int mode, long flag)
2067
{
2068
pari_sp av = avma;
2069
GEN L = listtogen(n, Fseq);
2070
long i, l = lg(L)-1;
2071
for(i = 1; i < l; i++)
2072
compilenode(L[i],Gvoid,0);
2073
compilenode(L[l],mode,flag&(FLreturn|FLsurvive));
2074
set_avma(av);
2075
}
2076
2077
static void
2078
compilenode(long n, int mode, long flag)
2079
{
2080
long x,y;
2081
#ifdef STACK_CHECK
2082
if (PARI_stack_limit && (void*) &x <= PARI_stack_limit)
2083
pari_err(e_MISC, "expression nested too deeply");
2084
#endif
2085
if (n<0) pari_err_BUG("compilenode");
2086
x=tree[n].x;
2087
y=tree[n].y;
2088
2089
switch(tree[n].f)
2090
{
2091
case Fseq:
2092
compileseq(n, mode, flag);
2093
return;
2094
case Fmatcoeff:
2095
compilematcoeff(n,mode);
2096
if (mode==Ggen && !(flag&FLnocopy))
2097
op_push(OCcopy,0,n);
2098
return;
2099
case Fassign:
2100
x = detag(x);
2101
if (tree[x].f==Fvec && tree[x].x>=0)
2102
{
2103
GEN vars = listtogen(tree[x].x,Fmatrixelts);
2104
long i, l = lg(vars)-1, d = mode==Gvoid? l-1: l;
2105
compilenode(y,Ggen,mode==Gvoid?0:flag&FLsurvive);
2106
for (i=1; i<=l; i++)
2107
if (tree[vars[i]].f==Fnoarg) d--;
2108
if (d) op_push(OCdup, d, x);
2109
for(i=1; i<=l; i++)
2110
if (tree[vars[i]].f!=Fnoarg)
2111
{
2112
long a = detag(vars[i]);
2113
entree *ep=getlvalue(a);
2114
long vn=getmvar(ep);
2115
op_push(OCpushlong,i,a);
2116
op_push(OCcompo1,Ggen,a);
2117
if (tree[a].f==Fentry)
2118
compilestore(vn,ep,n);
2119
else
2120
{
2121
compilenewptr(vn,ep,n);
2122
compilelvalue(a);
2123
op_push(OCstoreptr,0,a);
2124
}
2125
}
2126
if (mode!=Gvoid)
2127
compilecast(n,Ggen,mode);
2128
}
2129
else
2130
{
2131
entree *ep=getlvalue(x);
2132
long vn=getmvar(ep);
2133
if (tree[x].f!=Fentry)
2134
{
2135
compilenewptr(vn,ep,n);
2136
compilelvalue(x);
2137
}
2138
compilenode(y,Ggen,mode==Gvoid?FLnocopy:flag&FLsurvive);
2139
if (mode!=Gvoid)
2140
op_push(OCdup,1,n);
2141
if (tree[x].f==Fentry)
2142
compilestore(vn,ep,n);
2143
else
2144
op_push(OCstoreptr,0,x);
2145
if (mode!=Gvoid)
2146
compilecast(n,Ggen,mode);
2147
}
2148
return;
2149
case Fconst:
2150
{
2151
pari_sp ltop=avma;
2152
if (tree[n].x!=CSTquote)
2153
{
2154
if (mode==Gvoid) return;
2155
if (mode==Gvar) compile_varerr(tree[n].str);
2156
}
2157
if (mode==Gsmall)
2158
compile_err("this should be a small integer", tree[n].str);
2159
switch(tree[n].x)
2160
{
2161
case CSTreal:
2162
op_push(OCpushreal, data_push(strntoGENstr(tree[n].str,tree[n].len)),n);
2163
break;
2164
case CSTint:
2165
op_push(OCpushgen, data_push(strtoi((char*)tree[n].str)),n);
2166
compilecast(n,Ggen, mode);
2167
break;
2168
case CSTstr:
2169
op_push(OCpushgen, data_push(strntoGENexp(tree[n].str,tree[n].len)),n);
2170
break;
2171
case CSTquote:
2172
{ /* skip ' */
2173
entree *ep = fetch_entry_raw(tree[n].str+1,tree[n].len-1);
2174
if (EpSTATIC(ep)) compile_varerr(tree[n].str+1);
2175
op_push(OCpushvar, (long)ep,n);
2176
compilecast(n,Ggen, mode);
2177
break;
2178
}
2179
default:
2180
pari_err_BUG("compilenode, unsupported constant");
2181
}
2182
set_avma(ltop);
2183
return;
2184
}
2185
case Fsmall:
2186
compilesmall(n, x, mode);
2187
return;
2188
case Fvec:
2189
compilevec(n, mode, OCvec);
2190
return;
2191
case Fmat:
2192
compilemat(n, mode);
2193
return;
2194
case Frefarg:
2195
compile_err("unexpected character '&':",tree[n].str);
2196
return;
2197
case Findarg:
2198
compile_err("unexpected character '~':",tree[n].str);
2199
return;
2200
case Fentry:
2201
{
2202
entree *ep=getentry(n);
2203
long vn=getmvar(ep);
2204
if (vn)
2205
{
2206
access_push(vn);
2207
op_push(OCpushlex,(long)vn,n);
2208
addcopy(n,mode,flag,FLnocopy|FLnocopylex);
2209
compilecast(n,Ggen,mode);
2210
}
2211
else if (ep->valence==EpVAR || ep->valence==EpNEW)
2212
{
2213
if (DEBUGLEVEL && mode==Gvoid)
2214
pari_warn(warner,"statement with no effect: `%s'",ep->name);
2215
op_push(OCpushdyn,(long)ep,n);
2216
addcopy(n,mode,flag,FLnocopy);
2217
compilecast(n,Ggen,mode);
2218
}
2219
else
2220
closurefunc(ep,n,mode);
2221
return;
2222
}
2223
case Ffunction:
2224
{
2225
entree *ep=getfunc(n);
2226
if (getmvar(ep) || EpVALENCE(ep)==EpVAR || EpVALENCE(ep)==EpNEW)
2227
{
2228
if (tree[n].x<OPnboperator) /* should not happen */
2229
compile_err("operator unknown",tree[n].str);
2230
compilecall(n,mode,ep);
2231
}
2232
else
2233
compilefunc(ep,n,mode,flag);
2234
return;
2235
}
2236
case Fcall:
2237
compilecall(n,mode,NULL);
2238
return;
2239
case Flambda:
2240
{
2241
pari_sp ltop=avma;
2242
struct codepos pos;
2243
GEN arg=listtogen(x,Flistarg);
2244
long nb, lgarg, nbmvar, dovararg=0, gap;
2245
long strict = GP_DATA->strictargs;
2246
GEN vep = cgetg_copy(arg, &lgarg);
2247
GEN text=cgetg(3,t_VEC);
2248
gel(text,1)=strntoGENstr(tree[x].str,tree[x].len);
2249
gel(text,2)=strntoGENstr(tree[y].str,tree[y].len);
2250
getcodepos(&pos);
2251
dbgstart=tree[x].str+tree[x].len;
2252
gap = tree[y].str-dbgstart;
2253
nbmvar = nblex;
2254
ctxmvar(nbmvar);
2255
nb = lgarg-1;
2256
if (nb)
2257
{
2258
long i;
2259
for(i=1;i<=nb;i++)
2260
{
2261
long a = arg[i], f = tree[a].f;
2262
if (i==nb && f==Fvararg)
2263
{
2264
dovararg=1;
2265
vep[i]=(long)getvar(tree[a].x);
2266
}
2267
else
2268
vep[i]=(long)getvar(f==Fassign||f==Findarg?tree[a].x:a);
2269
var_push(NULL,Lmy);
2270
}
2271
checkdups(arg,vep);
2272
op_push(OCgetargs,nb,x);
2273
access_push(lg(vep)-1);
2274
frame_push(vep);
2275
for (i=1;i<=nb;i++)
2276
{
2277
long a = arg[i], f = tree[a].f;
2278
long y = tree[a].y;
2279
if (f==Fassign && (strict || !is_node_zero(y)))
2280
{
2281
if (tree[y].f==Fsmall)
2282
compilenode(y, Ggen, 0);
2283
else
2284
{
2285
struct codepos lpos;
2286
long nbmvar = nblex;
2287
getcodepos(&lpos);
2288
compilenode(y, Ggen, 0);
2289
op_push(OCpushgen, data_push(getclosure(&lpos,nbmvar)),a);
2290
}
2291
op_push(OCdefaultarg,-nb+i-1,a);
2292
} else if (f==Findarg)
2293
op_push(OCsetref, -nb+i-1, a);
2294
localvars[s_lvar.n-nb+i-1].ep=(entree*)vep[i];
2295
}
2296
}
2297
if (strict)
2298
op_push(OCcheckuserargs,nb,x);
2299
dbgstart=tree[y].str;
2300
if (y>=0 && tree[y].f!=Fnoarg)
2301
compilenode(y,Ggen,FLsurvive|FLreturn);
2302
else
2303
compilecast(n,Gvoid,Ggen);
2304
if (dovararg) nb|=VARARGBITS;
2305
op_push(OCpushgen, data_push(getfunction(&pos,nb,nbmvar,text,gap)),n);
2306
if (nbmvar) op_push(OCsaveframe,!!(flag&FLsurvive),n);
2307
compilecast(n, Gclosure, mode);
2308
set_avma(ltop);
2309
return;
2310
}
2311
case Ftag:
2312
compilenode(x, mode,flag);
2313
return;
2314
case Fnoarg:
2315
compilecast(n,Gvoid,mode);
2316
return;
2317
case Fnorange:
2318
op_push(OCpushlong,LONG_MAX,n);
2319
compilecast(n,Gsmall,mode);
2320
return;
2321
default:
2322
pari_err_BUG("compilenode");
2323
}
2324
}
2325
2326
GEN
2327
gp_closure(long n)
2328
{
2329
struct codepos pos;
2330
getcodepos(&pos);
2331
dbgstart=tree[n].str;
2332
compilenode(n,Ggen,FLsurvive|FLreturn);
2333
return getfunction(&pos,0,0,strntoGENstr(tree[n].str,tree[n].len),0);
2334
}
2335
2336
GEN
2337
closure_derivn(GEN G, long n)
2338
{
2339
pari_sp ltop = avma;
2340
struct codepos pos;
2341
long arity = closure_arity(G);
2342
const char *code;
2343
GEN t, text;
2344
2345
if (arity == 0 || closure_is_variadic(G)) pari_err_TYPE("derivfun",G);
2346
t = closure_get_text(G);
2347
code = GSTR((typ(t) == t_STR)? t: GENtoGENstr(G));
2348
if (n > 1)
2349
{
2350
text = cgetg(1+nchar2nlong(9+strlen(code)+n),t_STR);
2351
sprintf(GSTR(text), "derivn(%s,%ld)", code, n);
2352
}
2353
else
2354
{
2355
text = cgetg(1+nchar2nlong(4+strlen(code)),t_STR);
2356
sprintf(GSTR(text), (typ(t) == t_STR)? "%s'": "(%s)'",code);
2357
}
2358
getcodepos(&pos);
2359
dbgstart = code;
2360
op_push_loc(OCpackargs, arity, code);
2361
op_push_loc(OCpushgen, data_push(G), code);
2362
op_push_loc(OCpushlong, n, code);
2363
op_push_loc(OCprecreal, 0, code);
2364
op_push_loc(OCcallgen, (long)is_entry("_derivfun"), code);
2365
return gerepilecopy(ltop, getfunction(&pos, arity, 0, text, 0));
2366
}
2367
2368
GEN
2369
closure_deriv(GEN G)
2370
{ return closure_derivn(G, 1); }
2371
2372
static long
2373
vec_optimize(GEN arg)
2374
{
2375
long fl = COsafelex|COsafedyn;
2376
long i;
2377
for (i=1; i<lg(arg); i++)
2378
{
2379
optimizenode(arg[i]);
2380
fl &= tree[arg[i]].flags;
2381
}
2382
return fl;
2383
}
2384
2385
static void
2386
optimizevec(long n)
2387
{
2388
pari_sp ltop=avma;
2389
long x = tree[n].x;
2390
GEN arg = listtogen(x, Fmatrixelts);
2391
tree[n].flags = vec_optimize(arg);
2392
set_avma(ltop);
2393
}
2394
2395
static void
2396
optimizemat(long n)
2397
{
2398
pari_sp ltop = avma;
2399
long x = tree[n].x;
2400
long i;
2401
GEN line = listtogen(x,Fmatrixlines);
2402
long fl = COsafelex|COsafedyn;
2403
for(i=1;i<lg(line);i++)
2404
{
2405
GEN col=listtogen(line[i],Fmatrixelts);
2406
fl &= vec_optimize(col);
2407
}
2408
set_avma(ltop); tree[n].flags=fl;
2409
}
2410
2411
static void
2412
optimizematcoeff(long n)
2413
{
2414
long x=tree[n].x;
2415
long y=tree[n].y;
2416
long yx=tree[y].x;
2417
long yy=tree[y].y;
2418
long fl;
2419
optimizenode(x);
2420
optimizenode(yx);
2421
fl=tree[x].flags&tree[yx].flags;
2422
if (yy>=0)
2423
{
2424
optimizenode(yy);
2425
fl&=tree[yy].flags;
2426
}
2427
tree[n].flags=fl;
2428
}
2429
2430
static void
2431
optimizefunc(entree *ep, long n)
2432
{
2433
pari_sp av=avma;
2434
long j;
2435
long x=tree[n].x;
2436
long y=tree[n].y;
2437
Gtype t;
2438
PPproto mod;
2439
long fl=COsafelex|COsafedyn;
2440
const char *p;
2441
char c;
2442
GEN arg = listtogen(y,Flistarg);
2443
long nb=lg(arg)-1, ret_flag;
2444
if (is_func_named(ep,"if") && nb>=4)
2445
ep=is_entry("_multi_if");
2446
p = ep->code;
2447
if (!p)
2448
fl=0;
2449
else
2450
(void) get_ret_type(&p, 2, &t, &ret_flag);
2451
if (p && *p)
2452
{
2453
j=1;
2454
while((mod=parseproto(&p,&c,tree[n].str))!=PPend)
2455
{
2456
if (j<=nb && tree[arg[j]].f!=Fnoarg
2457
&& (mod==PPdefault || mod==PPdefaultmulti))
2458
mod=PPstd;
2459
switch(mod)
2460
{
2461
case PPstd:
2462
if (j>nb) compile_err("too few arguments", tree[n].str+tree[n].len-1);
2463
if (tree[arg[j]].f==Fnoarg && c!='I' && c!='E')
2464
compile_err("missing mandatory argument", tree[arg[j]].str);
2465
switch(c)
2466
{
2467
case 'G':
2468
case 'n':
2469
case 'M':
2470
case 'L':
2471
case 'U':
2472
case 'P':
2473
optimizenode(arg[j]);
2474
fl&=tree[arg[j++]].flags;
2475
break;
2476
case 'I':
2477
case 'E':
2478
case 'J':
2479
optimizenode(arg[j]);
2480
fl&=tree[arg[j]].flags;
2481
tree[arg[j++]].flags=COsafelex|COsafedyn;
2482
break;
2483
case '&': case '*':
2484
{
2485
long a=arg[j];
2486
if (c=='&')
2487
{
2488
if (tree[a].f!=Frefarg)
2489
compile_err("expected character: '&'", tree[a].str);
2490
a=tree[a].x;
2491
}
2492
optimizenode(a);
2493
tree[arg[j++]].flags=COsafelex|COsafedyn;
2494
fl=0;
2495
break;
2496
}
2497
case 'W':
2498
{
2499
long a = tree[arg[j]].f==Findarg ? tree[arg[j]].x: arg[j];
2500
optimizenode(a);
2501
fl=0; j++;
2502
break;
2503
}
2504
case 'V':
2505
case 'r':
2506
tree[arg[j++]].flags=COsafelex|COsafedyn;
2507
break;
2508
case '=':
2509
{
2510
long a=arg[j++], y=tree[a].y;
2511
if (tree[a].f!=Fassign)
2512
compile_err("expected character: '=' instead of",
2513
tree[a].str+tree[a].len);
2514
optimizenode(y);
2515
fl&=tree[y].flags;
2516
}
2517
break;
2518
case 's':
2519
fl &= vec_optimize(cattovec(arg[j++], OPcat));
2520
break;
2521
default:
2522
pari_err(e_MISC,"Unknown prototype code `%c' for `%.*s'",c,
2523
tree[x].len, tree[x].str);
2524
}
2525
break;
2526
case PPauto:
2527
break;
2528
case PPdefault:
2529
case PPdefaultmulti:
2530
if (j<=nb) optimizenode(arg[j++]);
2531
break;
2532
case PPstar:
2533
switch(c)
2534
{
2535
case 'E':
2536
{
2537
long n=nb+1-j;
2538
long k;
2539
for(k=1;k<=n;k++)
2540
{
2541
optimizenode(arg[j+k-1]);
2542
fl &= tree[arg[j+k-1]].flags;
2543
}
2544
j=nb+1;
2545
break;
2546
}
2547
case 's':
2548
{
2549
long n=nb+1-j;
2550
long k;
2551
for(k=1;k<=n;k++)
2552
fl &= vec_optimize(cattovec(arg[j+k-1],OPcat));
2553
j=nb+1;
2554
break;
2555
}
2556
default:
2557
pari_err(e_MISC,"Unknown prototype code `%c*' for `%.*s'",c,
2558
tree[x].len, tree[x].str);
2559
}
2560
break;
2561
default:
2562
pari_err_BUG("optimizefun [unknown PPproto]");
2563
}
2564
}
2565
if (j<=nb)
2566
compile_err("too many arguments",tree[arg[j]].str);
2567
}
2568
else (void)vec_optimize(arg);
2569
set_avma(av); tree[n].flags=fl;
2570
}
2571
2572
static void
2573
optimizecall(long n)
2574
{
2575
pari_sp av=avma;
2576
long x=tree[n].x;
2577
long y=tree[n].y;
2578
GEN arg=listtogen(y,Flistarg);
2579
optimizenode(x);
2580
tree[n].flags = COsafelex&tree[x].flags&vec_optimize(arg);
2581
set_avma(av);
2582
}
2583
2584
static void
2585
optimizeseq(long n)
2586
{
2587
pari_sp av = avma;
2588
GEN L = listtogen(n, Fseq);
2589
long i, l = lg(L)-1, flags=-1L;
2590
for(i = 1; i <= l; i++)
2591
{
2592
optimizenode(L[i]);
2593
flags &= tree[L[i]].flags;
2594
}
2595
set_avma(av);
2596
tree[n].flags = flags;
2597
}
2598
2599
void
2600
optimizenode(long n)
2601
{
2602
long x,y;
2603
#ifdef STACK_CHECK
2604
if (PARI_stack_limit && (void*) &x <= PARI_stack_limit)
2605
pari_err(e_MISC, "expression nested too deeply");
2606
#endif
2607
if (n<0)
2608
pari_err_BUG("optimizenode");
2609
x=tree[n].x;
2610
y=tree[n].y;
2611
2612
switch(tree[n].f)
2613
{
2614
case Fseq:
2615
optimizeseq(n);
2616
return;
2617
case Frange:
2618
optimizenode(x);
2619
optimizenode(y);
2620
tree[n].flags=tree[x].flags&tree[y].flags;
2621
break;
2622
case Fmatcoeff:
2623
optimizematcoeff(n);
2624
break;
2625
case Fassign:
2626
optimizenode(x);
2627
optimizenode(y);
2628
tree[n].flags=0;
2629
break;
2630
case Fnoarg:
2631
case Fnorange:
2632
case Fsmall:
2633
case Fconst:
2634
case Fentry:
2635
tree[n].flags=COsafelex|COsafedyn;
2636
return;
2637
case Fvec:
2638
optimizevec(n);
2639
return;
2640
case Fmat:
2641
optimizemat(n);
2642
return;
2643
case Frefarg:
2644
compile_err("unexpected character '&'",tree[n].str);
2645
return;
2646
case Findarg:
2647
return;
2648
case Fvararg:
2649
compile_err("unexpected characters '..'",tree[n].str);
2650
return;
2651
case Ffunction:
2652
{
2653
entree *ep=getfunc(n);
2654
if (EpVALENCE(ep)==EpVAR || EpVALENCE(ep)==EpNEW)
2655
optimizecall(n);
2656
else
2657
optimizefunc(ep,n);
2658
return;
2659
}
2660
case Fcall:
2661
optimizecall(n);
2662
return;
2663
case Flambda:
2664
optimizenode(y);
2665
tree[n].flags=COsafelex|COsafedyn;
2666
return;
2667
case Ftag:
2668
optimizenode(x);
2669
tree[n].flags=tree[x].flags;
2670
return;
2671
default:
2672
pari_err_BUG("optimizenode");
2673
}
2674
}
2675
2676