flatzinc 0.3.21

A FlatZinc parser
Documentation
use winnow::{
    error::{FromExternalError, ParserError},
    PResult, Parser,
};

use crate::{
    basic_types::BasicType,
    comments::space_or_comment0,
    expressions::{
        array_of_bool_literal, array_of_float_literal, array_of_int_literal, array_of_set_literal,
        set_literal, SetLiteral,
    },
    parameters::types::{par_type, BasicParType, ParType},
    primitive_literals::{bool_literal, float_literal, int_literal, var_par_identifier, IndexSet},
};

#[derive(PartialEq, Clone, Debug)]
pub enum ParDeclItem {
    Bool {
        id: String,
        bool: bool,
    },
    Int {
        id: String,
        int: i128,
    },
    Float {
        id: String,
        float: f64,
    },
    SetOfInt {
        id: String,
        set_literal: SetLiteral,
    },
    ArrayOfBool {
        ix: IndexSet,
        id: String,
        v: Vec<bool>,
    },
    ArrayOfInt {
        ix: IndexSet,
        id: String,
        v: Vec<i128>,
    },
    ArrayOfFloat {
        ix: IndexSet,
        id: String,
        v: Vec<f64>,
    },
    ArrayOfSet {
        ix: IndexSet,
        id: String,
        v: Vec<SetLiteral>,
    },
}

pub fn par_decl_item<'a, E>(input: &mut &'a str) -> PResult<ParDeclItem, E>
where
    E: ParserError<&'a str>
        + FromExternalError<&'a str, std::num::ParseIntError>
        + FromExternalError<&'a str, std::num::ParseFloatError>,
{
    space_or_comment0(input)?;
    let ptype = par_type(input)?;
    space_or_comment0(input)?;
    ':'.parse_next(input)?;
    space_or_comment0(input)?;
    let id = var_par_identifier(input)?;
    space_or_comment0(input)?;
    '='.parse_next(input)?;
    space_or_comment0(input)?;
    match ptype {
        ParType::BasicParType(bpt) => match bpt {
            BasicParType::BasicType(bt) => match bt {
                BasicType::Bool => {
                    let bool = bool_literal(input)?;
                    space_or_comment0(input)?;
                    ';'.parse_next(input)?;
                    space_or_comment0(input)?;
                    Ok(ParDeclItem::Bool { id, bool })
                }
                BasicType::Int => {
                    let int = int_literal(input)?;
                    space_or_comment0(input)?;
                    ';'.parse_next(input)?;
                    space_or_comment0(input)?;
                    Ok(ParDeclItem::Int { id, int })
                }
                BasicType::Float => {
                    let float = float_literal(input)?;
                    space_or_comment0(input)?;
                    ';'.parse_next(input)?;
                    space_or_comment0(input)?;
                    Ok(ParDeclItem::Float { id, float })
                }
            },
            BasicParType::SetOfInt => {
                let set_literal = set_literal(input)?;
                space_or_comment0(input)?;
                ';'.parse_next(input)?;
                space_or_comment0(input)?;
                Ok(ParDeclItem::SetOfInt { id, set_literal })
            }
        },
        ParType::Array { ix, par_type } => match par_type {
            BasicParType::BasicType(bt) => match bt {
                BasicType::Bool => {
                    let v = array_of_bool_literal(input)?;
                    space_or_comment0(input)?;
                    ';'.parse_next(input)?;
                    space_or_comment0(input)?;
                    Ok(ParDeclItem::ArrayOfBool { ix, id, v })
                }
                BasicType::Int => {
                    let v = array_of_int_literal(input)?;
                    space_or_comment0(input)?;
                    ';'.parse_next(input)?;
                    space_or_comment0(input)?;
                    Ok(ParDeclItem::ArrayOfInt { ix, id, v })
                }
                BasicType::Float => {
                    let v = array_of_float_literal(input)?;
                    space_or_comment0(input)?;
                    ';'.parse_next(input)?;
                    space_or_comment0(input)?;
                    Ok(ParDeclItem::ArrayOfFloat { ix, id, v })
                }
            },
            BasicParType::SetOfInt => {
                let v = array_of_set_literal(input)?;
                space_or_comment0(input)?;
                ';'.parse_next(input)?;
                space_or_comment0(input)?;
                Ok(ParDeclItem::ArrayOfSet { ix, id, v })
            }
        },
    }
}
#[test]
fn test_par_decl_item_1() {
    use crate::IndexSet;
    use winnow::error::ContextError;
    let mut input = "array [1..3] of  float: X_139 = [1.0,1.0,1.0];";
    assert_eq!(
        par_decl_item::<ContextError>(&mut input),
        Ok(ParDeclItem::ArrayOfFloat {
            ix: IndexSet(3),
            id: "X_139".to_string(),
            v: vec![1.0, 1.0, 1.0]
        })
    );
}
#[test]
#[should_panic]
fn test_par_decl_item_2() {
    use winnow::error::ContextError;
    let mut input = "bool : b2 = b1;";
    par_decl_item::<ContextError>(&mut input).unwrap();
}
#[test]
fn test_par_decl_item_3() {
    use crate::IndexSet;
    use crate::SetLiteral;
    use winnow::error::ContextError;
    let mut input = "array [1..3] of set of int : h = [{42,17},1..5,{}];";
    assert_eq!(
        par_decl_item::<ContextError>(&mut input),
        Ok(ParDeclItem::ArrayOfSet {
            ix: IndexSet(3),
            id: "h".to_string(),
            v: vec![
                SetLiteral::SetInts(vec![42, 17]),
                SetLiteral::IntRange(1, 5),
                SetLiteral::SetInts(vec![])
            ]
        })
    );
}