pddl/parsers/
typed_list.rs1use nom::character::complete::char;
4use nom::combinator::map;
5use nom::multi::many0;
6use nom::sequence::{preceded, tuple};
7
8use crate::parsers::{
9 parse_type, space_separated_list0, space_separated_list1, ws, ParseResult, Span,
10};
11use crate::types::{Typed, TypedList};
12
13pub fn typed_list<'a, F, O>(inner: F) -> impl FnMut(Span<'a>) -> ParseResult<'a, TypedList<O>>
49where
50 F: Clone + FnMut(Span<'a>) -> ParseResult<'a, O>,
51{
52 let implicitly_typed = map(inner.clone(), |o| Typed::new_object(o));
54 let implicitly_typed_list = space_separated_list0(implicitly_typed);
55
56 let explicitly_typed = map(
58 tuple((
59 space_separated_list1(inner.clone()),
60 preceded(ws(char('-')), parse_type),
61 )),
62 |(os, t)| {
63 os.into_iter()
64 .map(move |o| Typed::new(o, t.clone()))
65 .collect::<Vec<_>>()
66 },
67 );
68
69 let typed_list_choice = tuple((
70 map(many0(explicitly_typed), |vec| {
71 vec.into_iter().flatten().collect::<Vec<_>>()
72 }),
73 implicitly_typed_list,
74 ));
75
76 map(typed_list_choice, |(mut explicit, mut implicit)| {
77 explicit.append(&mut implicit);
78 TypedList::new(explicit)
79 })
80}
81
82#[cfg(test)]
83mod tests {
84 use crate::parsers::preamble::*;
85 use crate::parsers::{parse_name, typed_list};
86 use crate::{Name, ToTyped, Type, TypedList};
87
88 #[test]
89 fn test_parse() {
90 assert!(
92 typed_list(parse_name)(Span::new("abc"))
93 .is_value(TypedList::from_iter([
94 Name::new("abc").to_typed(Type::OBJECT)
95 ]))
96 );
97
98 assert!(
100 typed_list(parse_name)(Span::new("abc def\nghi")).is_value(TypedList::from_iter([
101 Name::new("abc").to_typed(Type::OBJECT),
102 Name::new("def").to_typed(Type::OBJECT),
103 Name::new("ghi").to_typed(Type::OBJECT)
104 ]))
105 );
106
107 assert!(
109 typed_list(parse_name)(Span::new("abc def - word kitchen - room")).is_value(
110 TypedList::from_iter([
111 Name::new("abc").to_typed("word"),
112 Name::new("def").to_typed("word"),
113 Name::new("kitchen").to_typed("room"),
114 ])
115 )
116 );
117
118 assert!(typed_list(parse_name)(Span::new(
120 "abc def - word\ngeorgia - (either state country)\nuvw xyz"
121 ))
122 .is_value(TypedList::from_iter([
123 Name::new("abc").to_typed("word"),
124 Name::new("def").to_typed("word"),
125 Name::new("georgia").to_typed_either(["state", "country"]),
126 Name::new("uvw").to_typed(Type::OBJECT),
127 Name::new("xyz").to_typed(Type::OBJECT)
128 ])));
129 }
130}