Skip to main content

conjure_cp_core/
lib.rs

1#[cfg(not(any(feature = "sat-cadical", feature = "sat-batsat")))]
2compile_error!("Select a SAT backend: enable sat-cadical or sat-batsat.");
3#[cfg(all(target_family = "wasm", not(feature = "sat-batsat")))]
4compile_error!("Wasm requires sat-batsat; use --no-default-features --features sat-batsat.");
5
6#[doc(hidden)]
7pub extern crate self as conjure_cp_core;
8
9#[doc(hidden)]
10pub use ast::Model;
11
12pub mod ast;
13
14// NOTE: this module defines the bug! macro, which is exported at the crate level, and has no other
15// contents.
16pub mod bug;
17
18pub mod context;
19pub mod domain_tightening;
20pub mod error;
21pub mod instantiate;
22pub mod objective;
23pub mod parse;
24pub mod representation;
25pub mod rule_engine;
26pub mod settings;
27pub mod solver;
28pub mod stats;
29
30// Various internal helper functions
31pub mod utils;
32
33/// Creates a [`Domain::Int`](ast::Domain::Int).
34///
35/// # Examples
36/// ```
37/// use conjure_cp_core::{domain_int,range,ast::Domain};
38///
39/// let a = 2*10;
40/// assert_eq!(domain_int!(1..5,a+2,), Domain::int(vec![range!(1..5),range!(a+2)]));
41/// assert_eq!(domain_int!(), Domain::int_ground(vec![]))
42/// ```
43#[macro_export]
44macro_rules! domain_int {
45    () => {$crate::ast::Domain::int_ground(vec![])};
46
47    // when parsing expressions, rust groups 1..2 into a single token tree, (1..2)
48    // however, we want it to be three seperate token trees [1,..,2] for parsing.
49    // use defile to turn it back into 3 token trees
50    ($($e:expr),+ $(,)?) => {::defile::defile! { $crate::ast::Domain::int(vec![$($crate::range!(@$e)),+]) } };
51}
52
53/// Creates a [`GroundDomain::Int`]
54#[macro_export]
55macro_rules! domain_int_ground {
56    () => {$crate::ast::GroundDomain::Int(vec![]).into()};
57
58    // when parsing expressions, rust groups 1..2 into a single token tree, (1..2)
59    // however, we want it to be three seperate token trees [1,..,2] for parsing.
60    // use defile to turn it back into 3 token trees
61    ($($e:expr),+ $(,)?) => {::defile::defile! { $crate::ast::GroundDomain::Int(vec![$($crate::range!(@$e)),+], None).into() } };
62}
63
64/// Creates a [`Range`](ast::Range).
65///
66/// # Examples
67///
68/// ```
69/// use conjure_cp_core::{range,ast::Range};
70///
71/// let a = 2*10;
72/// assert_eq!(range!(..a),Range::UnboundedL(a));
73/// assert_eq!(range!(2*5..),Range::UnboundedR(10));
74/// assert_eq!(range!(..10),Range::UnboundedL(10));
75/// assert_eq!(range!(1..5),Range::Bounded(1,5));
76/// assert_eq!(range!(Some(10).unwrap()),Range::Single(10));
77/// ```
78#[macro_export]
79macro_rules! range {
80    // decl macros have no lookahead, hence this nonsense with pushdown automata.
81
82    // @hasLowerbound: have atleast one token of the lower bound on the stack
83    (@hasLowerBound [$($lower:tt)+] -> ..) => {$crate::ast::Range::UnboundedR($crate::as_expr!($($lower)+))};
84    (@hasLowerBound [$($lower:tt)+] -> .. $($tail:tt)+) => {$crate::ast::Range::Bounded($crate::as_expr!($($lower)+),$crate::as_expr!($($tail)+))};
85    (@hasLowerBound [$($lower:tt)+] -> $b:tt $($tail:tt)*) => {range!(@hasLowerBound [$($lower)+ $b] -> $($tail)*)};
86    (@hasLowerBound [$($lower:tt)+] ->) => {$crate::ast::Range::Single($crate::as_expr!($($lower)+))};
87
88    // initial tokens
89    (.. $($a:tt)+) => {$crate::ast::Range::UnboundedL($crate::as_expr!($($a)+))};
90
91    ($a:tt $($tail:tt)*) => {range!(@hasLowerBound [$a] -> $($tail)*)};
92
93}
94
95// coorce a tt fragment into a expr fragment
96// https://lukaswirth.dev/tlborm/decl-macros/building-blocks/ast-coercion.html
97#[macro_export]
98#[doc(hidden)]
99macro_rules! as_expr {
100    ($e:expr) => {
101        $e
102    };
103}