Skip to main content

zerodds_lang_rules/rule/
fsharp.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3//! The F# rule catalogue. Spec §2.
4//!
5//! The same constructs `rule/zig.rs` and `rule/go.rs` cover, mapped onto
6//! F#'s own tree. Reading this beside `rule/zig.rs` is the point, because
7//! the two agree on every rule's *shape* — one struct becomes one
8//! aggregate, one member becomes one field, one union case becomes one
9//! field of the discriminated aggregate — and differ only in which ghost
10//! type each rule names; `crates/lang-rules/src/adapter/fsharp.rs`
11//! carries why the aggregate itself is a class and not Zig's `struct` or
12//! F#'s own discriminated union.
13//!
14//! - A module becomes a **name prefix**, as in Zig, C and Go. F#'s
15//!   `module rec` does not nest the way IDL's `module` can, so
16//!   `::common::util::Location` is `common_util_Location`.
17//! - An enumeration becomes **one declaration** holding its cases, as in
18//!   Zig's `enum(i32) { … }` — F#'s CLI enum syntax holds its cases the
19//!   same way, so `enum-to-enum` and `enumerator-to-variant` read exactly
20//!   as Zig's do.
21//! - A **bitmask still needs file-scope constants**, because its F# form
22//!   is a type abbreviation and not an enumeration — `bit-to-const` is a
23//!   rule of its own, as it is in Zig.
24//! - An **interface becomes a class of function-valued fields**, F#'s
25//!   answer to Zig's "struct of function pointers": a first-class
26//!   function value is a real F# field the way a function pointer is a
27//!   real Zig one.
28//!
29//! A union becomes a **class with a discriminator and one field per
30//! branch**, as in Zig's struct-not-tagged-union and Go's struct, and not
31//! F#'s own discriminated union — the load-bearing decision, and
32//! `crates/lang-rules/src/adapter/fsharp.rs`'s documentation carries the
33//! reason.
34
35use crate::rule::shape::{one_to_one, part_of};
36use seesaw_tgg::rules::format::RuleFile;
37
38/// The catalogue's own name, which a serialised rule file carries.
39const CATALOGUE_NAME: &str = "fsharp";
40
41/// The name of the rule that maps a struct to an F# class type.
42pub const STRUCT_TO_CLASS: &str = "struct-to-class";
43
44/// The name of the rule that maps a member to a class field.
45pub const MEMBER_TO_FIELD: &str = "member-to-field";
46
47/// The name of the rule that maps an enumeration to an F# enum type.
48pub const ENUM_TO_ENUM: &str = "enum-to-enum";
49
50/// The name of the rule that maps an enumerator to a case of that type.
51pub const ENUMERATOR_TO_VARIANT: &str = "enumerator-to-variant";
52
53/// The name of the rule that maps a typedef to an F# type abbreviation.
54pub const ALIAS_TO_ABBREVIATION: &str = "alias-to-abbreviation";
55
56/// The name of the rule that maps a union to a discriminated class.
57pub const UNION_TO_CLASS: &str = "union-to-class";
58
59/// The name of the rule that maps a union case to a field.
60pub const CASE_TO_FIELD: &str = "case-to-field";
61
62/// The name of the rule that maps a bitmask to an unsigned type
63/// abbreviation and its bits.
64pub const BITMASK_TO_INT: &str = "bitmask-to-int";
65
66/// The name of the rule that maps a bit to a file-scope constant.
67pub const BIT_TO_CONST: &str = "bit-to-const";
68
69/// The name of the rule that maps a bitset to a class of fields.
70pub const BITSET_TO_CLASS: &str = "bitset-to-class";
71
72/// The name of the rule that maps a valuetype to a class.
73pub const VALUETYPE_TO_CLASS: &str = "valuetype-to-class";
74
75/// The name of the rule that maps a module to a name prefix.
76pub const MODULE_TO_PREFIX: &str = "module-to-prefix";
77
78/// The name of the rule that maps a constant to an F# `let` binding.
79pub const CONST_TO_CONST: &str = "const-to-const";
80
81/// The name of the rule that maps an exception to a class.
82pub const EXCEPTION_TO_CLASS: &str = "exception-to-class";
83
84/// The name of the rule that maps a native declaration to an opaque
85/// mapping.
86pub const NATIVE_TO_OPAQUE: &str = "native-to-opaque";
87
88/// The name of the rule that maps an interface to a class of
89/// function-valued fields.
90pub const INTERFACE_TO_CLASS: &str = "interface-to-class";
91
92/// Every F# rule.
93#[must_use]
94pub fn catalogue() -> RuleFile {
95    RuleFile {
96        format: 3,
97        name: CATALOGUE_NAME.to_string(),
98        rules: vec![
99            one_to_one(STRUCT_TO_CLASS, "Structure", "FsClass", "FsClassCorr"),
100            part_of(
101                MEMBER_TO_FIELD,
102                ("Member", "Structure", "FsClassCorr"),
103                ("FsField", "FsClass", "FsFieldCorr"),
104            ),
105            one_to_one(ENUM_TO_ENUM, "Enumeration", "FsEnum", "FsEnumCorr"),
106            part_of(
107                ENUMERATOR_TO_VARIANT,
108                ("Enumerator", "Enumeration", "FsEnumCorr"),
109                ("FsVariant", "FsEnum", "FsVariantCorr"),
110            ),
111            one_to_one(ALIAS_TO_ABBREVIATION, "Alias", "FsAlias", "FsAliasCorr"),
112            one_to_one(UNION_TO_CLASS, "Union", "FsUnion", "FsUnionCorr"),
113            part_of(
114                CASE_TO_FIELD,
115                ("Case", "Union", "FsUnionCorr"),
116                ("FsCase", "FsUnion", "FsCaseCorr"),
117            ),
118            one_to_one(BITMASK_TO_INT, "Bitmask", "FsBitmask", "FsBitmaskCorr"),
119            part_of(
120                BIT_TO_CONST,
121                ("BitValue", "Bitmask", "FsBitmaskCorr"),
122                ("FsBitConst", "FsBitmask", "FsBitCorr"),
123            ),
124            one_to_one(BITSET_TO_CLASS, "Bitset", "FsBitset", "FsBitsetCorr"),
125            one_to_one(VALUETYPE_TO_CLASS, "Valuetype", "FsValue", "FsValueCorr"),
126            one_to_one(MODULE_TO_PREFIX, "Module", "FsModule", "FsModuleCorr"),
127            one_to_one(CONST_TO_CONST, "Const", "FsConst", "FsConstCorr"),
128            one_to_one(EXCEPTION_TO_CLASS, "Exception", "FsError", "FsErrorCorr"),
129            one_to_one(NATIVE_TO_OPAQUE, "Native", "FsNative", "FsNativeCorr"),
130            one_to_one(
131                INTERFACE_TO_CLASS,
132                "Interface",
133                "FsInterface",
134                "FsInterfaceCorr",
135            ),
136        ],
137    }
138}