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}