|
| 1 | +from os import PathLike |
| 2 | +from pathlib import Path |
| 3 | + |
| 4 | +import jinja2 |
| 5 | +from modflow_devtools.dfn import Dfn |
| 6 | + |
| 7 | +from flopy4.mf6.codec.reader.grammar import filters |
| 8 | + |
| 9 | + |
| 10 | +def _get_template_env(): |
| 11 | + loader = jinja2.PackageLoader("flopy4", "mf6/codec/reader/grammar/templates/") |
| 12 | + env = jinja2.Environment( |
| 13 | + loader=loader, |
| 14 | + trim_blocks=True, |
| 15 | + lstrip_blocks=True, |
| 16 | + keep_trailing_newline=True, |
| 17 | + ) |
| 18 | + env.filters["field_type"] = filters.field_type |
| 19 | + env.filters["record_child_type"] = filters.record_child_type |
| 20 | + return env |
| 21 | + |
| 22 | + |
| 23 | +def _get_template_data(blocks) -> tuple[list[dict], dict[str, object]]: |
| 24 | + all_blocks = [] |
| 25 | + all_fields = {} |
| 26 | + |
| 27 | + for block_name, block_fields in blocks.items(): |
| 28 | + period_groups = filters.group_period_fields(block_fields) |
| 29 | + has_index = block_name == "period" |
| 30 | + |
| 31 | + recarrays = [] |
| 32 | + grouped_field_names = set() |
| 33 | + if period_groups: |
| 34 | + for field_names in period_groups.values(): |
| 35 | + recarray_name = filters.get_recarray_name(block_name) |
| 36 | + recarrays.append({"name": recarray_name, "fields": field_names}) |
| 37 | + grouped_field_names.update(field_names) |
| 38 | + |
| 39 | + all_field_names = list(block_fields.keys()) |
| 40 | + standalone_fields = [f for f in all_field_names if f not in grouped_field_names] |
| 41 | + |
| 42 | + all_fields.update(block_fields) |
| 43 | + all_blocks.append( |
| 44 | + { |
| 45 | + "name": block_name, |
| 46 | + "has_index": has_index, |
| 47 | + "standalone_fields": standalone_fields, |
| 48 | + "recarrays": recarrays, |
| 49 | + } |
| 50 | + ) |
| 51 | + |
| 52 | + return all_blocks, all_fields |
| 53 | + |
| 54 | + |
| 55 | +def make_grammar(dfn: Dfn, outdir: PathLike): |
| 56 | + """Generate a Lark grammar file for a single component.""" |
| 57 | + outdir = Path(outdir).expanduser().resolve().absolute() |
| 58 | + env = _get_template_env() |
| 59 | + template = env.get_template("component.lark.jinja") |
| 60 | + target_path = outdir / f"{dfn.name}.lark" |
| 61 | + blocks, fields = _get_template_data(dfn.blocks) |
| 62 | + with open(target_path, "w") as f: |
| 63 | + name = dfn.name |
| 64 | + f.write(template.render(name=name, blocks=blocks, fields=fields)) |
| 65 | + |
| 66 | + |
| 67 | +def make_all_grammars(dfns: dict[str, Dfn], outdir: PathLike): |
| 68 | + """Generate grammars for all components.""" |
| 69 | + outdir = Path(outdir).expanduser().resolve().absolute() |
| 70 | + outdir.mkdir(parents=True, exist_ok=True) |
| 71 | + for dfn in dfns.values(): |
| 72 | + make_grammar(dfn, outdir) |
0 commit comments