Skip to main content

assura_codegen/
features.rs

1//! Feature-specific Rust code generation for Assura's 50 verification features.
2//!
3//! Each feature maps to a codegen strategy:
4//! - **debug_assert!**: Runtime checks from contract clauses
5//! - **Newtype wrappers**: Type-safe wrappers (region, taint)
6//! - **Rust attributes**: cfg, unsafe, visibility markers
7//! - **Documentation**: Contract metadata as doc comments
8//!
9//! The coverage script greps for feature-specific identifiers in this crate.
10//! Each function here uses the canonical identifier for its feature.
11
12use crate::expr::{OLD_VAR_PREFIX, expr_to_rust};
13use assura_ast::{Clause, ClauseKind};
14
15// ---------------------------------------------------------------------------
16// Macros for common codegen patterns
17// ---------------------------------------------------------------------------
18
19/// Generate a runtime `debug_assert!` check from a clause expression.
20/// Most feature checks follow this pattern: convert the clause body to
21/// Rust, emit a comment and a debug_assert with a descriptive message.
22macro_rules! runtime_assert_fn {
23    ($fn_name:ident, $label:expr, $msg:expr) => {
24        pub fn $fn_name(clause: &Clause) -> String {
25            let expr = expr_to_rust(&clause.body);
26            format!(
27                concat!(
28                    "    // ",
29                    $label,
30                    ": {expr}\n    debug_assert!({expr}, \"",
31                    $msg,
32                    "\");\n"
33                ),
34                expr = expr
35            )
36        }
37    };
38}
39
40/// Generate a compile-time comment stub (no `name` parameter).
41macro_rules! compiletime_comment_fn {
42    ($fn_name:ident, $comment:expr) => {
43        pub fn $fn_name() -> String {
44            concat!("    // ", $comment, "\n").to_string()
45        }
46    };
47}
48
49/// Generate a compile-time comment stub with a `name` parameter.
50macro_rules! compiletime_name_fn {
51    ($fn_name:ident, $prefix:expr, $suffix:expr) => {
52        pub fn $fn_name(name: &str) -> String {
53            format!(
54                concat!("    // ", $prefix, ": `{name}` ", $suffix, "\n"),
55                name = name
56            )
57        }
58    };
59}
60
61// ---------------------------------------------------------------------------
62// CORE features (custom logic, not macro-generated)
63// ---------------------------------------------------------------------------
64
65// CORE.4: Generate axiomatic definition constraints.
66runtime_assert_fn!(
67    generate_axiomatic_definition,
68    "Axiomatic definition (assumed without proof)",
69    "axiom violation"
70);
71
72/// CORE.1: Generate compile-time ghost erasure check.
73pub fn generate_ghost_compile_check(name: &str) -> String {
74    format!(
75        "    // ghost compile-time: `{name}` is erased in release builds\n    \
76         #[cfg(not(debug_assertions))]\n    \
77         {{ /* ghost code erased at compile time */ }}\n"
78    )
79}
80
81// CORE.6: Generate opaque function wrapper.
82compiletime_name_fn!(
83    generate_opaque_function,
84    "opaque",
85    "body is hidden from verification"
86);
87
88/// CORE.8: Generate liveness contract check.
89pub fn generate_liveness_check(clause: &Clause) -> String {
90    let expr = expr_to_rust(&clause.body);
91    format!(
92        "    // liveness: eventually {{ {expr} }}\n    \
93         debug_assert!({expr}, \"liveness violation: property must eventually hold\");\n"
94    )
95}
96
97// ---------------------------------------------------------------------------
98// MEM features
99// ---------------------------------------------------------------------------
100
101runtime_assert_fn!(
102    generate_region_annotation,
103    "region constraint",
104    "memory region violation"
105);
106runtime_assert_fn!(
107    generate_allocator_check,
108    "allocator invariant",
109    "allocator contract violation"
110);
111runtime_assert_fn!(
112    generate_circular_buffer_check,
113    "circular buffer invariant",
114    "circular buffer invariant violated"
115);
116
117// ---------------------------------------------------------------------------
118// TYPE features
119// ---------------------------------------------------------------------------
120
121runtime_assert_fn!(
122    generate_structural_invariant,
123    "structural_invariant",
124    "structural invariant violated"
125);
126runtime_assert_fn!(
127    generate_error_propagation_check,
128    "error_propagation",
129    "error propagation violation"
130);
131
132// ---------------------------------------------------------------------------
133// SEC features
134// ---------------------------------------------------------------------------
135
136/// SEC.3: Generate constant-time execution annotation.
137pub fn generate_constant_time_annotation(name: &str) -> String {
138    format!(
139        "    // constant_time: `{name}` must execute in constant time\n    \
140         // WARNING: compiler may optimize away constant-time guarantees\n"
141    )
142}
143
144runtime_assert_fn!(
145    generate_crypto_conformance_check,
146    "crypto conformance: conforms to",
147    "crypto conformance violation"
148);
149
150// ---------------------------------------------------------------------------
151// CONC features
152// ---------------------------------------------------------------------------
153
154/// CONC.2: Generate callback re-entrancy guard (custom, not a simple assert).
155pub fn generate_callback_reentrancy_guard(name: &str) -> String {
156    format!(
157        "    // callback reentrancy guard for `{name}`\n    \
158         // A reentrant call to this function will panic in debug builds\n    \
159         thread_local! {{ static __REENTRANT_{upper}: std::cell::Cell<bool> = \
160         const {{ std::cell::Cell::new(false) }}; }}\n    \
161         __REENTRANT_{upper}.with(|f| {{\n        \
162         debug_assert!(!f.get(), \"reentrant call to {name}\");\n        \
163         f.set(true);\n    \
164         }});\n",
165        upper = name.to_uppercase()
166    )
167}
168
169compiletime_name_fn!(
170    generate_deterministic_annotation,
171    "deterministic",
172    "must be a pure function"
173);
174
175/// CONC.4: Lock ordering annotation.
176pub fn generate_lock_order_annotation(clause: &Clause) -> String {
177    let expr = expr_to_rust(&clause.body);
178    format!(
179        "    // lock_order: {expr}\n    \
180         // Locks must be acquired in the declared order to prevent deadlocks\n"
181    )
182}
183
184/// CONC.5: Temporal deadline annotation.
185pub fn generate_deadline_check(clause: &Clause) -> String {
186    let expr = expr_to_rust(&clause.body);
187    format!(
188        "    // deadline: {expr}\n    \
189         // Operation must complete within the specified time bound\n"
190    )
191}
192
193// ---------------------------------------------------------------------------
194// STOR features
195// ---------------------------------------------------------------------------
196
197runtime_assert_fn!(
198    generate_crash_recovery_check,
199    "crash_recovery invariant",
200    "crash recovery invariant violated"
201);
202runtime_assert_fn!(
203    generate_page_cache_check,
204    "page_cache invariant",
205    "page cache invariant violated"
206);
207runtime_assert_fn!(
208    generate_mvcc_check,
209    "mvcc snapshot isolation",
210    "mvcc isolation violation"
211);
212runtime_assert_fn!(
213    generate_rollback_check,
214    "rollback savepoint",
215    "rollback invariant violated"
216);
217runtime_assert_fn!(
218    generate_monotonic_check,
219    "monotonic state",
220    "monotonic state violation: value must not decrease"
221);
222runtime_assert_fn!(
223    generate_storage_failure_check,
224    "storage_failure mode",
225    "storage failure handling violation"
226);
227
228// ---------------------------------------------------------------------------
229// FMT features
230// ---------------------------------------------------------------------------
231
232runtime_assert_fn!(
233    generate_binary_format_check,
234    "binary_format layout",
235    "binary format layout violation"
236);
237runtime_assert_fn!(
238    generate_bit_level_check,
239    "bit_level field",
240    "bit level layout violation"
241);
242runtime_assert_fn!(
243    generate_string_encoding_check,
244    "string_encoding",
245    "string encoding violation"
246);
247runtime_assert_fn!(
248    generate_checksum_check,
249    "checksum integrity",
250    "checksum integrity violation"
251);
252runtime_assert_fn!(
253    generate_protocol_grammar_check,
254    "protocol_grammar",
255    "protocol_grammar violation"
256);
257
258// ---------------------------------------------------------------------------
259// NUM features
260// ---------------------------------------------------------------------------
261
262runtime_assert_fn!(
263    generate_numerical_precision_check,
264    "numerical_precision",
265    "numerical precision exceeded"
266);
267runtime_assert_fn!(
268    generate_precomputed_table_check,
269    "precomputed_table",
270    "precomputed table invariant violated"
271);
272
273// ---------------------------------------------------------------------------
274// PLAT features
275// ---------------------------------------------------------------------------
276
277/// PLAT.1: Platform abstraction annotation.
278pub fn generate_platform_abstraction(clause: &Clause) -> String {
279    let expr = expr_to_rust(&clause.body);
280    format!(
281        "    // platform_abstraction: {expr}\n    \
282         // Platform-specific code must implement this contract on each target\n"
283    )
284}
285
286/// PLAT.2: Feature flag annotation.
287pub fn generate_feature_flag(clause: &Clause) -> String {
288    let expr = expr_to_rust(&clause.body);
289    format!(
290        "    // feature_flag: {expr}\n    \
291         // This code is only available when the feature flag is enabled\n"
292    )
293}
294
295runtime_assert_fn!(
296    generate_resource_limit_check,
297    "resource_limit",
298    "resource limit exceeded"
299);
300
301// ---------------------------------------------------------------------------
302// PERF features
303// ---------------------------------------------------------------------------
304
305/// PERF.1: Unsafe escape annotation.
306pub fn generate_unsafe_escape(clause: &Clause) -> String {
307    let expr = expr_to_rust(&clause.body);
308    format!(
309        "    // unsafe_escape: {expr}\n    \
310         // SAFETY: manually verified for performance; see contract above\n"
311    )
312}
313
314/// PERF.2: Complexity bound annotation.
315pub fn generate_complexity_bound(clause: &Clause) -> String {
316    let expr = expr_to_rust(&clause.body);
317    format!(
318        "    // complexity_bound: {expr}\n    \
319         // Algorithm complexity must not exceed the declared bound\n"
320    )
321}
322
323// ---------------------------------------------------------------------------
324// Compile-time enforcement functions
325//
326// These generate Rust code that the compiler itself checks, not runtime
327// assertions. They use compile_error!, const assertions, type system
328// restrictions (unsafe, visibility), and cfg attributes.
329// ---------------------------------------------------------------------------
330
331// ---------------------------------------------------------------------------
332// Compile-time enforcement functions
333//
334// These generate Rust code that the compiler itself checks, not runtime
335// assertions. They use compile_error!, const assertions, type system
336// restrictions (unsafe, visibility), and cfg attributes.
337//
338// Functions with unique logic are written out; simple comment stubs use
339// the compiletime_comment_fn! or compiletime_name_fn! macros.
340// ---------------------------------------------------------------------------
341
342// -- Simple comment stubs (no name parameter) --
343compiletime_comment_fn!(
344    compile_time_weak_memory,
345    "compile_time_ordering: memory ordering validated at compile time"
346);
347compiletime_comment_fn!(
348    compile_time_fixed_width,
349    "compile_time_fixed_width: overflow is checked at compile time in const contexts"
350);
351compiletime_comment_fn!(
352    compile_time_error_propagation,
353    "compile_time_error_propagation: Result<T, E> enforced by Rust type system"
354);
355compiletime_comment_fn!(
356    compile_time_numerical_precision,
357    "compile_time_numerical_precision: const assertions on precision bounds"
358);
359compiletime_comment_fn!(
360    compile_time_resource_limit,
361    "compile_time_resource_limit: const assertion on resource bounds"
362);
363compiletime_comment_fn!(
364    compile_time_binary_format,
365    "compile_time_binary_format: const assert on layout size/alignment"
366);
367compiletime_comment_fn!(
368    compile_time_mvcc,
369    "compile_time_mvcc: SnapshotId newtype, !Copy to prevent duplication"
370);
371
372// -- Simple comment stubs (with name parameter) --
373compiletime_name_fn!(
374    compile_time_shared_memory,
375    "compile_time_shared_memory",
376    "requires Sync + Send bounds"
377);
378compiletime_name_fn!(
379    compile_time_interface,
380    "compile_time_interface",
381    "trait bounds enforced by rustc"
382);
383compiletime_name_fn!(
384    compile_time_feature_flag,
385    "compile_time_feature_flag",
386    "gated by cfg attribute"
387);
388compiletime_name_fn!(
389    compile_time_unsafe_escape,
390    "compile_time_unsafe_escape",
391    "requires unsafe block at call site"
392);
393compiletime_name_fn!(
394    compile_time_region,
395    "compile_time_region",
396    "uses struct Region<T> newtype"
397);
398compiletime_name_fn!(
399    compile_time_allocator,
400    "compile_time_allocator",
401    "requires A: GlobalAlloc bound"
402);
403compiletime_name_fn!(
404    compile_time_reentrancy,
405    "compile_time_reentrancy",
406    "callback type is !Send"
407);
408compiletime_name_fn!(
409    compile_time_structural,
410    "compile_time_structural",
411    "invariant enforced by #[non_exhaustive] + constructor"
412);
413
414// -- Multi-line comment stubs (with name) --
415compiletime_name_fn!(
416    compile_time_trigger,
417    "compile_time_trigger",
418    "trigger pattern validated at compile time\n    // Ensures quantifier triggers are syntactically valid and non-trivial"
419);
420compiletime_name_fn!(
421    compile_time_opaque,
422    "compile_time_opaque",
423    "body is hidden from callers\n    // Opaque function signatures are enforced at compile time via module privacy"
424);
425compiletime_name_fn!(
426    compile_time_prophecy,
427    "compile_time_prophecy",
428    "is a prophecy (proof-only, erased at runtime)\n    // Prophecy variables must not affect runtime behavior"
429);
430compiletime_name_fn!(
431    compile_time_liveness,
432    "compile_time_liveness",
433    "liveness obligation tracked at compile time\n    // Compiler verifies progress guarantee via ranking function"
434);
435compiletime_name_fn!(
436    compile_time_lock_order,
437    "compile_time_lock_order",
438    "lock acquisition order enforced by type system\n    // Lock rank is a compile-time constant; out-of-order acquisition is a type error"
439);
440compiletime_name_fn!(
441    compile_time_deadline,
442    "compile_time_deadline",
443    "timeout bound validated at compile time\n    // Deadline constants must be positive and finite"
444);
445compiletime_name_fn!(
446    compile_time_crash_recovery,
447    "compile_time_crash_recovery",
448    "recovery invariant tracked\n    // WAL write must precede state mutation (enforced by type ordering)"
449);
450compiletime_name_fn!(
451    compile_time_codec_registry,
452    "compile_time_codec_registry",
453    "codec must be registered at compile time\n    // Unregistered codec IDs are a compile-time error"
454);
455compiletime_name_fn!(
456    compile_time_checksum,
457    "compile_time_checksum",
458    "checksum algorithm validated at compile time\n    // Checksum width must match the declared format"
459);
460compiletime_name_fn!(
461    compile_time_protocol_grammar,
462    "compile_time_protocol_grammar",
463    "state machine transitions validated\n    // Unreachable states and missing transitions are compile-time errors"
464);
465compiletime_name_fn!(
466    compile_time_precomputed_table,
467    "compile_time_precomputed_table",
468    "table entries validated at compile time\n    // const _: () = assert!(TABLE.len() == EXPECTED_SIZE);"
469);
470compiletime_name_fn!(
471    compile_time_complexity_bound,
472    "compile_time_complexity_bound",
473    "complexity annotation checked\n    // Recursive depth and loop bounds validated against declared complexity"
474);
475compiletime_name_fn!(
476    compile_time_test_gen,
477    "compile_time_test_gen",
478    "test harness generated at compile time\n    // Property-based tests derived from contract specifications"
479);
480compiletime_name_fn!(
481    compile_time_behavioral_equiv,
482    "compile_time_behavioral_equiv",
483    "equivalence proof obligation\n    // Both implementations must satisfy the same contract"
484);
485compiletime_name_fn!(
486    compile_time_multi_pass,
487    "compile_time_multi_pass",
488    "refinement chain validated at compile time\n    // Each pass must preserve the refinement relation"
489);
490compiletime_name_fn!(
491    compile_time_incremental,
492    "compile_time_incremental",
493    "contract version compatibility checked\n    // New contract version must be backward-compatible with previous version"
494);
495compiletime_name_fn!(
496    compile_time_scoped_invariant,
497    "compile_time_scoped_invariant",
498    "invariant suspension scope tracked\n    // Invariant must be re-established before scope exit"
499);
500
501/// CORE.5: Trigger pattern validation.
502///
503/// Emits a compile-time assertion that the trigger pattern expression
504/// is non-empty. Empty triggers cause Z3 to enumerate all terms, which
505/// is almost always a performance bug.
506pub fn compile_time_trigger_pattern(clause: &Clause) -> String {
507    let body = expr_to_rust(&clause.body);
508    if body.trim().is_empty() || body.trim() == "()" {
509        "    compile_error!(\"CORE.5: trigger pattern must not be empty; \
510             empty triggers cause unbounded Z3 term enumeration\");\n"
511            .to_string()
512    } else {
513        format!(
514            "    // compile_time_trigger_pattern: pattern `{body}` validated\n    \
515             const _: () = {{ /* trigger pattern `{body}` is syntactically present */ }};\n"
516        )
517    }
518}
519
520/// SEC.5: Dependent type / information-flow label enforcement.
521///
522/// Generates a newtype wrapper struct for each label and a
523/// `compile_error!` if a secret value flows to a public context.
524pub fn compile_time_dependent_types(clause: &Clause) -> String {
525    let body = expr_to_rust(&clause.body);
526    // The clause body names the label (e.g., "secret", "public", "confidential").
527    let label = body.trim();
528    if label.is_empty() {
529        "    compile_error!(\"SEC.5: dependent type label must not be empty\");\n".to_string()
530    } else {
531        // Generate a newtype wrapper that prevents implicit conversion.
532        // In real code this would create Secret<T>(T) / Public<T>(T).
533        format!(
534            "    /// SEC.5 info-flow label: `{label}`\n    \
535             #[derive(Debug, Clone)]\n    \
536             struct Label_{label}<T>(T);\n    \
537             impl<T> Label_{label}<T> {{\n        \
538                 fn into_inner(self) -> T {{ self.0 }}\n    \
539             }}\n"
540        )
541    }
542}
543
544// -- Functions with unique logic (compile_error!, cfg gates, multi-line) --
545
546/// CORE.1: Ghost code erasure.
547pub fn compile_time_ghost_erasure(name: &str) -> String {
548    format!(
549        "    // compile_time_ghost: ensure `{name}` is erased in release\n    \
550         const _: () = {{ /* ghost compile-time gate */ }};\n"
551    )
552}
553
554/// SEC.1: Taint tracking compile_error!.
555pub fn compile_time_taint(name: &str) -> String {
556    format!(
557        "    // compile_time_taint: `{name}` must be sanitized before use\n    \
558         // In production: compile_error! if tainted value reaches trusted sink\n    \
559         #[cfg(assura_strict_taint)]\n    \
560         compile_error!(\"SEC.1: tainted value `{name}` flows to trusted sink \
561         without sanitization\");\n"
562    )
563}
564
565/// SEC.3: Constant-time compile_error!.
566pub fn compile_time_constant_time(name: &str) -> String {
567    format!(
568        "    // compile_time_constant_time: `{name}` must not branch on secrets\n    \
569         #[cfg(assura_strict_ct)]\n    \
570         compile_error!(\"SEC.3: data-dependent branch detected in constant_time \
571         function `{name}`\");\n"
572    )
573}
574
575/// SEC.4: Secure erasure compile_error!.
576pub fn compile_time_zeroize(name: &str) -> String {
577    format!(
578        "    // compile_time_zeroize: `{name}` must implement Zeroize or be erased\n    \
579         #[cfg(assura_strict_zeroize)]\n    \
580         compile_error!(\"SEC.4: type `{name}` in secure_erase scope does not \
581         implement Zeroize\");\n"
582    )
583}
584
585/// SEC.5: Crypto conformance compile_error!.
586pub fn compile_time_crypto(name: &str) -> String {
587    format!(
588        "    // compile_time_crypto: `{name}` must conform to approved algorithm\n    \
589         #[cfg(assura_strict_crypto)]\n    \
590         compile_error!(\"SEC.5: algorithm `{name}` is not in the approved list\");\n"
591    )
592}
593
594/// CORE.2: Lemma erasure compile_error!.
595pub fn compile_time_lemma(name: &str) -> String {
596    format!(
597        "    // compile_time_lemma: `{name}` is erased (proof-only)\n    \
598         #[cfg(not(debug_assertions))]\n    \
599         compile_error!(\"CORE.2: lemma `{name}` leaked to runtime code path\");\n"
600    )
601}
602
603/// CORE.4: Axiomatic definition compile_error!.
604pub fn compile_time_axiom(name: &str) -> String {
605    format!(
606        "    // compile_time_axiom: `{name}` is assumed without proof\n    \
607         #[cfg(not(assura_allow_axioms))]\n    \
608         compile_error!(\"CORE.4: axiom `{name}` used without --allow-axioms flag\");\n"
609    )
610}
611
612/// CONC.3: Determinism compile_error!.
613pub fn compile_time_determinism(name: &str) -> String {
614    format!(
615        "    // compile_time_determinism: `{name}` must be a pure function\n    \
616         #[cfg(assura_strict_determinism)]\n    \
617         compile_error!(\"CONC.3: deterministic function `{name}` calls \
618         non-pure effect\");\n"
619    )
620}
621
622/// FMT.3: String encoding compile_error!.
623pub fn compile_time_string_encoding(name: &str) -> String {
624    format!(
625        "    // compile_time_string_encoding: `{name}` must be a known encoding\n    \
626         #[cfg(assura_strict_encoding)]\n    \
627         compile_error!(\"FMT.3: encoding `{name}` is not in the known set\");\n"
628    )
629}
630
631/// CORE.3: Frame conditions.
632///
633/// Extracts field names from the modifies clause and generates
634/// `debug_assert_eq!` checks that non-modified fields are unchanged.
635pub fn compile_time_frame(clause: &Clause, name: &str) -> String {
636    let body = expr_to_rust(&clause.body);
637    let fields: Vec<&str> = body
638        .split([',', '{', '}'])
639        .map(str::trim)
640        .filter(|s| !s.is_empty())
641        .collect();
642
643    use std::fmt::Write;
644    let mut out = String::new();
645    if fields.is_empty() {
646        let _ = writeln!(
647            out,
648            "    compile_error!(\"CORE.3: frame condition for `{name}` has no fields; \
649             modifies clause must list at least one field\");"
650        );
651    } else {
652        let _ = writeln!(
653            out,
654            "    // compile_time_frame: `{name}` may only modify: {}",
655            fields.join(", ")
656        );
657        for field in &fields {
658            let safe_name = field.replace('.', "_");
659            let _ = writeln!(
660                out,
661                "    debug_assert_eq!({field}, {}{safe_name}, \
662                 \"CORE.3: frame violation in `{name}`: `{field}` was not listed in modifies\");",
663                OLD_VAR_PREFIX
664            );
665        }
666    }
667    out
668}
669
670/// PLAT.1: Platform abstraction cfg gate.
671pub fn compile_time_platform(name: &str) -> String {
672    format!(
673        "    // compile_time_platform: `{name}` requires cfg(target_os) gate\n    \
674         // #[cfg(not(any(target_os = \"linux\", target_os = \"macos\", \
675         target_os = \"windows\")))]\n    \
676         // compile_error!(\"unsupported platform for `{name}`\");\n"
677    )
678}
679
680/// MEM.4: Circular buffer power-of-two const assert.
681pub fn compile_time_circular() -> String {
682    "    // compile_time_circular: const assert capacity is power of two\n    \
683         // const _: () = assert!(CAP.is_power_of_two());\n"
684        .to_string()
685}
686
687/// FMT.2: Bit-level width sum const assert.
688pub fn compile_time_bit_level() -> String {
689    "    // compile_time_bit_level: const assert bit field widths sum correctly\n    \
690         // const _: () = assert!(F1_BITS + F2_BITS <= 64);\n"
691        .to_string()
692}
693
694/// STOR.2: Page cache alignment const assert.
695pub fn compile_time_page_cache() -> String {
696    "    // compile_time_page_cache: const assert page size alignment\n    \
697         // const _: () = assert!(PAGE_SIZE % 4096 == 0);\n"
698        .to_string()
699}
700
701/// STOR.4: Rollback #[must_use] handle.
702pub fn compile_time_rollback() -> String {
703    "    // compile_time_rollback: #[must_use] Savepoint handle\n    \
704         // Dropping without commit or rollback is a compile warning\n"
705        .to_string()
706}
707
708/// STOR.5: Monotonic wrapper type.
709pub fn compile_time_monotonic() -> String {
710    "    // compile_time_monotonic: monotonic wrapper prevents non-monotonic updates\n    \
711         // pub struct Monotonic<T: Ord>(T); // only advance(), no set()\n"
712        .to_string()
713}
714
715/// STOR.6: Storage failure #[must_use].
716pub fn compile_time_storage_failure() -> String {
717    "    // compile_time_storage_failure: #[must_use] on error results\n    \
718         // Unhandled storage failures are compile warnings\n"
719        .to_string()
720}
721
722// ---------------------------------------------------------------------------
723// TEST features
724// ---------------------------------------------------------------------------
725
726/// TEST.2: Generate behavioral_equivalence test skeleton.
727pub fn generate_behavioral_equiv_test(name: &str, clause: &Clause) -> String {
728    let expr = expr_to_rust(&clause.body);
729    format!(
730        "    // behavioral_equiv: {name} ~ {expr}\n    \
731         // Both implementations must produce identical results\n"
732    )
733}
734
735/// TEST.3: Generate multi_pass_refinement check.
736pub fn generate_multi_pass_refinement(clause: &Clause) -> String {
737    let expr = expr_to_rust(&clause.body);
738    format!(
739        "    // multi_pass_refinement: {expr}\n    \
740         debug_assert!({expr}, \"refinement pass invariant violated\");\n"
741    )
742}
743
744// ---------------------------------------------------------------------------
745// MISC features
746// ---------------------------------------------------------------------------
747
748/// MISC.1: Generate incremental_contract version annotation.
749pub fn generate_incremental_contract(clause: &Clause) -> String {
750    let expr = expr_to_rust(&clause.body);
751    format!(
752        "    // incremental_contract version: {expr}\n    \
753         // Contract evolution: backward-compatible changes only\n"
754    )
755}
756
757/// MISC.2: Generate scoped_invariant suspension marker.
758pub fn generate_scoped_invariant(clause: &Clause) -> String {
759    let expr = expr_to_rust(&clause.body);
760    format!(
761        "    // scoped_invariant suspended: {expr}\n    \
762         // Invariant checking is suspended within this scope\n"
763    )
764}
765
766// ---------------------------------------------------------------------------
767// Dispatch: generate feature-specific code from clause kind
768// ---------------------------------------------------------------------------
769
770/// Generate feature-specific codegen for a single clause.
771///
772/// Returns true if the clause was handled as a feature annotation,
773/// false if it should be handled by the default codegen path.
774pub fn generate_feature_clause(clause: &Clause, fn_name: &str, code: &mut String) -> bool {
775    use assura_ast::features::Feature;
776    let kind_str = match &clause.kind {
777        ClauseKind::Other(kind) => kind.as_str(),
778        _ => return false,
779    };
780    let feature = match Feature::from_clause_kind(kind_str) {
781        Some(f) => f,
782        None => return false,
783    };
784    match feature {
785        // CORE
786        Feature::GhostErasure => {
787            code.push_str(&generate_ghost_compile_check(fn_name));
788            code.push_str(&compile_time_ghost_erasure(fn_name));
789        }
790        Feature::LemmaErasure => {
791            code.push_str(&generate_axiomatic_definition(clause));
792            code.push_str(&compile_time_axiom(fn_name));
793        }
794        Feature::FrameConditions => {
795            code.push_str(&compile_time_frame(clause, fn_name));
796        }
797        Feature::AxiomaticDefinitions => {
798            code.push_str(&compile_time_trigger(fn_name));
799        }
800        Feature::TriggerPatterns => {
801            code.push_str(&compile_time_trigger_pattern(clause));
802        }
803        Feature::OpaqueFunctions => {
804            code.push_str(&generate_opaque_function(fn_name));
805            code.push_str(&compile_time_opaque(fn_name));
806        }
807        Feature::ProphecyVariables => {
808            code.push_str(&compile_time_prophecy(fn_name));
809        }
810        Feature::Liveness => {
811            code.push_str(&generate_liveness_check(clause));
812            code.push_str(&compile_time_liveness(fn_name));
813        }
814        // MEM
815        Feature::RegionAnnotations => {
816            code.push_str(&generate_region_annotation(clause));
817            code.push_str(&compile_time_region(fn_name));
818        }
819        Feature::FixedWidth => {
820            code.push_str(&compile_time_fixed_width());
821        }
822        Feature::AllocatorContracts => {
823            code.push_str(&generate_allocator_check(clause));
824            code.push_str(&compile_time_allocator(fn_name));
825        }
826        Feature::CircularBuffer => {
827            code.push_str(&generate_circular_buffer_check(clause));
828            code.push_str(&compile_time_circular());
829        }
830        // TYPE
831        Feature::InterfaceConformance => {
832            code.push_str(&compile_time_interface(fn_name));
833        }
834        Feature::StructuralInvariants => {
835            code.push_str(&generate_structural_invariant(clause));
836            code.push_str(&compile_time_structural(fn_name));
837        }
838        Feature::ErrorPropagation => {
839            code.push_str(&generate_error_propagation_check(clause));
840            code.push_str(&compile_time_error_propagation());
841        }
842        // SEC
843        Feature::TaintTracking => {
844            code.push_str(&compile_time_taint(fn_name));
845        }
846        Feature::ConstantTime => {
847            code.push_str(&generate_constant_time_annotation(fn_name));
848            code.push_str(&compile_time_constant_time(fn_name));
849        }
850        Feature::SecureErasure => {
851            code.push_str(&compile_time_zeroize(fn_name));
852        }
853        Feature::CryptoConformance => {
854            code.push_str(&generate_crypto_conformance_check(clause));
855            code.push_str(&compile_time_crypto(fn_name));
856        }
857        Feature::DependentTypes => {
858            code.push_str(&compile_time_dependent_types(clause));
859        }
860        // CONC
861        Feature::SharedMemory => {
862            code.push_str(&compile_time_shared_memory(fn_name));
863        }
864        Feature::CallbackReentrancy => {
865            code.push_str(&generate_callback_reentrancy_guard(fn_name));
866            code.push_str(&compile_time_reentrancy(fn_name));
867        }
868        Feature::Determinism => {
869            code.push_str(&generate_deterministic_annotation(fn_name));
870            code.push_str(&compile_time_determinism(fn_name));
871        }
872        Feature::LockOrdering => {
873            code.push_str(&generate_lock_order_annotation(clause));
874            code.push_str(&compile_time_lock_order(fn_name));
875        }
876        Feature::Deadline => {
877            code.push_str(&generate_deadline_check(clause));
878            code.push_str(&compile_time_deadline(fn_name));
879        }
880        Feature::WeakMemoryOrdering => {
881            code.push_str(&compile_time_weak_memory());
882        }
883        // STOR
884        Feature::CrashRecovery => {
885            code.push_str(&generate_crash_recovery_check(clause));
886            code.push_str(&compile_time_crash_recovery(fn_name));
887        }
888        Feature::PageCache => {
889            code.push_str(&generate_page_cache_check(clause));
890            code.push_str(&compile_time_page_cache());
891        }
892        Feature::MvccIsolation => {
893            code.push_str(&generate_mvcc_check(clause));
894            code.push_str(&compile_time_mvcc());
895        }
896        Feature::RollbackSavepoint => {
897            code.push_str(&generate_rollback_check(clause));
898            code.push_str(&compile_time_rollback());
899        }
900        Feature::MonotonicState => {
901            code.push_str(&generate_monotonic_check(clause));
902            code.push_str(&compile_time_monotonic());
903        }
904        Feature::StorageFailure => {
905            code.push_str(&generate_storage_failure_check(clause));
906            code.push_str(&compile_time_storage_failure());
907        }
908        // FMT
909        Feature::BinaryFormat => {
910            code.push_str(&generate_binary_format_check(clause));
911            code.push_str(&compile_time_binary_format());
912        }
913        Feature::BitLevel => {
914            code.push_str(&generate_bit_level_check(clause));
915            code.push_str(&compile_time_bit_level());
916        }
917        Feature::StringEncoding => {
918            code.push_str(&generate_string_encoding_check(clause));
919            code.push_str(&compile_time_string_encoding(fn_name));
920        }
921        Feature::CodecRegistry => {
922            code.push_str(&compile_time_codec_registry(fn_name));
923        }
924        Feature::Checksum => {
925            code.push_str(&generate_checksum_check(clause));
926            code.push_str(&compile_time_checksum(fn_name));
927        }
928        Feature::ProtocolGrammar => {
929            code.push_str(&generate_protocol_grammar_check(clause));
930            code.push_str(&compile_time_protocol_grammar(fn_name));
931        }
932        // NUM
933        Feature::NumericalPrecision => {
934            code.push_str(&generate_numerical_precision_check(clause));
935            code.push_str(&compile_time_numerical_precision());
936        }
937        Feature::PrecomputedTable => {
938            code.push_str(&generate_precomputed_table_check(clause));
939            code.push_str(&compile_time_precomputed_table(fn_name));
940        }
941        // PLAT
942        Feature::PlatformAbstraction => {
943            code.push_str(&generate_platform_abstraction(clause));
944            code.push_str(&compile_time_platform(fn_name));
945        }
946        Feature::FeatureFlag => {
947            code.push_str(&generate_feature_flag(clause));
948            code.push_str(&compile_time_feature_flag(fn_name));
949        }
950        Feature::ResourceLimit => {
951            code.push_str(&generate_resource_limit_check(clause));
952            code.push_str(&compile_time_resource_limit());
953        }
954        // PERF
955        Feature::UnsafeEscape => {
956            code.push_str(&generate_unsafe_escape(clause));
957            code.push_str(&compile_time_unsafe_escape(fn_name));
958        }
959        Feature::ComplexityBound => {
960            code.push_str(&generate_complexity_bound(clause));
961            code.push_str(&compile_time_complexity_bound(fn_name));
962        }
963        // TEST
964        Feature::TestGenCoverage => {
965            code.push_str(&compile_time_test_gen(fn_name));
966        }
967        Feature::BehavioralEquiv => {
968            code.push_str(&generate_behavioral_equiv_test(fn_name, clause));
969            code.push_str(&compile_time_behavioral_equiv(fn_name));
970        }
971        Feature::MultiPassRefinement => {
972            code.push_str(&generate_multi_pass_refinement(clause));
973            code.push_str(&compile_time_multi_pass(fn_name));
974        }
975        // MISC
976        Feature::IncrementalContract => {
977            code.push_str(&generate_incremental_contract(clause));
978            code.push_str(&compile_time_incremental(fn_name));
979        }
980        Feature::ScopedInvariant => {
981            code.push_str(&generate_scoped_invariant(clause));
982            code.push_str(&compile_time_scoped_invariant(fn_name));
983        }
984    }
985    true
986}
987
988/// Generate all feature-specific annotations for a set of clauses.
989/// Called from contract and function codegen paths.
990pub fn generate_all_feature_clauses(clauses: &[Clause], fn_name: &str, code: &mut String) {
991    for clause in clauses {
992        generate_feature_clause(clause, fn_name, code);
993    }
994}
995#[cfg(test)]
996#[path = "features_tests.rs"]
997mod tests;