conjure_cp_core/lib.rs
1pub extern crate self as conjure_cp_core;
2
3pub use ast::Model;
4
5pub mod ast;
6pub mod bug;
7pub mod context;
8pub mod error;
9pub mod metadata;
10pub mod parse;
11pub mod representation;
12pub mod rule_engine;
13pub mod solver;
14pub mod stats;
15
16/// Creates a [`Domain::Int`](ast::Domain::Int).
17///
18/// # Examples
19/// ```
20/// use conjure_cp_core::{domain_int,range,ast::Domain};
21///
22/// let a = 2*10;
23/// assert_eq!(domain_int!(1..5,a+2,), Domain::Int(vec![range!(1..5),range!(a+2)]));
24/// assert_eq!(domain_int!(), Domain::Int(vec![]));
25/// ```
26#[macro_export]
27macro_rules! domain_int {
28 () => {$crate::ast::Domain::Int(vec![])};
29
30 // when parsing expressions, rust groups 1..2 into a single token tree, (1..2)
31 // however, we want it to be three seperate token trees [1,..,2] for parsing.
32 // use defile to turn it back into 3 token trees
33 ($($e:expr),+ $(,)?) => {::defile::defile! { $crate::ast::Domain::Int(vec![$($crate::range!(@$e)),+]) } };
34}
35
36/// Creates a [`Range`](ast::Range).
37///
38/// # Examples
39///
40/// ```
41/// use conjure_cp_core::{range,ast::Range};
42///
43/// let a = 2*10;
44/// assert_eq!(range!(..a),Range::UnboundedL(a));
45/// assert_eq!(range!(2*5..),Range::UnboundedR(10));
46/// assert_eq!(range!(..10),Range::UnboundedL(10));
47/// assert_eq!(range!(1..5),Range::Bounded(1,5));
48/// assert_eq!(range!(Some(10).unwrap()),Range::Single(10));
49/// ```
50#[macro_export]
51macro_rules! range {
52 // decl macros have no lookahead, hence this nonsense with pushdown automata.
53
54 // @hasLowerbound: have atleast one token of the lower bound on the stack
55 (@hasLowerBound [$($lower:tt)+] -> ..) => {$crate::ast::Range::UnboundedR($crate::as_expr!($($lower)+))};
56 (@hasLowerBound [$($lower:tt)+] -> .. $($tail:tt)+) => {$crate::ast::Range::Bounded($crate::as_expr!($($lower)+),$crate::as_expr!($($tail)+))};
57 (@hasLowerBound [$($lower:tt)+] -> $b:tt $($tail:tt)*) => {range!(@hasLowerBound [$($lower)+ $b] -> $($tail)*)};
58 (@hasLowerBound [$($lower:tt)+] ->) => {$crate::ast::Range::Single($crate::as_expr!($($lower)+))};
59
60 // initial tokens
61 (.. $($a:tt)+) => {$crate::ast::Range::UnboundedL($crate::as_expr!($($a)+))};
62
63 ($a:tt $($tail:tt)*) => {range!(@hasLowerBound [$a] -> $($tail)*)};
64
65}
66
67// coorce a tt fragment into a expr fragment
68// https://lukaswirth.dev/tlborm/decl-macros/building-blocks/ast-coercion.html
69#[macro_export]
70#[doc(hidden)]
71macro_rules! as_expr {
72 ($e:expr) => {
73 $e
74 };
75}