flatzinc/
primitive_literals.rs

1use winnow::{
2    combinator::{alt, opt},
3    error::{ErrorKind, FromExternalError, ParserError},
4    token::{literal, one_of, take_while},
5    PResult, Parser,
6};
7
8use crate::comments::space_or_comment0;
9
10pub fn identifier<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<String, E> {
11    let first = one_of([
12        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
13        's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
14        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
15    ])
16    .parse_next(input)?;
17    let rest = take_while(0.., is_identifier_rest).parse_next(input)?;
18    let combine = format!("{}{}", first, rest);
19    // check for reserved key words
20    if is_reserved_key_word(&combine) {
21        Err(winnow::error::ErrMode::Cut(ParserError::from_error_kind(
22            input,
23            ErrorKind::Token,
24        )))
25    } else {
26        Ok(combine)
27    }
28}
29
30pub fn var_par_identifier<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<String, E> {
31    let first = one_of([
32        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
33        's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
34        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_',
35    ])
36    .parse_next(input)?;
37
38    let rest = take_while(0.., is_identifier_rest).parse_next(input)?;
39    let combine = format!("{}{}", first, rest);
40    // check for reserved key words
41    if is_reserved_key_word(&combine) {
42        Err(winnow::error::ErrMode::Backtrack(
43            ParserError::from_error_kind(input, ErrorKind::Token),
44        ))
45    } else {
46        Ok(combine)
47    }
48}
49
50fn is_reserved_key_word(string: &str) -> bool {
51    matches!(
52        string,
53        "annotation"
54            | "any"
55            | "array"
56            | "bool"
57            | "case"
58            | "constraint"
59            | "diff"
60            | "div"
61            | "else"
62            | "elseif"
63            | "endif"
64            | "enum"
65            | "false"
66            | "float"
67            | "function"
68            | "if"
69            | "in"
70            | "include"
71            | "int"
72            | "intersect"
73            | "let"
74            | "list"
75            | "maximize"
76            | "minimize"
77            | "mod"
78            | "not"
79            | "of"
80            | "satisfy"
81            | "subset"
82            | "superset"
83            | "output"
84            | "par"
85            | "predicate"
86            | "record"
87            | "set"
88            | "solve"
89            | "string"
90            | "symdiff"
91            | "test"
92            | "then"
93            | "true"
94            | "tuple"
95            | "union"
96            | "type"
97            | "var"
98            | "where"
99            | "xor"
100    )
101}
102
103fn is_identifier_rest(c: char) -> bool {
104    matches!(
105        c,
106        'a' | 'b'
107            | 'c'
108            | 'd'
109            | 'e'
110            | 'f'
111            | 'g'
112            | 'h'
113            | 'i'
114            | 'j'
115            | 'k'
116            | 'l'
117            | 'm'
118            | 'n'
119            | 'o'
120            | 'p'
121            | 'q'
122            | 'r'
123            | 's'
124            | 't'
125            | 'u'
126            | 'v'
127            | 'w'
128            | 'x'
129            | 'y'
130            | 'z'
131            | 'A'
132            | 'B'
133            | 'C'
134            | 'D'
135            | 'E'
136            | 'F'
137            | 'G'
138            | 'H'
139            | 'I'
140            | 'J'
141            | 'K'
142            | 'L'
143            | 'M'
144            | 'N'
145            | 'O'
146            | 'P'
147            | 'Q'
148            | 'R'
149            | 'S'
150            | 'T'
151            | 'U'
152            | 'V'
153            | 'W'
154            | 'X'
155            | 'Y'
156            | 'Z'
157            | '_'
158            | '0'
159            | '1'
160            | '2'
161            | '3'
162            | '4'
163            | '5'
164            | '6'
165            | '7'
166            | '8'
167            | '9'
168    )
169}
170
171pub fn bool_literal<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<bool, E> {
172    alt((literal("true").value(true), literal("false").value(false))).parse_next(input)
173}
174
175pub fn int_literal<'a, E>(input: &mut &'a str) -> PResult<i128, E>
176where
177    E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
178{
179    alt((decimal, hexadecimal, octal)).parse_next(input)
180}
181#[test]
182fn test_int_literal() {
183    use winnow::error::ContextError;
184    let mut input = "1";
185    assert_eq!(int_literal::<ContextError>(&mut input), Ok(1));
186}
187
188fn decimal<'a, E>(input: &mut &'a str) -> PResult<i128, E>
189where
190    E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
191{
192    let negation = opt('-').parse_next(input)?;
193    let int = take_while(1.., is_dec_digit)
194        .parse_next(input)?
195        .parse::<i128>()
196        .map_err(|e| winnow::error::ErrMode::from_external_error(input, ErrorKind::Verify, e))?;
197
198    if negation.is_some() {
199        Ok(-int)
200    } else {
201        Ok(int)
202    }
203}
204#[test]
205fn test_decimal() {
206    use winnow::error::ContextError;
207    let mut input = "170141183460469231731687303715884105727";
208    assert_eq!(
209        decimal::<ContextError>(&mut input),
210        Ok(170141183460469231731687303715884105727)
211    );
212}
213#[test]
214fn test_decimal2() {
215    use winnow::error::ContextError;
216    let mut input = "-170141183460469231731687303715884105727";
217    assert_eq!(
218        decimal::<ContextError>(&mut input),
219        Ok(-170141183460469231731687303715884105727)
220    );
221}
222#[test]
223fn test_decimal3() {
224    use winnow::error::ContextError;
225    let mut input = "170141183460469231731687303715884105728";
226    //Should fail because of overflow
227    assert!(decimal::<ContextError>(&mut input).is_err());
228}
229
230fn hexadecimal<'a, E>(input: &mut &'a str) -> PResult<i128, E>
231where
232    E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
233{
234    let negation = opt('-').parse_next(input)?;
235    "0x".parse_next(input)?;
236    let int = take_while(1.., is_hex_digit).parse_next(input)?;
237    let int = i128::from_str_radix(int, 16)
238        .map_err(|e| winnow::error::ErrMode::from_external_error(input, ErrorKind::Verify, e))?;
239
240    if negation.is_some() {
241        Ok(-int)
242    } else {
243        Ok(int)
244    }
245}
246#[test]
247fn test_hex() {
248    use winnow::error::ContextError;
249    let mut input = "-0x2f";
250    assert_eq!(hexadecimal::<ContextError>(&mut input), Ok(-47));
251}
252
253fn octal<'a, E>(input: &mut &'a str) -> PResult<i128, E>
254where
255    E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
256{
257    let negation = opt('-').parse_next(input)?;
258    "0o".parse_next(input)?;
259    let int = take_while(1.., is_oct_digit).parse_next(input)?;
260    let int = i128::from_str_radix(int, 8)
261        .map_err(|e| winnow::error::ErrMode::from_external_error(input, ErrorKind::Verify, e))?;
262    if negation.is_some() {
263        Ok(-int)
264    } else {
265        Ok(int)
266    }
267}
268#[test]
269fn test_oct() {
270    use winnow::error::ContextError;
271    let mut input = "0o200000000000000000000000000000000001";
272    assert_eq!(
273        octal::<ContextError>(&mut input),
274        Ok(81129638414606681695789005144065)
275    );
276}
277
278fn is_hex_digit(c: char) -> bool {
279    c.is_ascii_hexdigit()
280}
281
282fn is_oct_digit(c: char) -> bool {
283    c.is_digit(8)
284}
285
286fn is_dec_digit(c: char) -> bool {
287    c.is_ascii_digit()
288}
289
290pub fn float_literal<'a, E>(input: &mut &'a str) -> PResult<f64, E>
291where
292    E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseFloatError>,
293{
294    fz_float(input)
295}
296#[test]
297fn test_float_literal() {
298    use winnow::error::ContextError;
299    //TODO should return error
300    // float_literal::<ContextError>("5")
301    let mut input = "023.21";
302    assert_eq!(float_literal::<ContextError>(&mut input), Ok(023.21));
303    let mut input = "0023.21E-098";
304    assert_eq!(float_literal::<ContextError>(&mut input), Ok(0023.21E-098));
305    let mut input = "0023.21e+098";
306    assert_eq!(float_literal::<ContextError>(&mut input), Ok(0023.21e+098));
307    let mut input = "002e+098";
308    assert_eq!(float_literal::<ContextError>(&mut input), Ok(002e+098));
309    let mut input = "0.21";
310    assert_eq!(float_literal::<ContextError>(&mut input), Ok(0.21));
311    let mut input = "1.0,";
312    assert_eq!(float_literal::<ContextError>(&mut input), Ok(1.0));
313
314    let mut input = "0.000000000000000000000000000000007609999999000000000000000000000000760999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999900000000000000000000000764DD4DDDDDDDDD%
315    ";
316    assert_eq!(
317        float_literal::<ContextError>(&mut input),
318        Ok(0.000000000000000000000000000000007609999999)
319    );
320}
321
322fn fz_float<'a, E>(input: &mut &'a str) -> PResult<f64, E>
323where
324    E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseFloatError>,
325{
326    let mut fl = alt((fz_float1, fz_float2)).parse_next(input)?;
327    winnow::ascii::float.parse_next(&mut fl)
328}
329
330fn fz_float1<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<&'a str, E> {
331    let sign = opt('-');
332
333    let pre = take_while(1.., is_dec_digit);
334    let post = take_while(1.., is_dec_digit);
335    let rest = opt(bpart);
336
337    (sign, pre, '.', post, rest).take().parse_next(input)
338}
339
340fn fz_float2<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<&'a str, E> {
341    let sign = opt('-');
342    let digits = take_while(1.., is_dec_digit);
343    let e = alt(('e', 'E'));
344    let sign2 = opt(alt(("-", "+")));
345    let digits2 = take_while(1.., is_dec_digit);
346    (sign, digits, e, sign2, digits2).take().parse_next(input)
347}
348
349fn bpart<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<String, E> {
350    let e = alt(('e', 'E')).parse_next(input)?;
351    let sign = opt(alt(("-", "+"))).parse_next(input)?;
352    let digits = take_while(1.., is_dec_digit).parse_next(input)?;
353    if let Some(sign) = sign {
354        Ok(format!("{}{}{}", e, sign, digits))
355    } else {
356        Ok(format!("{}{}", e, digits))
357    }
358}
359
360#[derive(PartialEq, Clone, Debug)]
361pub struct IndexSet(pub i128);
362
363pub fn index_set<'a, E>(input: &mut &'a str) -> PResult<IndexSet, E>
364where
365    E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
366{
367    '1'.parse_next(input)?;
368    space_or_comment0(input)?;
369    "..".parse_next(input)?;
370    space_or_comment0(input)?;
371    let int = int_literal.parse_next(input)?;
372    Ok(IndexSet(int))
373}