Skip to content

Commit 31dfed7

Browse files
committed
automatic generation of paridecl
1 parent 17724ff commit 31dfed7

File tree

7 files changed

+77
-38
lines changed

7 files changed

+77
-38
lines changed

autogen/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ def rebuild(force=False):
1212
pari_module_path = 'cypari2'
1313
src_files = [join(pari_share(), b'pari.desc')] + \
1414
glob.glob(join('autogen', '*.py'))
15-
gen_files = [join(pari_module_path, 'auto_gen.pxi')]
15+
gen_files = [join(pari_module_path, 'auto_paridecl.pxd'),
16+
join(pari_module_path, 'auto_gen.pxi')]
1617

17-
if all(exists(f) for f in gen_files):
18+
if not force and all(exists(f) for f in gen_files):
1819
src_mtime = max(getmtime(f) for f in src_files)
1920
gen_mtime = min(getmtime(f) for f in gen_files)
2021

21-
if gen_mtime > src_mtime and not force:
22+
if gen_mtime > src_mtime:
2223
return
2324

2425
G = PariFunctionGenerator()

autogen/args.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,15 @@ def __init__(self):
179179
PariArgument.__init__(self, iter(["self"]), None, 0)
180180
def _typerepr(self):
181181
return "Pari"
182+
def ctype(self):
183+
return "GEN"
182184

183185

184186
class PariArgumentGEN(PariArgumentObject):
185187
def _typerepr(self):
186188
return "GEN"
189+
def ctype(self):
190+
return "GEN"
187191
def convert_code(self):
188192
if self.index == 0:
189193
# "self" is always of type Gen, we skip the conversion
@@ -219,6 +223,8 @@ def call_code(self):
219223
class PariArgumentString(PariArgumentObject):
220224
def _typerepr(self):
221225
return "str"
226+
def ctype(self):
227+
return "char *"
222228
def convert_code(self):
223229
if self.default is None:
224230
s = " {name} = to_bytes({name})\n"
@@ -237,6 +243,8 @@ def call_code(self):
237243
class PariArgumentVariable(PariArgumentObject):
238244
def _typerepr(self):
239245
return "var"
246+
def ctype(self):
247+
return "long"
240248
def default_default(self):
241249
return "-1"
242250
def convert_code(self):

autogen/generator.py

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#*****************************************************************************
66
# Copyright (C) 2015 Jeroen Demeyer <[email protected]>
7+
# 2017 Vincent Delecroix <[email protected]>
78
#
89
# This program is free software: you can redistribute it and/or modify
910
# it under the terms of the GNU General Public License as published by
@@ -16,7 +17,7 @@
1617
import os, re, sys
1718

1819
from .args import PariArgumentGEN, PariInstanceArgument
19-
from .parser import (read_pari_desc, read_decl, parse_prototype)
20+
from .parser import read_pari_desc, parse_prototype
2021
from .doc import get_rest_doc
2122

2223

@@ -42,12 +43,52 @@
4243
"""
4344
'''.format(__file__)
4445

46+
decl_banner='''# This file is auto-generated by {}
47+
48+
from .types cimport *
49+
50+
cdef extern from *:
51+
'''.format(__file__)
52+
4553

4654
function_re = re.compile(r"^[A-Za-z][A-Za-z0-9_]*$")
4755
function_blacklist = {"O", # O(p^e) needs special parser support
4856
"alias", # Not needed and difficult documentation
4957
"listcreate", # "redundant and obsolete" according to PARI
5058
"allocatemem", # Better hand-written support in Pari class
59+
"global", # Invalid in Python (and obsolete)
60+
"inline", # Total confusion
61+
"uninline", # idem
62+
"local", # idem
63+
"my", # idem
64+
"plot", # Graphical function undeclared in pari public headers
65+
"plotbox", # idem
66+
"plotclip", # idem
67+
"plotcursor", # idem
68+
"plotcolor", # idem
69+
"plotcopy", # idem
70+
"plotdraw", # idem
71+
"plothsizes", # idem
72+
"plotinit", # idem
73+
"plotkill", # idem
74+
"plotlines", # idem
75+
"plotlinetype", # idem
76+
"plotmove", # idem
77+
"plotpoints", # idem
78+
"plotpointsize", # idem
79+
"plotpointtype", # idem
80+
"plotrbox", # idem
81+
"plotrecth", # idem
82+
"plotrecthraw", # idem
83+
"plotrline", # idem
84+
"plotrmove", # idem
85+
"plotrpoint", # idem
86+
"plotscale", # idem
87+
"plotstring", # idem
88+
"ploth", # idem
89+
"plothraw", # idem
90+
"psdraw", # idem
91+
"psplothraw", # idem
5192
}
5293

5394
class PariFunctionGenerator(object):
@@ -59,9 +100,9 @@ class PariFunctionGenerator(object):
59100
:class:`Pari`.
60101
"""
61102
def __init__(self):
62-
self.declared = read_decl()
63103
self.gen_filename = os.path.join('cypari2', 'auto_gen.pxi')
64104
self.instance_filename = os.path.join('cypari2', 'auto_instance.pxi')
105+
self.decl_filename = os.path.join('cypari2', 'auto_paridecl.pxd')
65106

