@@ -55,7 +55,8 @@ Current handled coverage:
5555The C frontend is currently parse-only. It supports:
5656
5757- Raw-source directive metadata for includes, simple macros, conditionals, and
58- pragmas.
58+ pragmas. Raw mode records these facts but does not expand macros or select
59+ conditional branches.
5960- Compiler-assisted preprocessing through the shared CLI flags, with ` #line `
6061 and GCC/Clang linemarker remapping back to original source locations.
6162- Top-level variables, typedefs, function declarations/definitions, structs,
@@ -66,8 +67,9 @@ The C frontend is currently parse-only. It supports:
6667- Project include/index facts through ` parse_c_project(...) ` , with includes
6768 recorded non-recursively: only explicitly supplied files or files below an
6869 explicitly supplied directory are parsed.
69- - Raw mutually exclusive function alternatives preserved for later semantic
70- selection rather than collapsed into one signature.
70+ - Compiler mode is the wrapper-facing path for macro-dependent APIs: it parses
71+ one compiler-expanded translation unit and keeps mutually exclusive branches
72+ separate across build configurations.
7173
7274The supported C subset continues through semantic IR conversion, ` .pyi `
7375generation, and wrap-readiness.
@@ -76,11 +78,16 @@ generation, and wrap-readiness.
7678
7779Public API entrypoints include:
7880
79- - ` x2py.parse_fortran_file(source_or_path, filename=None, macro_defines=None, encoding="utf-8") -> FortranFile `
81+ - ` x2py.parse_fortran_file(source_or_path, filename=None, encoding="utf-8") -> FortranFile `
8082- ` x2py.parse_fortran_project(files, encoding="utf-8") -> FortranProject `
81- - ` x2py.parse_c_file(source_or_path, filename=None, macro_defines=None, include_dirs=None, preprocessing="raw", encoding="utf-8") -> CFile `
82- - ` x2py.parse_c_project(files, include_dirs=None, macro_defines=None, preprocessing="raw", encoding="utf-8") -> CProject `
83+ - ` x2py.parse_c_file(source_or_path, filename=None, include_dirs=None, preprocessing="raw", encoding="utf-8") -> CFile `
84+ - ` x2py.parse_c_project(files, include_dirs=None, preprocessing="raw", encoding="utf-8") -> CProject `
8385- ` x2py.fortran_file_to_semantic_modules(parsed_file, standalone_module_name=None) -> list[SemanticModule] `
86+ - ` x2py.fortran_project_to_semantic_modules(project) -> list[SemanticModule] `
87+ - ` x2py.c_file_to_semantic_modules(parsed_file) -> list[SemanticModule] `
88+ - ` x2py.c_project_to_semantic_modules(project) -> list[SemanticModule] `
89+ - ` x2py.emit_module_stubs(module_or_modules) -> dict[str, str] `
90+ - ` x2py.load_pyi_modules(path_or_paths, encoding="utf-8") -> list[SemanticModule] `
8491- ` x2py.assess_semantic_wrap_readiness(semantic_ir, source=None) -> dict `
8592- ` x2py.assess_pyi_wrap_readiness(path_or_paths, encoding="utf-8") -> dict `
8693- ` x2py.c_type_probe.probe_c_standard_types(config, runner=None) -> CStandardTypeProbeReport `
@@ -152,7 +159,15 @@ python -m x2py path/to/c_src --language c --parse
152159Fortran directories scan ` .f ` , ` .for ` , ` .ftn ` , ` .f90 ` , ` .f95 ` , ` .f03 ` ,
153160` .f08 ` ; C directories scan ` .c ` , ` .h ` , and ` .i ` files.
154161
155- ### Compiler preprocessing and target probes
162+ ### Compiler preprocessing, includes, and target probes
163+
164+ Wrapper-facing source parsing should use compiler preprocessing whenever the
165+ input contains C/CPP preprocessing. The selected compiler is authoritative for
166+ macro expansion, ` #if ` /` #ifdef ` branch selection, C ` #include ` , Fortran CPP
167+ ` #include ` , predefined macros, ` -D ` /` -U ` , include paths, target flags, and
168+ sysroot behavior. Internal parser mode remains available for plain source,
169+ already-preprocessed source, and focused parser tests; it does not evaluate CPP
170+ branches.
156171
157172The shared compiler mode is:
158173
@@ -168,9 +183,45 @@ python -m x2py path/to/source.f90 --language fortran --parse \
168183```
169184
170185For C, ` --language c --preprocess compiler ` runs the exact compiler
171- preprocessor and parses stdout. C also supports `--compile-commands
172- build/compile_commands.json`; the matching entry supplies the compiler and
173- project flags.
186+ preprocessor and parses stdout. C and Fortran can use `--compile-commands
187+ build/compile_commands.json` when a matching entry supplies the compiler and
188+ project flags. GCC-compatible C/Clang invocations use ` -E -x c ` ; GNU Fortran
189+ invocations use ` -E -cpp ` . Linemarkers are preserved so parser locations can be
190+ mapped back to original files. For unsupported compiler families, use
191+ ` --preprocessor-adapter command-template --preprocess-template '...' ` ; the
192+ minimum adapter contract is expanded source on stdout.
193+
194+ Fortran native ` include "file.inc" ` is resolved after compiler CPP output and
195+ before parsing. This is textual insertion into the current module, procedure,
196+ interface, or execution scope; it is not the same as ` use module_name ` . Native
197+ includes are resolved relative to the including file first, then configured
198+ ` -I ` directories, and duplicate textual inclusion is preserved. Missing
199+ includes and cycles are reported as preprocessing diagnostics.
200+
201+ Preprocessing JSON records the exact recipe: compiler or adapter, argv, working
202+ directory, include directories, defines, undefs, standard, extra compiler
203+ arguments, included files, source mappings, diagnostics, and optional macro
204+ metadata when the adapter output exposes it. System-header declarations are
205+ classified private by default. Reachable project includes are public by
206+ default; use ` --include-exposure roots-only ` , ` --public-include ` , and
207+ ` --private-include ` to control wrapper export. Private declarations remain
208+ available internally for type resolution. Public signatures that refer to
209+ private C handle types can use private opaque classes rather than exposing data
210+ members.
211+
212+ The C parser tolerates common compiler-expanded declaration syntax from system
213+ headers, including GNU attributes, ` __declspec(...) ` , alternate qualifier
214+ spellings, declaration-level ` asm(...) ` , calling-convention keywords,
215+ ` typeof(...) ` , ` _BitInt(...) ` , and selected extended scalar names. Harmless
216+ syntax is accepted without exposing private header declarations. Ignored
217+ extensions that can affect ABI, layout, symbol identity, or type identity
218+ produce ` C_UNMODELED_COMPILER_EXTENSION ` warnings.
219+
220+ Preprocessing failures print explicit categories such as
221+ ` PREPROCESSOR_NOT_FOUND ` , ` PREPROCESSOR_FAILED ` ,
222+ ` INVALID_COMPILER_ARGUMENTS ` , ` UNSUPPORTED_COMPILER_CAPABILITY ` ,
223+ ` PROVENANCE_UNAVAILABLE ` , ` INCLUDE_NOT_FOUND ` , and ` INCLUDE_CYCLE ` without a
224+ Python traceback. Pass ` --debug ` to re-raise and show the traceback.
174225
175226Target-dependent type facts are not hard-coded. They are probed with the same
176227compiler path and target-relevant flags because results may change with ABI,
@@ -757,3 +808,46 @@ source/target mapping. A non-renamed `use iso_c_binding, only: c_int` maps
757808` source="delete_input_list" ` and ` target="delete_input" ` . The semantic layer
758809uses that information to emit Python stub imports such as
759810` from list_input import delete_input_list as delete_input ` .
811+
812+ Fortran ` use ` dependencies are not parsed or wrapped recursively. If a
813+ procedure refers to an imported derived type, semantic IR records its defining
814+ module and represents the reference as an opaque handle unless the defining
815+ module is explicitly part of the wrapping target. Explicitly supplied modules
816+ share one wrapped-type registry, so the imported reference resolves to the
817+ single class emitted by its owner module without being re-exported by the
818+ importing module. Reachable include exposure is already handled separately by
819+ the preprocessing include policy; a future dependency-expansion option would
820+ apply specifically to recursive Fortran ` use ` traversal.
821+
822+ When an imported derived type remains external, ` .pyi ` generation emits an
823+ owner-module dependency stub. For example, wrapping only ` physics.f90 ` may
824+ produce:
825+
826+ ``` python
827+ # physics.pyi
828+ from types_mod import particle
829+
830+ def move (p : Ptr(particle)) -> None : ...
831+ ```
832+
833+ ``` python
834+ # types_mod.pyi
835+ class particle (Opaque ):
836+ pass
837+ ```
838+
839+ ` python -m x2py physics.f90 --pyi --out ` writes both files beside the source.
840+ ` load_pyi_modules(...) ` loads a file set or directory, preserves opaque classes,
841+ and reconciles imported references against edited owner stubs. Replacing the
842+ opaque placeholder with a concrete edited class changes the semantic reference
843+ from ` representation="opaque" ` to ` representation="wrapped" ` . Existing
844+ ` Annotated[...] ` constraints also round-trip through this editable interface;
845+ richer coercion syntax can be added to the same ` .pyi ` format later.
846+
847+ The same opaque-handle file-set model applies to C. A local forward declaration
848+ such as ` struct context; ` emits ` class context(Opaque): pass ` . When a public C
849+ header uses a struct from another explicitly supplied header, its generated
850+ stub imports the class from that header's stub. A private included struct used
851+ through a public pointer boundary emits an opaque owner-module dependency stub.
852+ An unresolved C typedef is left unresolved rather than guessed to be opaque,
853+ because its ABI may not be pointer-shaped.
0 commit comments