use winnow::{
combinator::{alt, cut_err},
error::{AddContext, FromExternalError, ParserError, StrContext},
PResult, Parser,
};
use crate::{
comments::{space_or_comment0, space_or_comment1},
expressions::{
annotations, bool_expr, float_expr, int_expr, set_expr, Annotations, BoolExpr, FloatExpr,
IntExpr, SetExpr,
},
};
#[derive(PartialEq, Clone, Debug)]
pub struct SolveItem {
pub goal: Goal,
pub annotations: Annotations,
}
pub fn solve_item<'a, E>(input: &mut &'a str) -> PResult<SolveItem, E>
where
E: ParserError<&'a str>
+ FromExternalError<&'a str, std::num::ParseIntError>
+ FromExternalError<&'a str, std::num::ParseFloatError>
+ AddContext<&'a str, StrContext>,
{
space_or_comment0(input)?;
"solve".parse_next(input)?;
cut_err(solve_item_tail.context(StrContext::Label("Error while parsing solve statement")))
.parse_next(input)
}
pub fn solve_item_tail<'a, E>(input: &mut &'a str) -> PResult<SolveItem, E>
where
E: ParserError<&'a str>
+ FromExternalError<&'a str, std::num::ParseIntError>
+ FromExternalError<&'a str, std::num::ParseFloatError>,
{
space_or_comment1(input)?;
let annotations = annotations(input)?;
space_or_comment0(input)?;
let goal = alt((
satisfy,
optimize_bool,
optimize_int,
optimize_float,
optimize_set,
))
.parse_next(input)?;
space_or_comment0(input)?;
';'.parse_next(input)?;
space_or_comment0(input)?;
Ok(SolveItem { goal, annotations })
}
#[test]
fn test_solve_item() {
use crate::solve_items::{Goal, OptimizationType};
use crate::{AnnExpr, Annotation, Expr};
use winnow::error::ContextError;
let mut input = "solve :: int_search(X_59,input_order,indomain_min,complete) minimize X_24;";
assert_eq!(
solve_item::<ContextError>(&mut input),
Ok(SolveItem {
goal: Goal::OptimizeBool(
OptimizationType::Minimize,
BoolExpr::VarParIdentifier("X_24".to_string())
),
annotations: vec![Annotation {
id: "int_search".to_string(),
expressions: vec![
AnnExpr::Expr(Expr::VarParIdentifier("X_59".to_string())),
AnnExpr::Expr(Expr::VarParIdentifier("input_order".to_string())),
AnnExpr::Expr(Expr::VarParIdentifier("indomain_min".to_string())),
AnnExpr::Expr(Expr::VarParIdentifier("complete".to_string()))
]
}]
})
);
}
#[derive(PartialEq, Clone, Debug)]
pub enum Goal {
Satisfy,
OptimizeBool(OptimizationType, BoolExpr),
OptimizeInt(OptimizationType, IntExpr),
OptimizeFloat(OptimizationType, FloatExpr),
OptimizeSet(OptimizationType, SetExpr),
}
#[derive(PartialEq, Clone, Debug)]
pub enum OptimizationType {
Minimize,
Maximize,
}
pub fn satisfy<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<Goal, E> {
"satisfy".parse_next(input)?;
Ok(Goal::Satisfy)
}
fn opt_type<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<OptimizationType, E> {
alt((minimize, maximize)).parse_next(input)
}
fn minimize<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<OptimizationType, E> {
"minimize".parse_next(input)?;
Ok(OptimizationType::Minimize)
}
fn maximize<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<OptimizationType, E> {
"maximize".parse_next(input)?;
Ok(OptimizationType::Maximize)
}
pub fn optimize_bool<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<Goal, E> {
let opt_type = opt_type(input)?;
space_or_comment1(input)?;
let be = bool_expr(input)?;
Ok(Goal::OptimizeBool(opt_type, be))
}
pub fn optimize_int<'a, E>(input: &mut &'a str) -> PResult<Goal, E>
where
E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
{
let opt_type = opt_type(input)?;
space_or_comment1(input)?;
let be = int_expr(input)?;
Ok(Goal::OptimizeInt(opt_type, be))
}
pub fn optimize_float<'a, E>(input: &mut &'a str) -> PResult<Goal, E>
where
E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseFloatError>,
{
let opt_type = opt_type(input)?;
space_or_comment1(input)?;
let be = float_expr(input)?;
Ok(Goal::OptimizeFloat(opt_type, be))
}
pub fn optimize_set<'a, E>(input: &mut &'a str) -> PResult<Goal, E>
where
E: ParserError<&'a str>
+ FromExternalError<&'a str, std::num::ParseIntError>
+ FromExternalError<&'a str, std::num::ParseFloatError>,
{
let opt_type = opt_type(input)?;
space_or_comment1(input)?;
let be = set_expr(input)?;
Ok(Goal::OptimizeSet(opt_type, be))
}