66107
def can_handle_function(self, function, cname="", **kwds):
67108
"""
@@ -75,8 +116,6 @@ def can_handle_function(self, function, cname="", **kwds):
75116
True
76117
>>> G.can_handle_function("_bnfinit", "bnfinit0", **{"class":"basic"})
77118
False
78-
>>> G.can_handle_function("bnfinit", "BNFINIT0", **{"class":"basic"})
79-
False
80119
>>> G.can_handle_function("bnfinit", "bnfinit0", **{"class":"hard"})
81120
False
82121
"""
@@ -86,9 +125,6 @@ def can_handle_function(self, function, cname="", **kwds):
86125
if not function_re.match(function):
87126
# Not a legal function name, like "!_"
88127
return False
89-
if cname not in self.declared:
90-
# PARI function not in paridecl.pxd or declinl.pxi
91-
return False
92128
cls = kwds.get("class", "unknown")
93129
sec = kwds.get("section", "unknown")
94130
if cls not in ("basic", "highlevel"):
@@ -114,6 +150,7 @@ def handle_pari_function(self, function, cname="", prototype="", help="", obsole
114150
>>> G = PariFunctionGenerator()
115151
>>> G.gen_file = sys.stdout
116152
>>> G.instance_file = sys.stdout
153+
>>> G.decl_file = sys.stdout
117154
>>> G.handle_pari_function("bnfinit",
118155
... cname="bnfinit0", prototype="GD0,L,DGp",
119156
... help=r"bnfinit(P,{flag=0},{tech=[]}): compute...",
@@ -135,6 +172,7 @@ def bnfinit(P, long flag=0, tech=None, long precision=0):
135172
... cname="ellmodulareqn", prototype="LDnDn",
136173
... help=r"ellmodulareqn(N,{x},{y}): return...",
137174
... **{"class":"basic", "section":"elliptic_curves"})
175+
GEN ellmodulareqn(long N, long x, long y)
138176
def ellmodulareqn(self, long N, x=None, y=None):
139177
...
140178
cdef long _x = -1
@@ -171,6 +209,7 @@ def setrand(n):
171209
... help="bernvec(x): this routine is obsolete, use bernfrac repeatedly.",
172210
... obsolete="2007-03-30",
173211
... **{"class":"basic", "section":"transcendental"})
212+
GEN bernvec(long x)
174213
def bernvec(self, long x):
175214
r'''
176215
This routine is obsolete, kept for backward compatibility only.
@@ -182,6 +221,8 @@ def bernvec(self, long x):
182221
return new_gen(_ret)
183222
<BLANKLINE>
184223
"""
224+
if not cname:
225+
raise ValueError('function {} has no associated C name'.format(function))
185226
try:
186227
args, ret = parse_prototype(prototype, help)
187228
except NotImplementedError:
@@ -195,12 +236,18 @@ def bernvec(self, long x):
195236
self.write_method(function, cname, args, ret, args,
196237
self.gen_file, doc, obsolete)
197238

198-
# In any case, write a method of the Pari class.
239+
# In any case, write a declaration and a method of the Pari class.
240+
self.write_header(cname, args, ret, self.decl_file)
241+
199242
# Parse again with an extra "self" argument.
200243
args, ret = parse_prototype(prototype, help, [PariInstanceArgument()])
201244
self.write_method(function, cname, args, ret, args[1:],
202245
self.instance_file, doc, obsolete)
203246

247+
def write_header(self, cname, args, ret, file):
248+
args = ", ".join('{} {}'.format(a.ctype(), a.name) for a in args)
249+
print(' {ret} {function}({args})'.format(ret=ret.ctype(), function=cname, args=args), file=file)
250+
204251
def write_method(self, function, cname, args, ret, cargs, file, doc, obsolete):
205252
"""
206253
Write Cython code with a method to call one PARI function.
@@ -264,6 +311,8 @@ def __call__(self):
264311
self.gen_file.write(gen_banner)
265312
self.instance_file = open(self.instance_filename + '.tmp', 'w')
266313
self.instance_file.write(instance_banner)
314+
self.decl_file = open(self.decl_filename + '.tmp', 'w')
315+
self.decl_file.write(decl_banner)
267316

268317
for v in D:
269318
if not self.can_handle_function(**v):
@@ -276,7 +325,9 @@ def __call__(self):
276325

277326
self.gen_file.close()
278327
self.instance_file.close()
328+
self.decl_file.close()
279329

280330
# All done? Let's commit.
281331
os.rename(self.gen_filename + '.tmp', self.gen_filename)
282332
os.rename(self.instance_filename + '.tmp', self.instance_filename)
333+
os.rename(self.decl_filename + '.tmp', self.decl_filename)

autogen/parser.py

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
from .ret import pari_ret_types
2121
from .paths import pari_share
2222

23-
2423
paren_re = re.compile(r"[(](.*)[)]")
2524
argname_re = re.compile(r"[ {]*([A-Za-z_][A-Za-z0-9_]*)")
2625

@@ -71,31 +70,6 @@ def read_pari_desc():
7170

7271
return functions
7372

74-
75-
decl_re = re.compile(" ([A-Za-z][A-Za-z0-9_]*)[(]")
76-
77-
def read_decl():
78-
"""
79-
Read the files ``paridecl.pxd`` and ``declinl.pxi`` and return a set
80-
of all declared PARI library functions.
81-
82-
We do a simple regexp search, so there might be false positives.
83-
The main use is to skip undeclared functions.
84-
85-
EXAMPLES::
86-
87-
>>> from autogen.parser import read_decl
88-
>>> sorted(read_decl())
89-
['ABC_to_bnr', ..., 'zx_to_zv']
90-
"""
91-
s = set()
92-
with open(os.path.join("cypari2", "paridecl.pxd")) as f:
93-
s.update(decl_re.findall(f.read()))
94-
with open(os.path.join("cypari2", "declinl.pxi")) as f:
95-
s.update(decl_re.findall(f.read()))
96-
return s
97-
98-
9973
def parse_prototype(proto, help, initial_args=[]):
10074
"""
10175
Parse arguments and return type of a PARI function.

cypari2/gen.pyx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ from cpython.object cimport Py_EQ, Py_NE, Py_LE, Py_GE, Py_LT, Py_GT
7171
from cysignals.memory cimport sig_free, check_malloc
7272
from cysignals.signals cimport sig_check, sig_on, sig_off, sig_block, sig_unblock
7373

74-
from .paridecl cimport *
74+
from .types cimport *
7575
from .string_utils cimport to_string, to_bytes
7676
from .paripriv cimport *
7777
from .convert cimport (integer_to_gen, gen_to_integer,
@@ -81,6 +81,9 @@ from .pari_instance cimport (prec_bits_to_words, prec_words_to_bits,
8181
from .stack cimport new_gen, new_gen_noclear, clear_stack
8282
from .closure cimport objtoclosure
8383

84+
from .paridecl cimport *
85+
from .auto_paridecl cimport *
86+
8487
include 'auto_gen.pxi'
8588

8689
@cython.final

cypari2/pari_instance.pyx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ from cysignals.signals cimport sig_check, sig_on, sig_off
259259

260260
from .string_utils cimport to_string, to_bytes
261261
from .paridecl cimport *
262+
from .auto_paridecl cimport *
262263
from .paripriv cimport *
263264
from .gen cimport Gen, objtogen
264265
from .stack cimport new_gen, new_gen_noclear, clear_stack

cypari2/paridecl.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2987,6 +2987,7 @@ cdef extern from *: # PARI headers already included by types.pxd
29872987
GEN listput0(GEN list, GEN object, long index)
29882988
void listsort(GEN list, long flag)
29892989
GEN matsize(GEN x)
2990+
GEN mklist()
29902991
GEN mklistcopy(GEN x)
29912992
GEN normalize(GEN x)
29922993
GEN normalizepol(GEN x)

0 commit comments

Comments
 (0)