specmc_protocol/
types.rs

1use specmc_base::{
2    ensure_tokens,
3    parse::{Identifier, Parse, ParseError},
4};
5
6use crate::base::{BaseType, FieldList};
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub enum Type {
10    BaseType(BaseType),
11    CustomType(Identifier),
12}
13impl Parse for Type {
14    fn parse(tokens: &mut Vec<String>) -> Result<Self, ParseError> {
15        if let Ok(base_type) = BaseType::parse(tokens) {
16            Ok(Type::BaseType(base_type))
17        } else {
18            Ok(Type::CustomType(Identifier::parse(tokens)?))
19        }
20    }
21}
22
23#[derive(Debug, Clone, PartialEq)]
24pub struct CustomType {
25    pub name: Identifier,
26    pub fields: FieldList,
27}
28impl Parse for CustomType {
29    fn parse(tokens: &mut Vec<String>) -> Result<Self, ParseError> {
30        ensure_tokens!(tokens, "type");
31        let name: Identifier = Identifier::parse(tokens)?;
32        ensure_tokens!(tokens, "{");
33        let fields: FieldList = FieldList::parse(tokens)?;
34        ensure_tokens!(tokens, "}");
35
36        Ok(CustomType { name, fields })
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use std::collections::HashSet;
43
44    use specmc_base::tokenize;
45
46    use crate::{
47        base::{Field, IntegerType},
48        test_parse,
49    };
50
51    use super::*;
52
53    #[test]
54    fn test_type() {
55        let mut tokens: Vec<String> = tokenize!("bool i32 TestType");
56
57        test_parse!(tokens, Type, Ok(Type::BaseType(BaseType::Bool)));
58        test_parse!(
59            tokens,
60            Type,
61            Ok(Type::BaseType(BaseType::Integer(IntegerType::I32)))
62        );
63        test_parse!(
64            tokens,
65            Type,
66            Ok(Type::CustomType(Identifier("TestType".to_string())))
67        );
68
69        assert!(tokens.is_empty());
70        test_parse!(tokens, Type, Err(ParseError::EndOfFile));
71    }
72
73    #[test]
74    fn test_custom_type() {
75        let mut tokens: Vec<String> = tokenize!(
76            "
77            type TestType {
78                i32 a
79                bool b
80                if (b) {
81                    i32 c
82                }
83            }
84            "
85        );
86
87        test_parse!(
88            tokens,
89            CustomType,
90            Ok(CustomType {
91                name: Identifier("TestType".to_string()),
92                fields: FieldList(vec![
93                    Field {
94                        ty: Type::BaseType(BaseType::Integer(IntegerType::I32)),
95                        name: Identifier("a".to_string()),
96                        value: None,
97                        conditions: HashSet::new(),
98                    },
99                    Field {
100                        ty: Type::BaseType(BaseType::Bool),
101                        name: Identifier("b".to_string()),
102                        value: None,
103                        conditions: HashSet::new(),
104                    },
105                    Field {
106                        ty: Type::BaseType(BaseType::Integer(IntegerType::I32)),
107                        name: Identifier("c".to_string()),
108                        value: None,
109                        conditions: HashSet::from_iter(vec!["b".to_string()]),
110                    },
111                ])
112            })
113        );
114
115        assert!(tokens.is_empty());
116        test_parse!(tokens, CustomType, Err(ParseError::EndOfFile));
117    }
118}