tiger_lib/block/
blockitem.rs

1use crate::block::{BV, Block, Comparator, Eq::*, Field};
2use crate::report::{ErrorKey, err};
3use crate::token::Token;
4
5#[derive(Debug, Clone)]
6pub enum BlockItem {
7    Value(Token),
8    Block(Block),
9    Field(Field),
10}
11
12impl BlockItem {
13    pub fn expect_field(&self) -> Option<&Field> {
14        if let BlockItem::Field(field) = self {
15            Some(field)
16        } else {
17            let msg = format!("unexpected {}", self.describe());
18            err(ErrorKey::Structure).msg(msg).info("Did you forget an = ?").loc(self).push();
19            None
20        }
21    }
22
23    pub fn expect_into_field(self) -> Option<Field> {
24        if let BlockItem::Field(field) = self {
25            Some(field)
26        } else {
27            let msg = format!("unexpected {}", self.describe());
28            err(ErrorKey::Structure).msg(msg).info("Did you forget an = ?").loc(self).push();
29            None
30        }
31    }
32
33    pub fn get_field(&self) -> Option<&Field> {
34        if let BlockItem::Field(field) = self { Some(field) } else { None }
35    }
36
37    #[allow(dead_code)]
38    pub fn is_field(&self) -> bool {
39        matches!(self, BlockItem::Field(_))
40    }
41
42    pub fn get_value(&self) -> Option<&Token> {
43        if let BlockItem::Value(token) = self { Some(token) } else { None }
44    }
45
46    pub fn expect_value(&self) -> Option<&Token> {
47        if let BlockItem::Value(token) = self {
48            Some(token)
49        } else {
50            let msg = format!("expected value, found {}", self.describe());
51            err(ErrorKey::Structure).msg(msg).loc(self).push();
52            None
53        }
54    }
55
56    pub fn expect_into_value(self) -> Option<Token> {
57        if let BlockItem::Value(token) = self {
58            Some(token)
59        } else {
60            let msg = format!("expected value, found {}", self.describe());
61            err(ErrorKey::Structure).msg(msg).loc(self).push();
62            None
63        }
64    }
65
66    #[allow(dead_code)] // It's here for symmetry
67    pub fn get_block(&self) -> Option<&Block> {
68        if let BlockItem::Block(block) = self { Some(block) } else { None }
69    }
70
71    pub fn expect_block(&self) -> Option<&Block> {
72        if let BlockItem::Block(block) = self {
73            Some(block)
74        } else {
75            let msg = format!("expected block, found {}", self.describe());
76            err(ErrorKey::Structure).msg(msg).loc(self).push();
77            None
78        }
79    }
80
81    pub fn expect_into_block(self) -> Option<Block> {
82        if let BlockItem::Block(block) = self {
83            Some(block)
84        } else {
85            let msg = format!("expected block, found {}", self.describe());
86            err(ErrorKey::Structure).msg(msg).loc(self).push();
87            None
88        }
89    }
90
91    pub fn get_definition(&self) -> Option<(&Token, &Block)> {
92        if let Some(field) = self.get_field() { field.get_definition() } else { None }
93    }
94
95    pub fn expect_into_definition(self) -> Option<(Token, Block)> {
96        if let Some(field) = self.expect_into_field() {
97            field.expect_into_definition()
98        } else {
99            None
100        }
101    }
102
103    pub fn expect_definition(&self) -> Option<(&Token, &Block)> {
104        if let Some(field) = self.expect_field() { field.expect_definition() } else { None }
105    }
106
107    pub fn expect_into_assignment(self) -> Option<(Token, Token)> {
108        if let Some(field) = self.expect_into_field() {
109            field.expect_into_assignment()
110        } else {
111            None
112        }
113    }
114
115    pub fn expect_assignment(&self) -> Option<(&Token, &Token)> {
116        if let Some(field) = self.expect_field() {
117            #[allow(clippy::single_match_else)] // too complicated for a `let`
118            match field {
119                Field(key, Comparator::Equals(Single | Question), BV::Value(token)) => {
120                    return Some((key, token));
121                }
122                _ => {
123                    let msg = format!("expected assignment, found {}", field.describe());
124                    err(ErrorKey::Structure).msg(msg).loc(self).push();
125                }
126            }
127        }
128        None
129    }
130
131    pub fn get_assignment(&self) -> Option<(&Token, &Token)> {
132        #[allow(clippy::single_match_else)] // too complicated for a `let`
133        match self {
134            BlockItem::Field(Field(
135                key,
136                Comparator::Equals(Single | Question),
137                BV::Value(token),
138            )) => Some((key, token)),
139            _ => None,
140        }
141    }
142
143    pub fn describe(&self) -> &'static str {
144        match self {
145            BlockItem::Value(_) => "value",
146            BlockItem::Block(_) => "block",
147            BlockItem::Field(field) => field.describe(),
148        }
149    }
150
151    pub fn equivalent(&self, other: &Self) -> bool {
152        match self {
153            BlockItem::Value(token) => {
154                if let BlockItem::Value(t) = other {
155                    token == t
156                } else {
157                    false
158                }
159            }
160            BlockItem::Block(block) => {
161                if let BlockItem::Block(b) = other {
162                    block.equivalent(b)
163                } else {
164                    false
165                }
166            }
167            BlockItem::Field(field) => {
168                if let BlockItem::Field(f) = other {
169                    field.equivalent(f)
170                } else {
171                    false
172                }
173            }
174        }
175    }
176}