|
1 | | -""" |
2 | | -Fortran parameter code generator. |
3 | | -
|
4 | | -Generates namelist fragments and simple scalar declaration fragments |
5 | | -per target (pre/sim/post). Output consumed by generate.py. |
6 | | -
|
7 | | -Output format matches ffmt (the MFC Fortran formatter) so that |
8 | | -./mfc.sh format is idempotent on these generated files. |
9 | | -""" |
| 1 | +"""Fortran parameter code generator — namelist and scalar decl fragments per target.""" |
10 | 2 |
|
11 | 3 | import re |
12 | 4 | from typing import List |
|
17 | 9 | from ..registry import REGISTRY |
18 | 10 | from ..schema import ParamDef, ParamType |
19 | 11 |
|
20 | | -# ffmt collapses the two header lines into one and uses ASCII hyphen |
21 | | -_HEADER = "! AUTO-GENERATED - do not edit directly. Regenerate: ./mfc.sh generate\n!\n" |
| 12 | +_HEADER = "! AUTO-GENERATED - do not edit directly. Regenerate: cmake reconfigure\n!\n" |
22 | 13 |
|
23 | | -# ffmt formats Fortran with max 130-char lines and 4-space continuation indent |
24 | 14 | _MAX_LINE = 130 |
25 | 15 | _FIRST_PREFIX = "namelist /user_inputs/ " |
26 | 16 | _CONT_PREFIX = " & " |
27 | | -_CONT2_PREFIX = " & " # second-level continuation (inside Fypp #:if block) |
| 17 | +_CONT2_PREFIX = " & " # inside #:if block |
28 | 18 |
|
29 | | -# ffmt aligns '::' to a fixed column; widest type is character(LEN=path_len) = 23 chars |
30 | | -_DECL_COL = 24 # pad type string to this width before '::' |
| 19 | +_DECL_COL = 24 # '::' column, matches ffmt alignment |
31 | 20 |
|
32 | 21 |
|
33 | 22 | def get_namelist_var(param_name: str) -> str: |
@@ -55,93 +44,69 @@ def fortran_type_decl(param: ParamDef) -> str: |
55 | 44 |
|
56 | 45 |
|
57 | 46 | def _is_simple_scalar(name: str) -> bool: |
58 | | - """Return True if name has no '%' and no '(' - i.e. a plain simple variable.""" |
59 | 47 | return "%" not in name and "(" not in name |
60 | 48 |
|
61 | 49 |
|
62 | 50 | def _vars_for_target(target: str) -> List[str]: |
63 | | - """Return sorted list of namelist variable names for the given target.""" |
64 | 51 | return sorted(v for v, ts in NAMELIST_VARS.items() if target in ts) |
65 | 52 |
|
66 | 53 |
|
67 | 54 | def _pack_namelist(vars_list: List[str], first_prefix: str, cont_prefix: str, max_line: int) -> List[str]: |
68 | | - """ |
69 | | - Pack a list of variable names into Fortran namelist continuation lines. |
70 | | -
|
71 | | - Returns a list of lines WITHOUT trailing newlines. |
72 | | - All lines except the last end with ', &'. |
73 | | - """ |
| 55 | + """Pack variable names into Fortran continuation lines; all but last end with ', &'.""" |
74 | 56 | if not vars_list: |
75 | 57 | return [] |
76 | | - |
77 | 58 | lines: List[str] = [] |
78 | 59 | prefix = first_prefix |
79 | 60 | current_vars: List[str] = [] |
80 | 61 | current_len = len(prefix) |
81 | | - |
82 | 62 | for var in vars_list: |
83 | 63 | additional = len(var) + (2 if current_vars else 0) |
84 | 64 | if current_vars and current_len + additional + 3 > max_line: |
85 | | - # Flush with continuation marker |
86 | 65 | lines.append(prefix + ", ".join(current_vars) + ", &") |
87 | 66 | prefix = cont_prefix |
88 | 67 | current_vars = [var] |
89 | 68 | current_len = len(cont_prefix) + len(var) |
90 | 69 | else: |
91 | 70 | current_vars.append(var) |
92 | 71 | current_len += additional |
93 | | - |
94 | 72 | if current_vars: |
95 | 73 | lines.append(prefix + ", ".join(current_vars)) |
96 | | - |
97 | 74 | return lines |
98 | 75 |
|
99 | 76 |
|
100 | 77 | def _format_namelist(vars_list: List[str]) -> str: |
101 | | - """Format vars as a Fortran namelist statement block (no trailing newline).""" |
102 | | - lines = _pack_namelist(vars_list, _FIRST_PREFIX, _CONT_PREFIX, _MAX_LINE) |
103 | | - return "\n".join(lines) |
| 78 | + return "\n".join(_pack_namelist(vars_list, _FIRST_PREFIX, _CONT_PREFIX, _MAX_LINE)) |
104 | 79 |
|
105 | 80 |
|
106 | 81 | def generate_namelist_fpp(target: str) -> str: |
107 | | - """Generate the namelist /user_inputs/ statement for a target.""" |
| 82 | + """Return the namelist /user_inputs/ statement for a target as a string.""" |
108 | 83 | assert target in ("pre", "sim", "post") |
109 | 84 | all_vars = _vars_for_target(target) |
110 | 85 |
|
111 | 86 | if target != "sim": |
112 | 87 | return _HEADER + _format_namelist(all_vars) + "\n" |
113 | 88 |
|
114 | | - # For sim: split into normal vars and case-opt-excluded vars |
115 | 89 | normal = [v for v in all_vars if v not in CASE_OPT_EXCLUDE] |
116 | 90 | opt = sorted(v for v in CASE_OPT_EXCLUDE if v in NAMELIST_VARS and "sim" in NAMELIST_VARS[v]) |
117 | 91 |
|
118 | | - # Normal vars: last line gets ', &' since opt vars follow |
119 | 92 | nl_lines = _pack_namelist(normal, _FIRST_PREFIX, _CONT_PREFIX, _MAX_LINE) |
120 | 93 | nl_lines[-1] += ", &" |
121 | | - |
122 | | - # Opt vars: pack using cont_prefix for first line, cont2_prefix for subsequent |
123 | 94 | opt_lines = _pack_namelist(opt, _CONT_PREFIX, _CONT2_PREFIX, _MAX_LINE) |
124 | 95 |
|
125 | | - all_lines = [_HEADER.rstrip()] + nl_lines + ["#:if not MFC_CASE_OPTIMIZATION"] + opt_lines + ["#:endif"] |
126 | | - return "\n".join(all_lines) + "\n" |
| 96 | + parts = [_HEADER.rstrip()] + nl_lines + ["#:if not MFC_CASE_OPTIMIZATION"] + opt_lines + ["#:endif"] |
| 97 | + return "\n".join(parts) + "\n" |
127 | 98 |
|
128 | 99 |
|
129 | 100 | def generate_decls_fpp(target: str) -> str: |
130 | | - """Generate simple scalar Fortran variable declarations for a target. |
131 | | -
|
132 | | - Column-aligns '::' to match ffmt output (type padded to _DECL_COL chars). |
133 | | - """ |
| 101 | + """Return simple scalar Fortran declarations for a target as a string.""" |
134 | 102 | assert target in ("pre", "sim", "post") |
135 | 103 | all_params = REGISTRY.all_params |
136 | | - vars_for_target = _vars_for_target(target) |
137 | 104 | lines = [_HEADER.rstrip()] |
138 | | - for name in vars_for_target: |
| 105 | + for name in _vars_for_target(target): |
139 | 106 | if not _is_simple_scalar(name): |
140 | 107 | continue |
141 | 108 | param = all_params.get(name) |
142 | 109 | if param is None: |
143 | 110 | continue |
144 | | - type_str = fortran_type_decl(param) |
145 | | - padded = type_str.ljust(_DECL_COL) |
146 | | - lines.append(f"{padded}:: {name}") |
| 111 | + lines.append(f"{fortran_type_decl(param).ljust(_DECL_COL)}:: {name}") |
147 | 112 | return "\n".join(lines) + "\n" |
0 commit comments