1use winnow::{
2 combinator::{alt, cut_err},
3 error::{AddContext, FromExternalError, ParserError, StrContext},
4 PResult, Parser,
5};
6
7use crate::{
8 comments::{space_or_comment0, space_or_comment1},
9 expressions::{
10 annotations, bool_expr, float_expr, int_expr, set_expr, Annotations, BoolExpr, FloatExpr,
11 IntExpr, SetExpr,
12 },
13};
14
15#[derive(PartialEq, Clone, Debug)]
16pub struct SolveItem {
17 pub goal: Goal,
18 pub annotations: Annotations,
19}
20
21pub fn solve_item<'a, E>(input: &mut &'a str) -> PResult<SolveItem, E>
22where
23 E: ParserError<&'a str>
24 + FromExternalError<&'a str, std::num::ParseIntError>
25 + FromExternalError<&'a str, std::num::ParseFloatError>
26 + AddContext<&'a str, StrContext>,
27{
28 space_or_comment0(input)?;
29 "solve".parse_next(input)?;
30 cut_err(solve_item_tail.context(StrContext::Label("Error while parsing solve statement")))
31 .parse_next(input)
32}
33pub fn solve_item_tail<'a, E>(input: &mut &'a str) -> PResult<SolveItem, E>
34where
35 E: ParserError<&'a str>
36 + FromExternalError<&'a str, std::num::ParseIntError>
37 + FromExternalError<&'a str, std::num::ParseFloatError>,
38{
39 space_or_comment1(input)?;
40 let annotations = annotations(input)?;
41 space_or_comment0(input)?;
42 let goal = alt((
43 satisfy,
44 optimize_bool,
45 optimize_int,
46 optimize_float,
47 optimize_set,
48 ))
49 .parse_next(input)?;
50 space_or_comment0(input)?;
51 ';'.parse_next(input)?;
52 space_or_comment0(input)?;
53 Ok(SolveItem { goal, annotations })
54}
55#[test]
56fn test_solve_item() {
57 use crate::solve_items::{Goal, OptimizationType};
58 use crate::{AnnExpr, Annotation, Expr};
59 use winnow::error::ContextError;
60 let mut input = "solve :: int_search(X_59,input_order,indomain_min,complete) minimize X_24;";
61 assert_eq!(
62 solve_item::<ContextError>(&mut input),
63 Ok(SolveItem {
64 goal: Goal::OptimizeBool(
65 OptimizationType::Minimize,
66 BoolExpr::VarParIdentifier("X_24".to_string())
67 ),
68 annotations: vec![Annotation {
69 id: "int_search".to_string(),
70 expressions: vec![
71 AnnExpr::Expr(Expr::VarParIdentifier("X_59".to_string())),
72 AnnExpr::Expr(Expr::VarParIdentifier("input_order".to_string())),
73 AnnExpr::Expr(Expr::VarParIdentifier("indomain_min".to_string())),
74 AnnExpr::Expr(Expr::VarParIdentifier("complete".to_string()))
75 ]
76 }]
77 })
78 );
79}
80
81#[derive(PartialEq, Clone, Debug)]
82pub enum Goal {
83 Satisfy,
84 OptimizeBool(OptimizationType, BoolExpr),
85 OptimizeInt(OptimizationType, IntExpr),
86 OptimizeFloat(OptimizationType, FloatExpr),
87 OptimizeSet(OptimizationType, SetExpr),
88}
89
90#[derive(PartialEq, Clone, Debug)]
91pub enum OptimizationType {
92 Minimize,
93 Maximize,
94}
95
96pub fn satisfy<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<Goal, E> {
97 "satisfy".parse_next(input)?;
98 Ok(Goal::Satisfy)
99}
100
101fn opt_type<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<OptimizationType, E> {
102 alt((minimize, maximize)).parse_next(input)
103}
104
105fn minimize<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<OptimizationType, E> {
106 "minimize".parse_next(input)?;
107 Ok(OptimizationType::Minimize)
108}
109
110fn maximize<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<OptimizationType, E> {
111 "maximize".parse_next(input)?;
112 Ok(OptimizationType::Maximize)
113}
114
115pub fn optimize_bool<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<Goal, E> {
116 let opt_type = opt_type(input)?;
117 space_or_comment1(input)?;
118 let be = bool_expr(input)?;
119 Ok(Goal::OptimizeBool(opt_type, be))
120}
121
122pub fn optimize_int<'a, E>(input: &mut &'a str) -> PResult<Goal, E>
123where
124 E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
125{
126 let opt_type = opt_type(input)?;
127 space_or_comment1(input)?;
128 let be = int_expr(input)?;
129 Ok(Goal::OptimizeInt(opt_type, be))
130}
131
132pub fn optimize_float<'a, E>(input: &mut &'a str) -> PResult<Goal, E>
133where
134 E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseFloatError>,
135{
136 let opt_type = opt_type(input)?;
137 space_or_comment1(input)?;
138 let be = float_expr(input)?;
139 Ok(Goal::OptimizeFloat(opt_type, be))
140}
141
142pub fn optimize_set<'a, E>(input: &mut &'a str) -> PResult<Goal, E>
143where
144 E: ParserError<&'a str>
145 + FromExternalError<&'a str, std::num::ParseIntError>
146 + FromExternalError<&'a str, std::num::ParseFloatError>,
147{
148 let opt_type = opt_type(input)?;
149 space_or_comment1(input)?;
150 let be = set_expr(input)?;
151 Ok(Goal::OptimizeSet(opt_type, be))
152}