diff --git a/interfaces/sourcegen/sourcegen/_HeaderFileParser.py b/interfaces/sourcegen/sourcegen/_HeaderFileParser.py index c48ee39597..d9d3d6966d 100644 --- a/interfaces/sourcegen/sourcegen/_HeaderFileParser.py +++ b/interfaces/sourcegen/sourcegen/_HeaderFileParser.py @@ -10,14 +10,21 @@ from ._dataclasses import HeaderFile, Func, Recipe from ._helpers import read_config -_logger = logging.getLogger() -_clib_path = Path(__file__).parents[3] / "include" / "cantera" / "clib" -_clib_ignore = ["clib_defs.h", "ctmatlab.h"] +_LOGGER = logging.getLogger() -_data_path = Path(__file__).parent / "_data" +_CLIB_PATH = Path(__file__).parents[3] / "include" / "cantera" / "clib" +_CLIB_IGNORE = ["clib_defs.h", "ctmatlab.h"] + +_DATA_PATH = Path(__file__).parent / "_data" class HeaderFileParser: + """ + Parser for header files or corresponding YAML specifications. + + Provides for convenience methods to generate lists of `HeaderFile` objects, which + themselves are used for subsequent code scaffolding. + """ def __init__(self, path: Path, ignore_funcs: list[str] = None): self._path = path @@ -26,7 +33,7 @@ def __init__(self, path: Path, ignore_funcs: list[str] = None): @classmethod def headers_from_yaml(cls, ignore_files, ignore_funcs) -> list[HeaderFile]: """Parse header file YAML configuration.""" - files = [ff for ff in _data_path.glob("*.yaml") if ff.name not in ignore_files] + files = [ff for ff in _DATA_PATH.glob("*.yaml") if ff.name not in ignore_files] files.sort() return [cls(ff, ignore_funcs.get(ff.name, []))._parse_yaml() for ff in files] @@ -45,21 +52,24 @@ def _parse_yaml(self) -> HeaderFile: if not isinstance(uses, list): uses = [uses] recipes.append( - Recipe(prefix, - func['name'], - base, - parents, - derived, + Recipe(func['name'], func.get("implements", ""), uses, - func.get("what", ""))) - return HeaderFile(self._path, [], recipes, base, prefix) + func.get("what", ""), + func.get("brief", ""), + func.get("code", ""), + prefix, + base, + parents, + derived)) + + return HeaderFile(self._path, [], prefix, base, parents, derived, recipes) @classmethod def headers_from_h(cls, ignore_files, ignore_funcs) -> list[HeaderFile]: """Parse existing header file.""" - files = [ff for ff in _clib_path.glob("*.h") - if ff.name not in ignore_files + _clib_ignore] + files = [ff for ff in _CLIB_PATH.glob("*.h") + if ff.name not in ignore_files + _CLIB_IGNORE] files.sort() return [cls(ff, ignore_funcs.get(ff.name, []))._parse_h() for ff in files] @@ -75,9 +85,9 @@ def _parse_h(self) -> HeaderFile: parsed = map(Func.from_str, c_functions) - _logger.info(f" parsing {self._path.name!r}") + _LOGGER.info(f" parsing {self._path.name!r}") if self._ignore_funcs: - _logger.info(f" ignoring {self._ignore_funcs!r}") + _LOGGER.info(f" ignoring {self._ignore_funcs!r}") parsed = [f for f in parsed if f.name not in self._ignore_funcs] diff --git a/interfaces/sourcegen/sourcegen/_TagFileParser.py b/interfaces/sourcegen/sourcegen/_TagFileParser.py index 232952b08c..f6449fafb1 100644 --- a/interfaces/sourcegen/sourcegen/_TagFileParser.py +++ b/interfaces/sourcegen/sourcegen/_TagFileParser.py @@ -13,10 +13,10 @@ from ._helpers import with_unpack_iter -_logger = logging.getLogger(__name__) +_LOGGER = logging.getLogger(__name__) -_tag_path = Path(__file__).parents[3] / "build" / "doc" -_xml_path = _tag_path / "doxygen" / "xml" +_TAG_PATH = Path(__file__).parents[3] / "build" / "doc" +_XML_PATH = _TAG_PATH / "doxygen" / "xml" @dataclass(frozen=True) @@ -83,11 +83,11 @@ class TagFileParser: """Class handling contents of doxygen tag file.""" def __init__(self, bases: dict[str, str]) -> None: - tag_file = _tag_path / "Cantera.tag" + tag_file = _TAG_PATH / "Cantera.tag" if not tag_file.exists(): msg = (f"Tag file does not exist at expected location:\n {tag_file}\n" "Run 'scons doxygen' to generate.") - _logger.critical(msg) + _LOGGER.critical(msg) sys.exit(1) with tag_file.open() as fid: @@ -114,7 +114,7 @@ def xml_compounds(kind: str, names: list[str]) -> dict[str,str]: missing = '", "'.join(set(names) - set(found)) msg = f"Missing {kind!r} compound(s):\n {missing!r}\nusing regex " msg += f"{regex}. Continuing with remaining compounds: \n {found!r}" - _logger.error(msg) + _LOGGER.error(msg) # Parse content of namespace Cantera namespace = xml_compounds("namespace", ["Cantera"])["Cantera"] @@ -125,7 +125,7 @@ def xml_compounds(kind: str, names: list[str]) -> dict[str,str]: unknown = set(bases) - set(class_names) if "', '".join(unknown): unknown = "', '".join(unknown) - _logger.critical("Class(es) in configuration file are missing " + _LOGGER.critical("Class(es) in configuration file are missing " f"from tag file: {unknown!r}") exit(1) @@ -166,14 +166,14 @@ def detect(self, name, bases, permissive=True): return name if permissive: return None - _logger.critical(f"Unable to detect {name!r} in doxygen tags.") + _LOGGER.critical(f"Unable to detect {name!r} in doxygen tags.") exit(1) def tag_info(self, func_string: str) -> TagInfo: """Look up tag information based on (partial) function signature.""" cxx_func = func_string.split("(")[0].split(" ")[-1] if cxx_func not in self._known: - _logger.critical(f"Could not find {cxx_func!r} in doxygen tag file.") + _LOGGER.critical(f"Could not find {cxx_func!r} in doxygen tag file.") sys.exit(1) ix = 0 if len(self._known[cxx_func]) > 1: @@ -183,7 +183,7 @@ def tag_info(self, func_string: str) -> TagInfo: known = '\n - '.join( [""] + [ArgList.from_xml(xml_tag("arglist", xml)).short_str() for xml in self._known[cxx_func]]) - _logger.critical( + _LOGGER.critical( f"Need argument list to disambiguate {func_string!r}. " f"possible matches are:{known}") sys.exit(1) @@ -195,7 +195,7 @@ def tag_info(self, func_string: str) -> TagInfo: ix = i break if ix < 0: - _logger.critical( + _LOGGER.critical( f"Unable to match {func_string!r} to known functions.") sys.exit(1) @@ -227,10 +227,10 @@ def cxx_func(self, func_string: str) -> CFunc: def tag_lookup(tag_info: TagInfo) -> TagDetails: """Retrieve tag details from doxygen tree.""" - xml_file = _xml_path / tag_info.anchorfile + xml_file = _XML_PATH / tag_info.anchorfile if not xml_file.exists(): msg = (f"XML file does not exist at expected location: {xml_file}") - _logger.error(msg) + _LOGGER.error(msg) return TagDetails() with xml_file.open() as fid: @@ -241,10 +241,10 @@ def tag_lookup(tag_info: TagInfo) -> TagDetails: matches = re.findall(regex, xml_details) if not matches: - _logger.error(f"No XML matches found for {tag_info.qualified_name!r}") + _LOGGER.error(f"No XML matches found for {tag_info.qualified_name!r}") return TagDetails() if len(matches) != 1: - _logger.warning(f"Inconclusive XML matches found for {tag_info.qualified_name!r}") + _LOGGER.warning(f"Inconclusive XML matches found for {tag_info.qualified_name!r}") matches = matches[:1] def cleanup(entry: str) -> str: @@ -317,5 +317,5 @@ def xml_tags(tag: str, text: str, suffix: str="", permissive: bool=False) -> lis blanks = text.split("\n")[-1].split("<")[0] msg = f"Could not extract {tag!r} from:\n{blanks}{text}\n" msg += f"using regex: {regex}" - _logger.error(msg) + _LOGGER.error(msg) return [] diff --git a/interfaces/sourcegen/sourcegen/_data/ctkin_auto.yaml b/interfaces/sourcegen/sourcegen/_data/ctkin_auto.yaml index 18686c777d..702f4acd9b 100644 --- a/interfaces/sourcegen/sourcegen/_data/ctkin_auto.yaml +++ b/interfaces/sourcegen/sourcegen/_data/ctkin_auto.yaml @@ -13,5 +13,6 @@ cabinet: - name: nReactions - name: del what: noop + brief: Destructor; required by some APIs although object is managed by Solution. - name: cabinetSize - name: parentHandle diff --git a/interfaces/sourcegen/sourcegen/_data/ctsoln_auto.yaml b/interfaces/sourcegen/sourcegen/_data/ctsol_auto.yaml similarity index 89% rename from interfaces/sourcegen/sourcegen/_data/ctsoln_auto.yaml rename to interfaces/sourcegen/sourcegen/_data/ctsol_auto.yaml index 5223717bb3..1b525cfe3c 100644 --- a/interfaces/sourcegen/sourcegen/_data/ctsoln_auto.yaml +++ b/interfaces/sourcegen/sourcegen/_data/ctsol_auto.yaml @@ -5,7 +5,7 @@ # at https://cantera.org/license.txt for license and copyright information. cabinet: - prefix: soln3 + prefix: sol3 base: Solution parents: [] # List of parent classes derived: [Interface] # List of specializations @@ -28,4 +28,6 @@ cabinet: - name: nAdjacent - name: adjacent implements: Solution::adjacent(size_t) + uses: [thermo, kinetics, transport] + what: constructor # registers object in CLib storage - name: cabinetSize diff --git a/interfaces/sourcegen/sourcegen/_data/ctthermo_auto.yaml b/interfaces/sourcegen/sourcegen/_data/ctthermo_auto.yaml index df461ea21e..680f14ed98 100644 --- a/interfaces/sourcegen/sourcegen/_data/ctthermo_auto.yaml +++ b/interfaces/sourcegen/sourcegen/_data/ctthermo_auto.yaml @@ -33,5 +33,6 @@ cabinet: uses: nSpecies - name: del what: noop + brief: Destructor; required by some APIs although object is managed by Solution. - name: cabinetSize - name: parentHandle diff --git a/interfaces/sourcegen/sourcegen/_data/cttrans_auto.yaml b/interfaces/sourcegen/sourcegen/_data/cttrans_auto.yaml index 2c7c72dfd5..651787557f 100644 --- a/interfaces/sourcegen/sourcegen/_data/cttrans_auto.yaml +++ b/interfaces/sourcegen/sourcegen/_data/cttrans_auto.yaml @@ -14,5 +14,6 @@ cabinet: - name: thermalConductivity - name: del what: noop + brief: Destructor; required by some APIs although object is managed by Solution. - name: cabinetSize - name: parentHandle diff --git a/interfaces/sourcegen/sourcegen/_dataclasses.py b/interfaces/sourcegen/sourcegen/_dataclasses.py index 8cc16e767a..4f49c8258c 100644 --- a/interfaces/sourcegen/sourcegen/_dataclasses.py +++ b/interfaces/sourcegen/sourcegen/_dataclasses.py @@ -18,6 +18,7 @@ class Param: p_type: str #: Parameter type name: str = "" #: Parameter name; may be empty if used for return argument + description: str = "" #: Parameter description (optional annotation) direction: str = "" #: Direction of parameter (optional annotation) default: Any = None #: Default value (optional) @@ -155,8 +156,8 @@ class CFunc(Func): uses: list['CFunc'] = None #: List of auxiliary C++ methods (optional) @classmethod - def from_str(cls, func: str) -> 'CFunc': - """Generate CFunc from header block of a function.""" + def from_str(cls, func: str, brief="") -> 'CFunc': + """Generate annotated CFunc from header block of a function.""" lines = func.split("\n") func = super().from_str(lines[-1]) if len(lines) == 1: @@ -166,7 +167,7 @@ def from_str(cls, func: str) -> 'CFunc': args = [] for ix, line in enumerate(lines[:-1]): line = line.strip().lstrip("*").strip() - if ix == 1: + if ix == 1 and not brief: brief = line elif line.startswith("@param"): # assume that variables are documented in order @@ -199,26 +200,31 @@ class Recipe: Class holds contents of YAML header configuration. """ - prefix: str #: Prefix used for CLib access function - name: str #: Name of method (without prefix) - base: str #: C++ class implementing method - parents: list[str] #: List of C++ parent class(es) - derived: list[str] #: List of C++ specialization(s) - implements: str #: Signature of implemented method - uses: str | list[str] #: Auxiliary methods used by recipe - what: str #: Non-empty for special methods: "constructor", "destructor" + name: str #: name of method (without prefix) + implements: str #: signature of implemented C++ function/method + uses: str | list[str] #: auxiliary C++ methods used by recipe + what: str #: override auto-detection of recipe type + brief: str #: override brief description from doxygen documentation + code: str #: custom code to override autogenerated code (stub: to be implemented) + + prefix: str #: prefix used for CLib access function + base: str #: C++ class implementing method (if applicable) + parents: list[str] #: list of C++ parent classes (if applicable) + derived: list[str] #: list of C++ specializations (if applicable) @dataclass -# @with_unpack_iter class HeaderFile: - """Represents information about a parsed C header file""" + """Represents information about a parsed C header file.""" + + path: Path #: output folder + funcs: list[Func] #: list of functions to be scaffolded - path: Path - funcs: list[Func] - recipes: list[Recipe] = None - cabinet: str = "" - prefix: str = "" + prefix: str = "" #: prefix used for CLib function names + base: str = "" #: base class of C++ methods (if applicable) + parents: list[str] = None #: list of C++ parent class(es) + derived: list[str] = None #: list of C++ specialization(s) + recipes: list[Recipe] = None #: list of header recipes read from YAML def output_name(self, auto="3", suffix=""): """Return updated path.""" diff --git a/interfaces/sourcegen/sourcegen/_orchestrate.py b/interfaces/sourcegen/sourcegen/_orchestrate.py index d01f2e5b0f..622c597e38 100644 --- a/interfaces/sourcegen/sourcegen/_orchestrate.py +++ b/interfaces/sourcegen/sourcegen/_orchestrate.py @@ -13,7 +13,7 @@ from ._helpers import read_config -_logger = logging.getLogger() +_LOGGER = logging.getLogger() class CustomFormatter(logging.Formatter): """Minimalistic logging output""" @@ -27,12 +27,12 @@ def generate_source(lang: str, out_dir: str=None, verbose=False): """Main entry point of sourcegen.""" loghandler = logging.StreamHandler(sys.stdout) loghandler.setFormatter(CustomFormatter()) - _logger.handlers.clear() - _logger.addHandler(loghandler) - _logger.setLevel(logging.DEBUG if verbose else logging.INFO) + _LOGGER.handlers.clear() + _LOGGER.addHandler(loghandler) + _LOGGER.setLevel(logging.DEBUG if verbose else logging.INFO) if not out_dir: - _logger.critical("Aborting: sourcegen requires output folder information.") + _LOGGER.critical("Aborting: sourcegen requires output folder information.") exit(1) module = importlib.import_module(__package__ + "." + lang) @@ -59,10 +59,10 @@ def generate_source(lang: str, out_dir: str=None, verbose=False): clib_scaffolder.resolve_tags(files) # find and instantiate the language-specific SourceGenerator - _logger.info(f"Generating {lang!r} source files...") + _LOGGER.info(f"Generating {lang!r} source files...") _, scaffolder_type = inspect.getmembers(module, lambda m: inspect.isclass(m) and issubclass(m, SourceGenerator))[0] scaffolder: SourceGenerator = scaffolder_type(out_dir, config, templates) scaffolder.generate_source(files) - _logger.info("Done.") + _LOGGER.info("Done.") diff --git a/interfaces/sourcegen/sourcegen/clib/_CLibSourceGenerator.py b/interfaces/sourcegen/sourcegen/clib/_CLibSourceGenerator.py index e35eced264..177e0e03ca 100644 --- a/interfaces/sourcegen/sourcegen/clib/_CLibSourceGenerator.py +++ b/interfaces/sourcegen/sourcegen/clib/_CLibSourceGenerator.py @@ -16,7 +16,7 @@ from .._TagFileParser import TagFileParser -_logger = logging.getLogger() +_LOGGER = logging.getLogger() class CLibSourceGenerator(SourceGenerator): """The SourceGenerator for generating CLib.""" @@ -34,7 +34,7 @@ def __init__(self, out_dir: str, config: dict, templates: dict): def _javadoc_comment(block): """Build deblanked JavaDoc-style (C-style) comment block.""" block = ["/**"] + block.strip().split("\n") - block = "\n * ".join(block).strip() + "\n */" + block = "\n * ".join(block).strip() + "\n */" return "\n".join([line.rstrip() for line in block.split('\n')]) def _scaffold_annotation(self, c_func: CFunc, what: str) -> str: @@ -45,13 +45,13 @@ def _scaffold_annotation(self, c_func: CFunc, what: str) -> str: def param(item: Param): ret = par_template.render(par=item) - return f"{ret:<20} {item.description}" + return f"{ret:<19} {item.description}" implements = what if isinstance(c_func.implements, CFunc): implements += f": {c_func.implements.short_declaration()}" block = template.render( - briefdescription=c_func.brief, + brief=c_func.brief, params=[param(par) for par in c_func.arglist], returns=c_func.returns, implements=implements, relates=[f"{uu.name}()" for uu in c_func.uses]) @@ -71,7 +71,7 @@ def _handle_crosswalk(self, what: str, crosswalk: dict, derived: list[str]) -> s # successful crosswalk with cabinet object return cabinet - logging.critical(f"Failed crosswalk for handle type {what!r} using {classes}.") + _LOGGER.critical(f"Failed crosswalk for handle type {what!r} using {classes}.") sys.exit(1) def _ret_crosswalk( @@ -86,8 +86,8 @@ def _ret_crosswalk( "int", "", "Actual length of string or -1 for exception handling.") buffer = [ - Param("int", "lenBuf", "Length of reserved array.", "in"), - Param(ret_type, "charBuf", "Returned string value.", "out")] + Param("int", "bufLen", "Length of reserved array.", "in"), + Param(ret_type, "buf", "Returned string value.", "out")] return returns, buffer if ret_type == "void": returns = Param( @@ -102,7 +102,7 @@ def _ret_crosswalk( returns = Param( "int", "", f"Actual length of {what} or -1 for exception handling.") buffer = [ - Param("int", "lenBuf", "Length of reserved array.", "in"), + Param("int", "bufLen", "Length of reserved array.", "in"), Param(ret_type, "valueBuf", f"Returned {what} value.", "out")] return returns, buffer @@ -115,7 +115,7 @@ def _ret_crosswalk( f"Handle to stored {handle} object or -1 for exception handling.") return returns, [] - logging.critical(f"Failed crosswalk for return type {what!r}.") + _LOGGER.critical(f"Failed crosswalk for return type {what!r}.") sys.exit(1) def _prop_crosswalk(self, par_list: list[Param]) -> list[Param]: @@ -143,7 +143,7 @@ def _prop_crosswalk(self, par_list: list[Param]) -> list[Param]: description = f"Integer handle to {handle} object. {par.description}" params.append(Param("int", par.name, description, par.direction)) else: - logging.critical(f"Failed crosswalk for argument type {what!r}.") + _LOGGER.critical(f"Failed crosswalk for argument type {what!r}.") sys.exit(1) return params @@ -187,7 +187,7 @@ def shared_object(cxx_type): f"copyString(out, {c_args[c_ix+1].name}, {c_name});", "int(out.size())"] else: - _logger.critical(f"Scaffolding failed for {c_func.name!r}: reverse " + _LOGGER.critical(f"Scaffolding failed for {c_func.name!r}: reverse " f"crosswalk not implemented for {cxx_type!r}:\n" f"{c_func.declaration()}") exit(1) @@ -201,7 +201,7 @@ def shared_object(cxx_type): elif c_name.endswith("Len"): check_array = True else: - _logger.critical(f"Scaffolding failed for {c_func.name!r}: " + _LOGGER.critical(f"Scaffolding failed for {c_func.name!r}: " f"unexpected behavior for {c_name!r}.") exit(1) continue @@ -220,7 +220,7 @@ def shared_object(cxx_type): # Can be passed directly; example: double *const args.append(c_name) else: - _logger.critical(f"Scaffolding failed for {c_func.name!r}: reverse " + _LOGGER.critical(f"Scaffolding failed for {c_func.name!r}: reverse " f"crosswalk not implemented for {cxx_type!r}.") exit(1) check_array = False @@ -307,7 +307,7 @@ def _scaffold_body(self, c_func: CFunc, recipe: Recipe) -> tuple[str, set[str]]: self._templates[f"clib-reserved-{recipe.name}-cpp"]) else: - _logger.critical(f"{recipe.what!r} not implemented: {c_func.name!r}.") + _LOGGER.critical(f"{recipe.what!r} not implemented: {c_func.name!r}.") exit(1) return template.render(**args), bases @@ -343,11 +343,11 @@ def merge_params(implements, cxx_func: CFunc) -> tuple[list[Param], int]: recipe.what = "reserved" loader = Environment(loader=BaseLoader) if not quiet: - _logger.debug(f" generating {func_name!r} -> {recipe.what}") + _LOGGER.debug(f" generating {func_name!r} -> {recipe.what}") header = loader.from_string( self._templates[f"clib-reserved-{recipe.name}-h"] ).render(base=recipe.base, prefix=recipe.prefix) - return CFunc.from_str(header) + return CFunc.from_str(header, brief=recipe.brief) # Ensure that all functions/methods referenced in recipe are detected correctly bases = [recipe.base] + recipe.parents + recipe.derived @@ -363,7 +363,7 @@ def merge_params(implements, cxx_func: CFunc) -> tuple[list[Param], int]: if recipe.implements: if not quiet: - _logger.debug(f" generating {func_name!r} -> {recipe.implements}") + _LOGGER.debug(f" generating {func_name!r} -> {recipe.implements}") cxx_func = self._doxygen_tags.cxx_func(recipe.implements) # Convert C++ return type to format suitable for crosswalk: @@ -403,7 +403,7 @@ def merge_params(implements, cxx_func: CFunc) -> tuple[list[Param], int]: if recipe.what in ["destructor", "noop"]: # these function types don't have direct C++ equivalents if not quiet: - _logger.debug(f" generating {func_name!r} -> {recipe.what}") + _LOGGER.debug(f" generating {func_name!r} -> {recipe.what}") if recipe.what == "noop": args = [] brief= "No operation." @@ -416,76 +416,76 @@ def merge_params(implements, cxx_func: CFunc) -> tuple[list[Param], int]: "int", "", "Zero for success and -1 for exception handling.") buffer_params = [] + if recipe.brief: + brief = recipe.brief uses = [self._doxygen_tags.cxx_func(uu) for uu in recipe.uses] return CFunc(ret_param.p_type, func_name, ArgList(args), brief, cxx_func, ret_param.description, None, uses) - def _write_header(self, header: HeaderFile) -> None: + def _write_header(self, headers: HeaderFile) -> None: """Parse header specification and generate header file.""" loader = Environment(loader=BaseLoader, trim_blocks=True, lstrip_blocks=True) - filename = header.output_name(suffix=".h", auto="3") - _logger.info(f" scaffolding {filename.name!r}") + filename = headers.output_name(suffix=".h", auto="3") + _LOGGER.info(f" scaffolding {filename.name!r}") template = loader.from_string(self._templates["clib-definition"]) declarations = [] - for c_func, recipe in zip(header.funcs, header.recipes): - _logger.debug(f" scaffolding {c_func.name!r} header") + for c_func, recipe in zip(headers.funcs, headers.recipes): + _LOGGER.debug(f" scaffolding {c_func.name!r} header") declarations.append( template.render( declaration=c_func.declaration(), annotations=self._scaffold_annotation(c_func, recipe.what))) - headers = "\n\n".join(declarations) - no_constructor = "constructor:" not in headers + declarations = "\n\n".join(declarations) guard = f"__{filename.name.upper().replace('.', '_')}__" template = loader.from_string(self._templates["clib-header-file"]) output = template.render( - name=filename.stem, guard=guard, headers=headers, - base=header.cabinet, prefix=header.prefix, no_constructor=no_constructor) + name=filename.stem, guard=guard, headers=declarations, + base=headers.base, prefix=headers.prefix) out = (Path(self._out_dir) / "include" / "cantera" / "clib_experimental" / filename.name) - _logger.info(f" writing {filename.name!r}") + _LOGGER.info(f" writing {filename.name!r}") if not out.parent.exists(): out.parent.mkdir(parents=True, exist_ok=True) with open(out, "wt", encoding="utf-8") as stream: stream.write(output) stream.write("\n") - def _write_implementation(self, header: HeaderFile) -> None: + def _write_implementation(self, headers: HeaderFile) -> None: """Parse header specification and generate implementation file.""" loader = Environment(loader=BaseLoader, trim_blocks=True, lstrip_blocks=True) - filename = header.output_name(suffix=".cpp", auto="3") - _logger.info(f" scaffolding {filename.name!r}") + filename = headers.output_name(suffix=".cpp", auto="3") + _LOGGER.info(f" scaffolding {filename.name!r}") template = loader.from_string(self._templates["clib-implementation"]) implementations = [] other = set() - for c_func, recipe in zip(header.funcs, header.recipes): - _logger.debug(f" scaffolding {c_func.name!r} implementation") + for c_func, recipe in zip(headers.funcs, headers.recipes): + _LOGGER.debug(f" scaffolding {c_func.name!r} implementation") body, bases = self._scaffold_body(c_func, recipe) implementations.append( template.render(declaration=c_func.declaration(),body=body)) other |= bases implementations = "\n\n".join(implementations) str_utils = "copyString" in implementations - no_constructor = "constructor:" not in implementations includes = [] - for obj in [header.cabinet] + list(other): + for obj in [headers.base] + list(other): if obj: includes += self._config.includes[obj] template = loader.from_string(self._templates["clib-source-file"]) output = template.render( - name=filename.stem, implementations=implementations, prefix=header.prefix, - includes=includes, base=header.cabinet, other=other, - str_utils=str_utils, no_constructor=no_constructor) + name=filename.stem, implementations=implementations, prefix=headers.prefix, + includes=includes, base=headers.base, other=other, + str_utils=str_utils) out = Path(self._out_dir) / "src" / filename.name - _logger.info(f" writing {filename.name!r}") + _LOGGER.info(f" writing {filename.name!r}") if not out.parent.exists(): out.parent.mkdir(parents=True, exist_ok=True) with open(out, "wt", encoding="utf-8") as stream: @@ -502,18 +502,18 @@ def get_bases() -> list[str]: return list(bases) self._doxygen_tags = TagFileParser(get_bases()) - for header in headers_files: + for headers in headers_files: if not quiet: - _logger.info(f" resolving recipes in {header.path.name!r}:") + _LOGGER.info(f" resolving recipes in {headers.path.name!r}:") c_funcs = [] - for recipe in header.recipes: + for recipe in headers.recipes: c_funcs.append(self._resolve_recipe(recipe, quiet=quiet)) - header.funcs = c_funcs + headers.funcs = c_funcs def generate_source(self, headers_files: list[HeaderFile]): """Generate output.""" self.resolve_tags(headers_files, quiet=False) - for header in headers_files: - self._write_header(header) - self._write_implementation(header) + for headers in headers_files: + self._write_header(headers) + self._write_implementation(headers) diff --git a/interfaces/sourcegen/sourcegen/clib/config.yaml b/interfaces/sourcegen/sourcegen/clib/config.yaml index bc0153ae20..fd62bcdfdf 100644 --- a/interfaces/sourcegen/sourcegen/clib/config.yaml +++ b/interfaces/sourcegen/sourcegen/clib/config.yaml @@ -8,7 +8,7 @@ ignore_files: [] # Ignore these specific functions: ignore_funcs: - ctsoln_auto.yaml: [newInterface, adjacent] + ctsol_auto.yaml: [newInterface] # Cabinets with associated includes includes: diff --git a/interfaces/sourcegen/sourcegen/clib/templates.yaml b/interfaces/sourcegen/sourcegen/clib/templates.yaml index 3e351c0471..934d91b398 100644 --- a/interfaces/sourcegen/sourcegen/clib/templates.yaml +++ b/interfaces/sourcegen/sourcegen/clib/templates.yaml @@ -7,13 +7,13 @@ clib-param: |- @param{{ '[' + par.direction + ']' if par.direction }} {{ par.name }} clib-comment: |- - {{ briefdescription }} + {{ brief }} {% for par in params %} {{ par }} {% endfor %} {% if returns %} - {{ '@returns' + 13*' ' + returns }} + {{ '@returns' + 12*' ' + returns }} {% endif %} {% if params or returns %} @@ -31,71 +31,67 @@ clib-definition: |- clib-reserved-parentHandle-h: |- /** - * Return handle to parent of {{ base }} object. - * - * @param handle Handle to queried {{ base }} object. - * @returns Parent handle or -1 for exception handling. - */ + * Return handle to parent of {{ base }} object. + * @param handle Handle to queried {{ base }} object. + * @returns Parent handle or -1 for exception handling. + */ int {{ prefix }}_parentHandle(int handle); clib-reserved-cabinetSize-h: |- /** - * Return size of {{ base }} storage. - * - * @returns Size or -1 for exception handling. - */ + * Return size of {{ base }} storage. + * @returns Size or -1 for exception handling. + */ int {{ prefix }}_cabinetSize(); clib-reserved-getCanteraVersion-h: |- /** - * Get Cantera version. - * @param[in] lenBuf Length of reserved array. - * @param[out] charBuf String representation of %Cantera version. - * @returns Actual length of string or -1 for exception handling. - */ - int {{ prefix }}_getCanteraVersion(int lenBuf, char* charBuf); + * Get Cantera version. + * @param[in] bufLen Length of reserved array. + * @param[out] buf String representation of %Cantera version. + * @returns Actual length of string or -1 for exception handling. + */ + int {{ prefix }}_getCanteraVersion(int bufLen, char* buf); clib-reserved-getCanteraError-h: |- /** - * Get %Cantera error. - * @param[in] lenBuf Length of reserved array. - * @param[out] charBuf String containing %Cantera error. - * @returns Actual length of string or -1 for exception handling. - */ - int {{ prefix }}_getCanteraError(int lenBuf, char* charBuf); + * Get %Cantera error. + * @param[in] bufLen Length of reserved array. + * @param[out] buf String containing %Cantera error. + * @returns Actual length of string or -1 for exception handling. + */ + int {{ prefix }}_getCanteraError(int bufLen, char* buf); clib-reserved-resetStorage-h: |- /** - * Delete all objects and erase mapping. - * - * @returns Zero if successful or -1 for exception handling. - */ + * Delete all objects and erase mapping. + * @returns Zero if successful or -1 for exception handling. + */ int {{ prefix }}_resetStorage(); clib-reserved-clearStorage-h: |- /** - * Delete all objects with mapping preserved. - * - * @returns Zero if successful or -1 for exception handling. - */ + * Delete all objects with mapping preserved. + * @returns Zero if successful or -1 for exception handling. + */ int {{ prefix }}_clearStorage(); clib-header-file: |- /** - * {{ name.upper() }} - Experimental CLib %Cantera interface library. + * {{ name.upper() }} - Experimental CLib %Cantera interface library. * - * @file {{ name }}.cpp + * @file {{ name }}.cpp * - * This library of functions is designed to encapsulate %Cantera functionality - * and make it available for use in languages and applications other than C++. - * A set of library functions is provided that are declared "extern C". All - * %Cantera objects are stored and referenced by integers - no pointers are - * passed to or from the calling application. + * This library of functions is designed to encapsulate %Cantera functionality + * and make it available for use in languages and applications other than C++. + * A set of library functions is provided that are declared "extern C". All + * %Cantera objects are stored and referenced by integers - no pointers are + * passed to or from the calling application. * - * This file was generated by sourcegen. It will be re-generated by the - * %Cantera build process. Do not manually edit. + * This file was generated by sourcegen. It will be re-generated by the + * %Cantera build process. Do not manually edit. * - * @warning This module is an experimental part of the %Cantera API and + * @warning This module is an experimental part of the %Cantera API and * may be changed or removed without notice. */ @@ -283,7 +279,7 @@ clib-reserved-getCanteraVersion-cpp: |- // get Cantera version try { string out = CANTERA_VERSION; - copyString(out, charBuf, lenBuf); + copyString(out, buf, bufLen); return int(out.size()); } catch (...) { return handleAllExceptions(-1, ERR); @@ -292,7 +288,7 @@ clib-reserved-getCanteraVersion-cpp: |- clib-reserved-getCanteraError-cpp: |- try { string err = Application::Instance()->lastErrorMessage(); - copyString(err, charBuf, lenBuf); + copyString(err, buf, bufLen); return int(err.size()); } catch (...) { return handleAllExceptions(-1, ERR); @@ -322,14 +318,14 @@ clib-reserved-clearStorage-cpp: |- clib-source-file: |- /** - * {{ name.upper() }} - Experimental CLib %Cantera interface library. + * {{ name.upper() }} - Experimental CLib %Cantera interface library. * - * @file {{ name }}.cpp + * @file {{ name }}.cpp * - * This file was generated by sourcegen. It will be re-generated by the - * %Cantera build process. Do not manually edit. + * This file was generated by sourcegen. It will be re-generated by the + * %Cantera build process. Do not manually edit. * - * @warning This module is an experimental part of the %Cantera API and + * @warning This module is an experimental part of the %Cantera API and * may be changed or removed without notice. */ diff --git a/interfaces/sourcegen/sourcegen/yaml/_YamlSourceGenerator.py b/interfaces/sourcegen/sourcegen/yaml/_YamlSourceGenerator.py index 258f9b6f8a..74eeb43e14 100644 --- a/interfaces/sourcegen/sourcegen/yaml/_YamlSourceGenerator.py +++ b/interfaces/sourcegen/sourcegen/yaml/_YamlSourceGenerator.py @@ -18,7 +18,7 @@ from .._SourceGenerator import SourceGenerator -_logger = logging.getLogger() +_LOGGER = logging.getLogger() class YamlSourceGenerator(SourceGenerator): """The SourceGenerator for generating CLib.""" @@ -38,7 +38,7 @@ def _write_yaml(self, headers: HeaderFile): definition = loader.from_string(self._templates["yaml-definition"]) declarations = [] for c_func, recipe in zip(headers.funcs, headers.recipes): - _logger.debug(f" scaffolding {c_func.name!r} implementation") + _LOGGER.debug(f" scaffolding {c_func.name!r} implementation") implements = "" if isinstance(c_func.implements, CFunc): implements = c_func.implements.short_declaration() @@ -52,7 +52,7 @@ def _write_yaml(self, headers: HeaderFile): output = template.render(filename=filename.name, header_entries=declarations) out = Path(self._out_dir) / "yaml" / filename.name - _logger.info(f" writing {filename.name!r}") + _LOGGER.info(f" writing {filename.name!r}") if not out.parent.exists(): out.parent.mkdir(parents=True, exist_ok=True) with open(out, "wt", encoding="utf-8") as stream: @@ -62,5 +62,5 @@ def _write_yaml(self, headers: HeaderFile): def generate_source(self, headers_files: list[HeaderFile]): """Generate output.""" for headers in headers_files: - _logger.info(f" parsing functions in {headers.path.name!r}") + _LOGGER.info(f" parsing functions in {headers.path.name!r}") self._write_yaml(headers)