openfga_dsl_parser/parser/
mod.rs

1use std::fmt::Display;
2
3use crate::ast::{Alias, AliasKind, Document, Relation, Type};
4use crate::lexer::{
5    token::{Token, TokenKind},
6    Lexer,
7};
8
9/// Result type for the [Parser](crate::parser::Parser) type.
10pub type ParseResult<T> = Result<T, ParserError>;
11
12pub struct Parser {
13    lex: Lexer,
14    curr: Token,
15    peek: Token,
16}
17
18#[derive(Debug, PartialEq, Eq)]
19pub enum ParserError {
20    UnexpectedToken(TokenKind, TokenKind),
21    UnexpectedKeyword(TokenKind),
22    UnexpectedEOF,
23}
24
25impl Parser {
26    pub fn new(input: &str) -> Self {
27        let mut lex = Lexer::new(input);
28        let curr = lex.next_token();
29        let peek = lex.next_token();
30        Self { lex, curr, peek }
31    }
32
33    pub fn from_lexer(mut lex: Lexer) -> Self {
34        let curr = lex.next_token();
35        let peek = lex.next_token();
36        Self { lex, curr, peek }
37    }
38
39    pub fn parse_document(&mut self) -> ParseResult<Document> {
40        let mut types = Vec::new();
41        while self.curr.kind() != TokenKind::EOF {
42            if self.curr.kind() != TokenKind::Type {
43                return Err(ParserError::UnexpectedToken(
44                    TokenKind::Type,
45                    self.curr.kind(),
46                ));
47            }
48            let ty = self.parse_type()?;
49            types.push(ty);
50            self.next_token();
51        }
52        Ok(Document { types })
53    }
54
55    fn parse_type(&mut self) -> ParseResult<Type> {
56        self.expect_peek(TokenKind::Text)?;
57        let kind = self.curr.literal().to_string();
58        let mut relations = Vec::new();
59
60        if self.peek.kind() != TokenKind::EOF && self.peek.kind() != TokenKind::Type {
61            self.expect_peek(TokenKind::Relations)?;
62
63            while self.peek.kind() == TokenKind::Define {
64                self.next_token();
65                let rel = self.parse_relation()?;
66                relations.push(rel);
67            }
68        }
69
70        Ok(Type { kind, relations })
71    }
72
73    fn parse_relation(&mut self) -> ParseResult<Relation> {
74        self.expect_peek(TokenKind::Text)?;
75        let kind = self.curr.literal().to_string();
76        self.next_token();
77        if self.curr.kind() != TokenKind::As {
78            // NOTE this might be invalid syntax...
79            return Ok(Relation {
80                kind,
81                aliases: Vec::new(),
82            });
83        }
84
85        self.next_token();
86        let mut aliases = Vec::new();
87        let first_alias = self.parse_alias()?;
88        aliases.push(first_alias);
89        while self.peek.kind() == TokenKind::Or || self.peek.kind() == TokenKind::But {
90            let alias = if self.peek.kind() == TokenKind::But {
91                self.next_token();
92                self.parse_but_not()?
93            } else {
94                self.next_token();
95                self.next_token();
96                self.parse_alias()?
97            };
98            aliases.push(alias)
99        }
100
101        Ok(Relation { kind, aliases })
102    }
103
104    fn parse_alias(&mut self) -> ParseResult<Alias> {
105        let kind = match self.curr.kind() {
106            TokenKind::This => AliasKind::This,
107            TokenKind::Text => AliasKind::Named(self.curr.literal().to_string()),
108            TokenKind::EOF => return Err(ParserError::UnexpectedEOF),
109            _ => return Err(ParserError::UnexpectedKeyword(self.curr.kind())),
110        };
111
112        let parent = self.parse_alias_parent()?;
113        Ok(Alias { kind, parent })
114    }
115
116    fn parse_but_not(&mut self) -> ParseResult<Alias> {
117        self.expect_peek(TokenKind::Not)?;
118        self.expect_peek(TokenKind::Text)?;
119        let kind = AliasKind::Negative(self.curr.literal().to_string());
120        let parent = self.parse_alias_parent()?;
121
122        Ok(Alias { kind, parent })
123    }
124
125    fn parse_alias_parent(&mut self) -> ParseResult<Option<String>> {
126        if self.peek.kind() == TokenKind::From {
127            self.next_token();
128            self.expect_peek(TokenKind::Text)?;
129            let parent = Some(self.curr.literal().to_string());
130            Ok(parent)
131        } else {
132            Ok(None)
133        }
134    }
135
136    fn next_token(&mut self) {
137        let prev = std::mem::replace(&mut self.peek, self.lex.next_token());
138        self.curr = prev;
139    }
140
141    fn expect_peek(&mut self, expected: TokenKind) -> ParseResult<()> {
142        if self.peek.kind() == expected {
143            self.next_token();
144            Ok(())
145        } else {
146            Err(ParserError::UnexpectedToken(expected, self.peek.kind()))
147        }
148    }
149}
150
151impl Display for ParserError {
152    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153        use ParserError::*;
154        match self {
155            UnexpectedToken(exp, got) => {
156                write!(f, "Unexpected token: expected {exp:?}, got {got:?}")
157            }
158            UnexpectedKeyword(got) => write!(f, "Unexpected keyword: {got:?}"),
159            UnexpectedEOF => write!(f, "received an unexpected EOF"),
160        }
161    }
162}
163
164#[cfg(test)]
165mod tests {
166    use super::*;
167
168    #[test]
169    fn can_parse_types() {
170        let i = "type document
171type org";
172        let lex = Lexer::new(i);
173        let mut parser = Parser::from_lexer(lex);
174        let exp = Document {
175            types: vec![
176                Type {
177                    kind: "document".into(),
178                    relations: Vec::new(),
179                },
180                Type {
181                    kind: "org".into(),
182                    relations: Vec::new(),
183                },
184            ],
185        };
186        assert_eq!(Ok(exp), parser.parse_document());
187    }
188
189    #[test]
190    fn can_parse_relation_self() {
191        let i = "define write as self";
192        let exp = Relation {
193            kind: "write".into(),
194            aliases: vec![Alias {
195                kind: AliasKind::This,
196                parent: None,
197            }],
198        };
199
200        let lex = Lexer::new(i);
201        let mut parser = Parser::from_lexer(lex);
202        assert_eq!(Ok(exp), parser.parse_relation());
203    }
204
205    #[test]
206    fn can_parse_but_not_alias() {
207        let i = "define write as self but not owner from parent";
208        let exp = Relation {
209            kind: "write".into(),
210            aliases: vec![
211                Alias {
212                    kind: AliasKind::This,
213                    parent: None,
214                },
215                Alias {
216                    kind: AliasKind::Negative("owner".into()),
217                    parent: Some("parent".into()),
218                },
219            ],
220        };
221
222        let lex = Lexer::new(i);
223        let mut parser = Parser::from_lexer(lex);
224        assert_eq!(Ok(exp), parser.parse_relation());
225    }
226
227    #[test]
228    fn error_eof_missing_relation_type() {
229        let i = "define write as";
230        let exp = Err(ParserError::UnexpectedEOF);
231
232        let lex = Lexer::new(i);
233        let mut parser = Parser::from_lexer(lex);
234        assert_eq!(exp, parser.parse_relation());
235    }
236
237    #[test]
238    fn error_expected_keyword_relation_type() {
239        let i = "define write as type";
240        let exp = Err(ParserError::UnexpectedKeyword(TokenKind::Type));
241
242        let lex = Lexer::new(i);
243        let mut parser = Parser::from_lexer(lex);
244        assert_eq!(exp, parser.parse_relation());
245    }
246
247    #[test]
248    fn can_parse_relation_multiple_alias() {
249        let i = "define write as self or owner or thing";
250        let exp = Relation {
251            kind: "write".into(),
252            aliases: vec![
253                Alias {
254                    kind: AliasKind::This,
255                    parent: None,
256                },
257                Alias {
258                    kind: AliasKind::Named("owner".into()),
259                    parent: None,
260                },
261                Alias {
262                    kind: AliasKind::Named("thing".into()),
263                    parent: None,
264                },
265            ],
266        };
267
268        let lex = Lexer::new(i);
269        let mut parser = Parser::from_lexer(lex);
270        assert_eq!(Ok(exp), parser.parse_relation());
271    }
272
273    #[test]
274    fn can_parse_relation_parent_alias() {
275        let i = "define write as self or owner from parent or thing";
276        let exp = Relation {
277            kind: "write".into(),
278            aliases: vec![
279                Alias {
280                    kind: AliasKind::This,
281                    parent: None,
282                },
283                Alias {
284                    kind: AliasKind::Named("owner".into()),
285                    parent: Some("parent".into()),
286                },
287                Alias {
288                    kind: AliasKind::Named("thing".into()),
289                    parent: None,
290                },
291            ],
292        };
293
294        let lex = Lexer::new(i);
295        let mut parser = Parser::from_lexer(lex);
296        assert_eq!(Ok(exp), parser.parse_relation());
297    }
298
299    #[test]
300    fn can_parse_doc() {
301        let i = "type organization
302  relations
303    define member as self
304type document
305  relations
306    define owner as self
307    define can_share as owner or editor or owner from parent";
308        let exp = Document {
309            types: vec![
310                Type {
311                    kind: "organization".into(),
312                    relations: vec![Relation {
313                        kind: "member".into(),
314                        aliases: vec![Alias {
315                            kind: AliasKind::This,
316                            parent: None,
317                        }],
318                    }],
319                },
320                Type {
321                    kind: "document".into(),
322                    relations: vec![
323                        Relation {
324                            kind: "owner".into(),
325                            aliases: vec![Alias {
326                                kind: AliasKind::This,
327                                parent: None,
328                            }],
329                        },
330                        Relation {
331                            kind: "can_share".into(),
332                            aliases: vec![
333                                Alias {
334                                    kind: AliasKind::Named("owner".into()),
335                                    parent: None,
336                                },
337                                Alias {
338                                    kind: AliasKind::Named("editor".into()),
339                                    parent: None,
340                                },
341                                Alias {
342                                    kind: AliasKind::Named("owner".into()),
343                                    parent: Some("parent".into()),
344                                },
345                            ],
346                        },
347                    ],
348                },
349            ],
350        };
351
352        let lex = Lexer::new(i);
353        let mut parser = Parser::from_lexer(lex);
354        assert_eq!(Ok(exp), parser.parse_document());
355    }
356}