From b118bda9e78c4637967342253c383b30d678c67e Mon Sep 17 00:00:00 2001 From: rashad Date: Fri, 19 Dec 2025 14:13:29 +0200 Subject: [PATCH] removing unesserary imports and implementing add_macro and add_type --- src/sage_setup/autogen/flint/reader.py | 141 +++++++++++++++---------- 1 file changed, 84 insertions(+), 57 deletions(-) diff --git a/src/sage_setup/autogen/flint/reader.py b/src/sage_setup/autogen/flint/reader.py index 3673b330d96..58e7cb4c28b 100644 --- a/src/sage_setup/autogen/flint/reader.py +++ b/src/sage_setup/autogen/flint/reader.py @@ -2,7 +2,7 @@ Extraction of function, macros, types from flint documentation. """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2023 Vincent Delecroix <20100.delecroix@gmail.com> # # This program is free software: you can redistribute it and/or modify @@ -10,16 +10,14 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** - -import os -from .env import FLINT_INCLUDE_DIR, FLINT_DOC_DIR +# ***************************************************************************** class Extractor: r""" Tool to extract function declarations from a flint .rst file """ + NONE = 0 DOC = 1 FUNCTION_DECLARATION = 2 @@ -28,16 +26,20 @@ class Extractor: def __init__(self, filename): self.filename = filename - if not filename.endswith('.rst'): + if not filename.endswith(".rst"): raise ValueError # Attributes that are modified throughout the document parsing - self.state = self.NONE # position in the documentation - self.section = None # current section - self.content = {} # section -> list of pairs (function signatures, func documentation) - self.functions = [] # current list of pairs (function signatures, func documentation) - self.signatures = [] # current list of function/macro/type signatures - self.doc = [] # current function documentation + self.state = self.NONE # position in the documentation + self.section = None # current section + self.content = ( + {} + ) # section -> list of pairs (function signatures, func documentation) + self.functions = ( + [] + ) # current list of pairs (function signatures, func documentation) + self.signatures = [] # current list of function/macro/type signatures + self.doc = [] # current function documentation with open(filename) as f: text = f.read() @@ -68,7 +70,7 @@ def clean_doc(self): for i, line in enumerate(self.doc): # To make sage linter happier - line = line.replace('\\choose ', 'choose ') + line = line.replace("\\choose ", "choose ") self.doc[i] = line @staticmethod @@ -78,51 +80,64 @@ def has_boolean_return_type(func_signature): If so, it will be declared in Cython as `bint` rather than `int`. """ - if func_signature.count('(') != 1 or func_signature.count(')') != 1: + if func_signature.count("(") != 1 or func_signature.count(")") != 1: return False - j = func_signature.index('(') + j = func_signature.index("(") func_name = func_signature[:j].strip().split() if len(func_name) != 2: return False return_type = func_name[0] - if return_type != 'int': + if return_type != "int": return False func_name = func_name[1] - return func_name.startswith('is_') or \ - '_is_' in func_name or \ - func_name.endswith('_eq') or \ - func_name.endswith('_ne') or \ - func_name.endswith('_lt') or \ - func_name.endswith('_le') or \ - func_name.endswith('_gt') or \ - func_name.endswith('_ge') or \ - '_contains_' in func_name or \ - func_name.endswith('_contains') or \ - '_equal_' in func_name or \ - func_name.endswith('_equal') or \ - func_name.endswith('_overlaps') + return ( + func_name.startswith("is_") + or "_is_" in func_name + or func_name.endswith("_eq") + or func_name.endswith("_ne") + or func_name.endswith("_lt") + or func_name.endswith("_le") + or func_name.endswith("_gt") + or func_name.endswith("_ge") + or "_contains_" in func_name + or func_name.endswith("_contains") + or "_equal_" in func_name + or func_name.endswith("_equal") + or func_name.endswith("_overlaps") + ) def clean_signatures(self): - if (self.state & self.FUNCTION_DECLARATION) or (self.state & self.MACRO_DECLARATION): + if (self.state & self.FUNCTION_DECLARATION) or ( + self.state & self.MACRO_DECLARATION + ): for i, func_signature in enumerate(self.signatures): - replacement = [('(void)', '()'), (' enum ', ' ')] + replacement = [("(void)", "()"), (" enum ", " ")] for bad_type, good_type in replacement: func_signature = func_signature.replace(bad_type, good_type) - bad_arg_names = [('in', 'input'), ('lambda', 'lmbda'), ('iter', 'it'), ('is', 'iis')] - replacements = [(pattern.format(bad), pattern.format(good)) for pattern in [' {},', ' {})', '*{},', '*{})'] for bad, good in bad_arg_names] + bad_arg_names = [ + ("in", "input"), + ("lambda", "lmbda"), + ("iter", "it"), + ("is", "iis"), + ] + replacements = [ + (pattern.format(bad), pattern.format(good)) + for pattern in [" {},", " {})", "*{},", "*{})"] + for bad, good in bad_arg_names + ] for bad_form, good_form in replacements: func_signature = func_signature.replace(bad_form, good_form) if self.has_boolean_return_type(func_signature): func_signature = func_signature.strip() - if not func_signature.startswith('int '): + if not func_signature.startswith("int "): raise RuntimeError - func_signature = 'b' + func_signature + func_signature = "b" + func_signature self.signatures[i] = func_signature @@ -144,10 +159,10 @@ def add_function(self): # Drop va_list argument signatures = [] for func_signature in self.signatures: - if '(' not in func_signature or ')' not in func_signature: + if "(" not in func_signature or ")" not in func_signature: raise RuntimeError(func_signature) - elif 'va_list ' in func_signature: - print('Warning: va_list unsupported {}'.format(func_signature)) + elif "va_list " in func_signature: + print("Warning: va_list unsupported {}".format(func_signature)) else: signatures.append(func_signature) self.signatures = signatures @@ -156,11 +171,14 @@ def add_function(self): self.functions.append((tuple(self.signatures), tuple(self.doc))) def add_macro(self): - # TODO: we might want to support auto-generation of macros + self.clean_doc() + self.clean_signatures() + self.functions.append((tuple(self.signatures), tuple(self.doc))) return def add_type(self): - # TODO: we might want to support auto-generation of types + self.clean_doc() + self.functions.append((tuple(self.signatures), tuple(self.doc))) return def process_line(self): @@ -170,30 +188,39 @@ def process_line(self): if self.i >= len(self.lines): return 0 - if bool(self.state & self.FUNCTION_DECLARATION) + bool(self.state & self.MACRO_DECLARATION) + bool(self.state & self.TYPE_DECLARATION) > 1: - raise RuntimeError('self.state = {} and i = {}'.format(self.state, self.i)) + if ( + bool(self.state & self.FUNCTION_DECLARATION) + + bool(self.state & self.MACRO_DECLARATION) + + bool(self.state & self.TYPE_DECLARATION) + > 1 + ): + raise RuntimeError("self.state = {} and i = {}".format(self.state, self.i)) line = self.lines[self.i] - if line.startswith('.. function::'): + if line.startswith(".. function::"): self.add_declaration() - line_rest = line.removeprefix('.. function::') - if not line_rest.startswith(' '): - print('Warning: no space {}'.format(line)) + line_rest = line.removeprefix(".. function::") + if not line_rest.startswith(" "): + print("Warning: no space {}".format(line)) self.state = self.FUNCTION_DECLARATION self.i += 1 signature = line_rest.strip() - while signature.endswith('\\'): - signature = signature.removesuffix('\\').strip() + ' ' + self.lines[self.i].strip() + while signature.endswith("\\"): + signature = ( + signature.removesuffix("\\").strip() + + " " + + self.lines[self.i].strip() + ) self.i += 1 self.signatures.append(signature) - elif line.startswith('.. macro::'): + elif line.startswith(".. macro::"): self.add_declaration() - if line[10] != ' ': - print('Warning no space{}'.format(line)) + if line[10] != " ": + print("Warning no space{}".format(line)) self.signatures.append(line[10:].strip()) self.state = self.MACRO_DECLARATION self.i += 1 - elif line.startswith('.. type::'): + elif line.startswith(".. type::"): # type # NOTE: we do nothing as the documentation duplicates type declaration # and lacks the actual list of attributes @@ -201,7 +228,7 @@ def process_line(self): self.state = self.TYPE_DECLARATION self.i += 1 elif self.state == self.FUNCTION_DECLARATION: - if len(line) > 14 and line.startswith(' ' * 14): + if len(line) > 14 and line.startswith(" " * 14): # function with similar declaration line = line[14:].strip() if line: @@ -214,7 +241,7 @@ def process_line(self): else: raise ValueError(line) elif self.state == self.MACRO_DECLARATION: - if len(line) > 10 and line.startswith(' ' * 10): + if len(line) > 10 and line.startswith(" " * 10): # macro with similar declaration line = line[10:].strip() if line: @@ -226,18 +253,18 @@ def process_line(self): self.i += 1 else: raise ValueError(line) - elif (self.state & self.DOC) and line.startswith(' '): + elif (self.state & self.DOC) and line.startswith(" "): # function doc line = line.strip() if line: self.doc.append(line) self.i += 1 - elif self.i + 1 < len(self.lines) and self.lines[self.i + 1].startswith('----'): + elif self.i + 1 < len(self.lines) and self.lines[self.i + 1].startswith("----"): # new section self.add_declaration() if self.functions: self.update_section() - section = line + # section = line self.i += 2 elif not line: self.i += 1