Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

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

28495 views
License: GPL3
ubuntu2004
1
/* Copyright (C) 2000 The PARI group.
2
3
This file is part of the PARI/GP 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
/*******************************************************************/
16
/** **/
17
/** PARI CALCULATOR **/
18
/** **/
19
/*******************************************************************/
20
#ifdef _WIN32
21
# include "../systems/mingw/pwinver.h"
22
# include <windows.h>
23
# include "../systems/mingw/mingw.h"
24
#endif
25
#include "pari.h"
26
#include "paripriv.h"
27
#include "gp.h"
28
29
static jmp_buf *env;
30
static pari_stack s_env;
31
void (*cb_gp_output)(GEN z) = NULL;
32
void (*cb_pari_end_output)(void) = NULL;
33
34
static void
35
gp_ask_confirm(const char *s)
36
{
37
err_printf(s);
38
err_printf(". OK ? (^C if not)\n");
39
pari_hit_return();
40
}
41
42
/* numerr < 0: after changing PARI stack size
43
* numerr > 0: normal error, including SIGINT */
44
static void
45
gp_err_recover(long numerr)
46
{
47
longjmp(env[s_env.n-1], numerr);
48
}
49
50
/* numerr >= 0 */
51
static void
52
gp_pre_recover(long numerr)
53
{
54
out_puts(pariErr, "\n"); pariErr->flush();
55
gp_err_recover(numerr);
56
}
57
58
static void
59
reset_ctrlc(void)
60
{
61
#if defined(_WIN32) || defined(__CYGWIN32__)
62
win32ctrlc = 0;
63
#endif
64
}
65
66
static int
67
is_silent(char *s) { return s[strlen(s) - 1] == ';'; }
68
69
static int stdin_isatty = 0;
70
static int
71
is_interactive(void)
72
{ return pari_infile == stdin && stdin_isatty; }
73
74
/*******************************************************************/
75
/** **/
76
/** INITIALIZATION **/
77
/** **/
78
/*******************************************************************/
79
static void
80
print_shortversion(void)
81
{
82
const ulong mask = (1UL<<PARI_VERSION_SHIFT) - 1;
83
ulong n = paricfg_version_code, major, minor, patch;
84
85
patch = n & mask; n >>= PARI_VERSION_SHIFT;
86
minor = n & mask; n >>= PARI_VERSION_SHIFT;
87
major = n;
88
printf("%lu.%lu.%lu\n", major,minor,patch); exit(0);
89
}
90
91
static void
92
usage(char *s)
93
{
94
printf("### Usage: %s [options] [GP files]\n", s);
95
printf("Available options:\n");
96
printf(" [-f,--fast]\t\tFast start: do not read .gprc\n");
97
printf(" [-q,--quiet]\t\tQuiet mode: do not print banner and history numbers\n");
98
printf(" [-s stacksize]\tStart with the PARI stack of given size (in bytes)\n");
99
printf(" [--default key=val]\tExecute default(key,val) on startup\n");
100
printf(" [--emacs]\t\tRun as if in Emacs shell\n");
101
printf(" [--help]\t\tPrint this message\n");
102
printf(" [--test]\t\tTest mode. No history, wrap long lines (bench only)\n");
103
printf(" [--texmacs]\t\tRun as if using TeXmacs frontend\n");
104
printf(" [--version]\t\tOutput version info and exit\n");
105
printf(" [--version-short]\tOutput version number and exit\n\n");
106
exit(0);
107
}
108
109
static void
110
gp_head(void)
111
{
112
pari_print_version();
113
pari_putc('\n');
114
pari_center("Copyright (C) 2000-2021 The PARI Group");
115
pari_putc('\n');
116
print_text("PARI/GP is free software, covered by the GNU General Public \
117
License, and comes WITHOUT ANY WARRANTY WHATSOEVER.");
118
pari_puts("\nType ? for help, \\q to quit.\n");
119
pari_printf("Type ?%d for how to get moral"
120
" (and possibly technical) support.\n", pari_community());
121
if (pari_mainstack->vsize)
122
pari_printf("\nparisizemax = %lu, primelimit = %lu",
123
pari_mainstack->vsize,GP_DATA->primelimit);
124
else
125
pari_printf("\nparisize = %lu, primelimit = %lu",
126
pari_mainstack->rsize,GP_DATA->primelimit);
127
if (pari_mt_nbthreads > 1)
128
pari_printf(", nbthreads = %lu", pari_mt_nbthreads);
129
pari_putc('\n');
130
}
131
132
static char *
133
read_arg(long *nread, char *t, long argc, char **argv)
134
{
135
long i = *nread;
136
if (isdigit((int)*t)) return t;
137
if (*t || i==argc) usage(argv[0]);
138
*nread = i+1; return argv[i];
139
}
140
141
static char *
142
read_arg_equal(long *nread, char *t, long argc, char **argv)
143
{
144
long i = *nread;
145
if (*t=='=' && isdigit((int)t[1])) return t+1;
146
if (*t || i==argc) usage(argv[0]);
147
*nread = i+1; return argv[i];
148
}
149
150
static void
151
init_trivial_stack(void)
152
{
153
const size_t s = 2048;
154
pari_mainstack->size = s;
155
pari_mainstack->bot = (pari_sp)pari_malloc(s);
156
avma = pari_mainstack->top = pari_mainstack->bot + s;
157
}
158
159
static void
160
free_trivial_stack(void)
161
{
162
free((void*)pari_mainstack->bot);
163
}
164
165
typedef struct { char *key, *val; } pair_t;
166
/* If ab of the form key=val, record pair in new stack entry
167
* P[n].key must be freed by caller to avoid memory leak */
168
static void
169
record_default(pari_stack *s_P, char *ab)
170
{
171
pair_t *P = (pair_t*)*pari_stack_base(s_P);
172
char *k, *v;
173
long n;
174
ab = pari_strdup(ab);
175
parse_key_val(ab, &k, &v);
176
n = pari_stack_new(s_P);
177
P[n].key = k;
178
P[n].val = v;
179
}
180
static void
181
read_opt(pari_stack *p_A, long argc, char **argv)
182
{
183
pair_t *P;
184
pari_stack s_P; /* key / value to record default() settings */
185
char *b = NULL, *p = NULL, *s = NULL;
186
ulong f = GP_DATA->flags;
187
long i = 1, initrc = 1;
188
189
(void)&p; (void)&b; (void)&s; /* -Wall gcc-2.95 */
190
191
pari_stack_init(&s_P,sizeof(*P),(void**)&P);
192
pari_stack_alloc(&s_P, 64);
193
pari_outfile = stderr;
194
while (i < argc)
195
{
196
char *t = argv[i];
197
198
if (*t++ != '-') break;
199
i++;
200
START:
201
switch(*t++)
202
{
203
case 'p': p = read_arg(&i,t,argc,argv); break;
204
case 's': s = read_arg(&i,t,argc,argv); break;
205
case 'e':
206
f |= gpd_EMACS; if (*t) goto START;
207
break;
208
case 'q':
209
f |= gpd_QUIET; if (*t) goto START;
210
break;
211
case 't':
212
f |= gpd_TEST; if (*t) goto START;
213
break;
214
case 'f':
215
initrc = 0; if (*t) goto START;
216
break;
217
case 'D':
218
if (*t || i == argc) usage(argv[0]);
219
record_default(&s_P, argv[i++]);
220
break;
221
case '-':
222
if (strcmp(t, "version-short") == 0) { print_shortversion(); exit(0); }
223
if (strcmp(t, "version") == 0) {
224
init_trivial_stack(); pari_print_version();
225
free_trivial_stack(); exit(0);
226
}
227
if (strcmp(t, "default") == 0) {
228
if (i == argc) usage(argv[0]);
229
record_default(&s_P, argv[i++]);
230
break;
231
}
232
if (strcmp(t, "texmacs") == 0) { f |= gpd_TEXMACS; break; }
233
if (strcmp(t, "emacs") == 0) { f |= gpd_EMACS; break; }
234
if (strcmp(t, "test") == 0) { f |= gpd_TEST; initrc = 0; break; }
235
if (strcmp(t, "quiet") == 0) { f |= gpd_QUIET; break; }
236
if (strcmp(t, "fast") == 0) { initrc = 0; break; }
237
if (strncmp(t, "primelimit",10) == 0) {p = read_arg_equal(&i,t+10,argc,argv); break; }
238
if (strncmp(t, "stacksize",9) == 0) {s = read_arg_equal(&i,t+9,argc,argv); break; }
239
/* fall through */
240
default:
241
usage(argv[0]);
242
}
243
}
244
if (f & gpd_TEST) stdin_isatty = 0;
245
GP_DATA->flags = f;
246
#ifdef READLINE
247
GP_DATA->use_readline = stdin_isatty;
248
#endif
249
if (!is_interactive()) GP_DATA->breakloop = 0;
250
if (initrc) gp_initrc(p_A);
251
for ( ; i < argc; i++) pari_stack_pushp(p_A, pari_strdup(argv[i]));
252
253
/* override the values from gprc */
254
if (p) (void)sd_primelimit(p, d_INITRC);
255
if (s) (void)sd_parisize(s, d_INITRC);
256
for (i = 0; i < s_P.n; i++) {
257
setdefault(P[i].key, P[i].val, d_INITRC);
258
free((void*)P[i].key);
259
}
260
pari_stack_delete(&s_P);
261
pari_outfile = stdout;
262
}
263
264
/*******************************************************************/
265
/** **/
266
/** TEST MODE **/
267
/** **/
268
/*******************************************************************/
269
static int
270
test_is_interactive(void) { return 0; }
271
272
static void
273
test_output(GEN z) { init_linewrap(76); gen_output(z); }
274
void
275
init_test(void)
276
{
277
disable_color = 1;
278
init_linewrap(76);
279
pari_errfile = stdout;
280
cb_gp_output = test_output;
281
cb_pari_is_interactive = test_is_interactive;
282
}
283
284
/*******************************************************************/
285
/** **/
286
/** FORMAT GP OUTPUT **/
287
/** **/
288
/*******************************************************************/
289
/* REGULAR */
290
static void
291
normal_output(GEN z, long n)
292
{
293
long l = 0;
294
char *s;
295
/* history number */
296
if (n)
297
{
298
char buf[64];
299
if (!(GP_DATA->flags & gpd_QUIET))
300
{
301
term_color(c_HIST);
302
sprintf(buf, "%%%ld = ", n);
303
pari_puts(buf);
304
l = strlen(buf);
305
}
306
}
307
/* output */
308
term_color(c_OUTPUT);
309
s = GENtostr(z);
310
if (GP_DATA->lim_lines)
311
lim_lines_output(s, l, GP_DATA->lim_lines);
312
else
313
pari_puts(s);
314
pari_free(s);
315
term_color(c_NONE); pari_putc('\n');
316
}
317
318
static void
319
gp_output(GEN z)
320
{
321
if (cb_gp_output) { cb_gp_output(z); return; }
322
if (GP_DATA->fmt->prettyp == f_PRETTY)
323
{ if (tex2mail_output(z, GP_DATA->hist->total)) return; }
324
normal_output(z, GP_DATA->hist->total);
325
pari_flush();
326
}
327
328
static GEN
329
gp_main_loop(long ismain)
330
{
331
VOLATILE GEN z = gnil;
332
VOLATILE long t = 0, r = 0;
333
VOLATILE pari_sp av = avma;
334
filtre_t F;
335
Buffer *b = filtered_buffer(&F);
336
struct gp_context rec;
337
long er;
338
if ((er = setjmp(env[s_env.n-1])))
339
{ /* recover: jump from error [ > 0 ] or allocatemem [ -1 ] */
340
if (er > 0) { /* true error */
341
if (!(GP_DATA->recover)) exit(1);
342
gp_context_restore(&rec);
343
/* true error not from main instance, let caller sort it out */
344
if (!ismain) { kill_buffers_upto_including(b); return NULL; }
345
} else { /* allocatemem */
346
tmp_restore(rec.file.file);
347
gp_context_save(&rec);
348
}
349
set_avma(av = pari_mainstack->top);
350
parivstack_reset();
351
kill_buffers_upto(b);
352
pari_alarm(0);
353
}
354
for(;;)
355
{
356
gp_context_save(&rec);
357
if (! gp_read_line(&F, NULL))
358
{
359
if (popinfile()) gp_quit(0);
360
if (ismain) continue;
361
pop_buffer(); return z;
362
}
363
if (ismain)
364
{
365
reset_ctrlc();
366
timer_start(GP_DATA->T);
367
walltimer_start(GP_DATA->Tw);
368
pari_set_last_newline(1);
369
}
370
if (gp_meta(b->buf,ismain)) continue;
371
z = pari_compile_str(b->buf);
372
z = closure_evalres(z);
373
if (!ismain) continue;
374
375
t = timer_delay(GP_DATA->T);
376
r = walltimer_delay(GP_DATA->Tw);
377
if (!pari_last_was_newline()) pari_putc('\n');
378
pari_alarm(0);
379
if (t && GP_DATA->chrono)
380
{
381
if (pari_mt_nbthreads==1)
382
{
383
pari_puts("time = ");
384
pari_puts(gp_format_time(t));
385
}
386
else
387
{
388
pari_puts("cpu time = ");
389
pari_puts(gp_format_time(t));
390
pari_puts(", real time = ");
391
pari_puts(gp_format_time(r));
392
}
393
pari_puts(".\n");
394
}
395
if (GP_DATA->simplify) z = simplify_shallow(z);
396
pari_add_hist(z, t, r);
397
if (z != gnil && ! is_silent(b->buf) ) gp_output(z);
398
set_avma(av);
399
parivstack_reset();
400
}
401
}
402
403
/* as gp_read_file, before running the main gp instance */
404
static void
405
read_main(const char *s)
406
{
407
GEN z;
408
if (setjmp(env[s_env.n-1]))
409
z = NULL;
410
else {
411
FILE *f = switchin(s);
412
if (file_is_binary(f)) {
413
z = readbin(s,f, NULL);
414
popinfile();
415
}
416
else z = gp_main_loop(0);
417
}
418
if (!z) err_printf("... skipping file '%s'\n", s);
419
set_avma(pari_mainstack->top);
420
}
421
422
static const char *
423
break_loop_prompt(long n)
424
{
425
const char *s = (n==1)? "break> ": stack_sprintf("break[%ld]> ", n);
426
return gp_format_prompt(s);
427
}
428
429
static long frame_level=0, dbg_level = 0;
430
431
static int
432
break_loop(int numerr)
433
{
434
filtre_t F;
435
Buffer *b;
436
int sigint = numerr<0, go_on = sigint;
437
struct gp_context rec1, rec2;
438
const char *prompt, *msg;
439
long nenv, oldframe_level = frame_level;
440
pari_sp av;
441
442
if (numerr == e_SYNTAX) return 0;
443
if (numerr == e_STACK) { evalstate_clone(); set_avma(pari_mainstack->top); }
444
gp_context_save(&rec1);
445
446
b = filtered_buffer(&F);
447
nenv=pari_stack_new(&s_env);
448
prompt = break_loop_prompt(s_env.n-1);
449
iferr_env = NULL;
450
dbg_level = 0;
451
frame_level = closure_context(oldframe_level, dbg_level);
452
pari_infile = newfile(stdin, "stdin", mf_IN)->file;
453
term_color(c_ERR); pari_putc('\n');
454
if (sigint)
455
msg = "Break loop: <Return> to continue; 'break' to go back to GP prompt";
456
else
457
msg = "Break loop: type 'break' to go back to GP prompt";
458
print_errcontext(pariOut, msg, NULL, NULL);
459
term_color(c_NONE);
460
av = avma;
461
for(;;)
462
{
463
GEN x;
464
long er, br_status;
465
set_avma(av);
466
gp_context_save(&rec2);
467
if ((er=setjmp(env[nenv])))
468
{
469
if (er < 0)
470
{
471
s_env.n = 1;
472
frame_level = oldframe_level;
473
longjmp(env[s_env.n-1], er);
474
}
475
gp_context_restore(&rec2);
476
iferr_env = NULL;
477
closure_err(dbg_level);
478
compilestate_restore(&rec1.eval.comp);
479
(void) closure_context(oldframe_level, dbg_level);
480
pari_infile = newfile(stdin, "stdin", mf_IN)->file;
481
}
482
term_color(c_NONE);
483
if (!gp_read_line(&F, prompt))
484
br_status = br_BREAK; /* EOF */
485
else
486
{
487
/* Empty input ? Continue if entry on sigint (exit debugger frame) */
488
if (! *(b->buf) && sigint) break;
489
reset_ctrlc();
490
if (gp_meta(b->buf,0)) continue;
491
x = pari_compile_str(b->buf);
492
x = closure_evalbrk(x, &br_status);
493
}
494
switch (br_status)
495
{
496
case br_NEXT: case br_MULTINEXT:
497
popinfile(); /* exit frame. Don't exit debugger if s_env.n > 2 */
498
go_on = 0; goto BR_EXIT;
499
case br_BREAK: case br_RETURN:
500
killallfiles(); /* completely exit the debugger */
501
go_on = 0; goto BR_EXIT;
502
}
503
if (x!=gnil && !is_silent(b->buf)) { term_color(c_OUTPUT); gen_output(x); }
504
}
505
BR_EXIT:
506
s_env.n=nenv;
507
frame_level = oldframe_level;
508
gp_context_restore(&rec1);
509
pop_buffer(); return go_on;
510
}
511
512
#ifdef __CYGWIN32__
513
void
514
cyg_environment(int argc, char ** argv)
515
{
516
char *ti_dirs = getenv("TERMINFO_DIRS");
517
char *argv0, *p;
518
char *newdir;
519
long n;
520
521
if (!argc || !argv) return;
522
argv0 = *argv;
523
if (!argv0 || !*argv0) return;
524
p = strrchr(argv0, '/');
525
if (!p)
526
p = argv0 = "";
527
else
528
p++;
529
n = p - argv0;
530
if (ti_dirs)
531
{
532
n += 14 + strlen(ti_dirs) + 1 + 8 + 1;
533
newdir = malloc(n);
534
if (!newdir) return;
535
snprintf(newdir, n-8, "TERMINFO_DIRS=%s:%s", ti_dirs, argv0);
536
}
537
else
538
{
539
n += 14 + 8 + 1;
540
newdir = malloc(n);
541
if (!newdir) return;
542
snprintf(newdir, n-8, "TERMINFO_DIRS=%s", argv0);
543
}
544
strcpy(newdir+n-9,"terminfo");
545
putenv(newdir);
546
}
547
#endif
548
549
int
550
main(int argc, char **argv)
551
{
552
char **A;
553
pari_stack s_A;
554
555
GP_DATA = default_gp_data();
556
pari_stack_init(&s_env, sizeof(*env), (void**)&env);
557
(void)pari_stack_new(&s_env);
558
559
if (setjmp(env[s_env.n-1]))
560
{
561
puts("### Errors on startup, exiting...\n\n");
562
exit(1);
563
}
564
#ifdef __CYGWIN32__
565
cyg_environment(argc, argv);
566
#endif
567
stdin_isatty = pari_stdin_isatty();
568
pari_init_defaults();
569
pari_library_path = DL_DFLT_NAME;
570
pari_stack_init(&s_A,sizeof(*A),(void**)&A);
571
/* must be defined here in case an error is raised in pari_init_opts, e.g.
572
* when parsing function prototypes */
573
cb_pari_err_recover = gp_err_recover;
574
pari_init_opts(1000000 * sizeof(long), 0, INIT_SIGm | INIT_noPRIMEm | INIT_noIMTm);
575
cb_pari_pre_recover = gp_pre_recover;
576
cb_pari_break_loop = break_loop;
577
cb_pari_is_interactive = is_interactive;
578
579
read_opt(&s_A, argc,argv);
580
pari_init_primes(GP_DATA->primelimit);
581
#ifdef SIGALRM
582
(void)os_signal(SIGALRM,gp_alarm_handler);
583
#endif
584
pari_add_module(functions_gp);
585
586
pari_set_plot_engine(gp_get_plot);
587
cb_pari_quit = gp_quit;
588
cb_pari_whatnow = whatnow;
589
cb_pari_sigint = gp_sigint_fun;
590
cb_pari_handle_exception = gp_handle_exception;
591
cb_pari_ask_confirm = gp_ask_confirm;
592
pari_init_paths();
593
pari_mt_init(); /* MPI: will not return on slaves (pari_MPI_rank = 0) */
594
#ifdef _WIN32
595
if (stdin_isatty) win32_set_codepage();
596
#endif
597
#ifdef READLINE
598
init_readline();
599
#endif
600
if (GP_DATA->flags & gpd_EMACS) init_emacs();
601
if (GP_DATA->flags & gpd_TEXMACS) init_texmacs();
602
603
timer_start(GP_DATA->T);
604
walltimer_start(GP_DATA->Tw);
605
if (!(GP_DATA->flags & gpd_QUIET)) gp_head();
606
if (GP_DATA->flags & gpd_TEST) init_test();
607
if (s_A.n)
608
{
609
FILE *l = pari_logfile;
610
long i;
611
pari_logfile = NULL;
612
for (i = 0; i < s_A.n; pari_free(A[i]),i++) read_main(A[i]);
613
/* Reading one of the input files above can set pari_logfile.
614
* Don't restore in that case. */
615
if (!pari_logfile) pari_logfile = l;
616
}
617
pari_stack_delete(&s_A);
618
(void)gp_main_loop(1);
619
gp_quit(0);
620
return 0; /* LCOV_EXCL_LINE */
621
}
622
623
void
624
pari_breakpoint(void)
625
{
626
if (!pari_last_was_newline()) pari_putc('\n');
627
closure_err(0);
628
if (cb_pari_break_loop && cb_pari_break_loop(-1)) return;
629
cb_pari_err_recover(e_MISC);
630
}
631
632
void
633
dbg_down(long k)
634
{
635
if (k<0) k=0;
636
dbg_level -= k;
637
if (dbg_level<0) dbg_level=0;
638
gp_err_recover(e_NONE);
639
}
640
641
GEN
642
dbg_err(void) { GEN E = pari_err_last(); return E? gcopy(E):gnil; }
643
644
void
645
dbg_up(long k)
646
{
647
if (k<0) k=0;
648
dbg_level += k;
649
if (dbg_level>frame_level) dbg_level=frame_level;
650
gp_err_recover(e_NONE);
651
}
652
653
void
654
gp_quit(long code)
655
{
656
pari_kill_plot_engine();
657
pari_close();
658
kill_buffers_upto(NULL);
659
if (!(GP_DATA->flags & gpd_QUIET)) pari_puts("Goodbye!\n");
660
if (cb_pari_end_output) cb_pari_end_output();
661
exit(code);
662
}
663
664
void
665
whatnow0(char *s) { whatnow(pariOut, s,0); }
666
667
#include "gp_init.h"
668
669