Skip to main content

cairo_lang_filesystem/
flag.rs

1use cairo_lang_utils::Intern;
2use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
3use salsa::{Database, Setter};
4use serde::{Deserialize, Serialize};
5
6use crate::db::files_group_input;
7use crate::ids::{FlagId, FlagLongId};
8
9/// A compilation flag.
10#[derive(PartialEq, Eq, Debug, Copy, Clone, Serialize, Deserialize, Hash, salsa::Update)]
11pub enum Flag {
12    /// Whether to automatically add `withdraw_gas` calls in code cycles.
13    /// Default is true - automatically add.
14    ///
15    /// Additionally controls addition of `redeposit_gas` which happens on default.
16    AddWithdrawGas(bool),
17    NumericMatchOptimizationMinArmsThreshold(usize),
18    /// Whether to add panic backtrace handling to the generated code.
19    ///
20    /// Default is false - do not add, as it won't be used in production.
21    PanicBacktrace(bool),
22    /// Whether to use unsafe_panic in the generated code.
23    ///
24    /// Default is false as it makes panic unprovable.
25    UnsafePanic(bool),
26    /// Whether to use future_sierra in the generated code.
27    ///
28    /// Default is false.
29    FutureSierra(bool),
30}
31impl Flag {
32    pub const ADD_WITHDRAW_GAS: &'static str = "add_withdraw_gas";
33    pub const NUMERIC_MATCH_OPTIMIZATION_MIN_ARMS_THRESHOLD: &'static str =
34        "numeric_match_optimization_min_arms_threshold";
35    pub const PANIC_BACKTRACE: &'static str = "panic_backtrace";
36    pub const UNSAFE_PANIC: &'static str = "unsafe_panic";
37    pub const FUTURE_SIERRA: &'static str = "future_sierra";
38}
39
40/// Extracts the value of a flag given the flag string and the expected variant.
41/// Returns `None` if the flag is missing.
42/// Panics if there is a variant mismatch.
43macro_rules! extract_flag_value {
44    ($db:ident, $flag:ident, $variant:ident) => {{
45        let flag = FlagId::new($db, FlagLongId(Flag::$flag.into()));
46        match $db.get_flag(flag) {
47            None => None,
48            Some(Flag::$variant(value)) => Some(value),
49            Some(other) => panic!("Unexpected flag variant for `{}`: {other:?}", Flag::$flag),
50        }
51    }};
52}
53
54/// Returns the value of the `add_withdraw_gas` flag, or `true` if the flag is not set.
55#[salsa::tracked]
56fn flag_add_withdraw_gas(db: &dyn Database) -> bool {
57    extract_flag_value!(db, ADD_WITHDRAW_GAS, AddWithdrawGas).unwrap_or(true)
58}
59
60/// Returns the value of the `numeric_match_optimization_min_arms_threshold` flag, or `None` if the
61/// flag is not set.
62#[salsa::tracked]
63fn flag_numeric_match_optimization_min_arms_threshold(db: &dyn salsa::Database) -> Option<usize> {
64    extract_flag_value!(
65        db,
66        NUMERIC_MATCH_OPTIMIZATION_MIN_ARMS_THRESHOLD,
67        NumericMatchOptimizationMinArmsThreshold
68    )
69}
70
71/// Returns the value of the `unsafe_panic` flag, or `false` if the flag is not set.
72#[salsa::tracked]
73fn flag_panic_backtrace(db: &dyn salsa::Database) -> bool {
74    extract_flag_value!(db, PANIC_BACKTRACE, PanicBacktrace).unwrap_or_default()
75}
76
77/// Returns the value of the `unsafe_panic` flag, or `false` if the flag is not set.
78#[salsa::tracked]
79fn flag_unsafe_panic(db: &dyn salsa::Database) -> bool {
80    extract_flag_value!(db, UNSAFE_PANIC, UnsafePanic).unwrap_or_default()
81}
82
83/// Returns the value of the `future_sierra` flag, or `false` if the flag is not set.
84#[salsa::tracked]
85fn flag_future_sierra(db: &dyn salsa::Database) -> bool {
86    extract_flag_value!(db, FUTURE_SIERRA, FutureSierra).unwrap_or_default()
87}
88
89#[salsa::tracked(returns(ref))]
90pub fn flags<'db>(db: &'db dyn Database) -> OrderedHashMap<FlagId<'db>, Flag> {
91    let inp = files_group_input(db).flags(db).as_ref().expect("flags is not set");
92    inp.iter().map(|(flag_id, flag)| (flag_id.clone().intern(db), *flag)).collect()
93}
94
95/// Returns a reference to the flag value.
96#[salsa::tracked]
97fn get_flag<'db>(db: &'db dyn Database, id: FlagId<'db>) -> Option<Flag> {
98    db.flags().get(&id).copied()
99}
100
101pub trait FlagsGroup: Database {
102    /// Interned version of `flags_input`.
103    fn flags<'db>(&'db self) -> &'db OrderedHashMap<FlagId<'db>, Flag> {
104        flags(self.as_dyn_database())
105    }
106    /// Query to get a compilation flag by its ID.
107    fn get_flag<'db>(&'db self, id: FlagId<'db>) -> Option<Flag> {
108        get_flag(self.as_dyn_database(), id)
109    }
110
111    /// Sets the given flag value. None value removes the flag.
112    fn set_flag(&mut self, flag: FlagLongId, value: Option<Flag>) {
113        let db_ref = self.as_dyn_database();
114        let mut flags = files_group_input(db_ref).flags(db_ref).clone().unwrap();
115        match value {
116            Some(value) => flags.insert(flag, value),
117            None => flags.swap_remove(&flag),
118        };
119        files_group_input(db_ref).set_flags(self).to(Some(flags));
120    }
121    /// Returns the value of the `add_withdraw_gas` flag.
122    fn flag_add_withdraw_gas(&self) -> bool {
123        flag_add_withdraw_gas(self.as_dyn_database())
124    }
125    /// Returns the value of the `numeric_match_optimization_min_arms_threshold` flag.
126    fn flag_numeric_match_optimization_min_arms_threshold(&self) -> Option<usize> {
127        flag_numeric_match_optimization_min_arms_threshold(self.as_dyn_database())
128    }
129    /// Returns the value of the `panic_backtrace` flag.
130    fn flag_panic_backtrace(&self) -> bool {
131        flag_panic_backtrace(self.as_dyn_database())
132    }
133    /// Returns the value of the `unsafe_panic` flag.
134    fn flag_unsafe_panic(&self) -> bool {
135        flag_unsafe_panic(self.as_dyn_database())
136    }
137    /// Returns the value of the `future_sierra` flag.
138    fn flag_future_sierra(&self) -> bool {
139        flag_future_sierra(self.as_dyn_database())
140    }
141}
142impl<T: Database + ?Sized> FlagsGroup for T {}