Actually just three programming languages in a trenchcoat
1use super::*;
2use crate::{Parser, Spanned};
3use trilogy_scanner::{Token, TokenType};
4
5#[derive(Clone, Debug, Spanned)]
6pub enum Query {
7 Disjunction(Box<QueryDisjunction>),
8 Conjunction(Box<QueryConjunction>),
9 Implication(Box<QueryImplication>),
10 Alternative(Box<QueryAlternative>),
11 Direct(Box<DirectUnification>),
12 Element(Box<ElementUnification>),
13 Parenthesized(Box<ParenthesizedQuery>),
14 Lookup(Box<Lookup>),
15 Pass(Box<Token>),
16 End(Box<Token>),
17 Is(Box<BooleanQuery>),
18 Not(Box<NotQuery>),
19}
20
21#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
22pub(crate) enum Precedence {
23 None,
24 Disjunction,
25 Implication,
26 Conjunction,
27 Not,
28}
29
30impl Query {
31 fn parse_follow(
32 parser: &mut Parser,
33 precedence: Precedence,
34 lhs: Query,
35 ) -> SyntaxResult<Result<Self, Self>> {
36 use TokenType::*;
37 let token = parser.peek();
38 match token.token_type {
39 KwAnd if precedence <= Precedence::Conjunction => Ok(Ok(Self::Conjunction(Box::new(
40 QueryConjunction::parse(parser, lhs)?,
41 )))),
42 KwOr if precedence <= Precedence::Disjunction => Ok(Ok(Self::Disjunction(Box::new(
43 QueryDisjunction::parse(parser, lhs)?,
44 )))),
45 KwElse if precedence <= Precedence::Disjunction => Ok(Ok(Self::Alternative(Box::new(
46 QueryAlternative::parse(parser, lhs)?,
47 )))),
48 _ => Ok(Err(lhs)),
49 }
50 }
51
52 fn parse_prefix(parser: &mut Parser) -> SyntaxResult<Self> {
53 use TokenType::*;
54 let token = parser.peek();
55 match token.token_type {
56 KwIf => Ok(Self::Implication(Box::new(QueryImplication::parse(
57 parser,
58 )?))),
59 KwPass => Ok(Self::Pass(Box::new(parser.expect(KwPass).unwrap()))),
60 KwEnd => Ok(Self::End(Box::new(parser.expect(KwEnd).unwrap()))),
61 KwIs => Ok(Self::Is(Box::new(BooleanQuery::parse(parser)?))),
62 // Since a query may start with a pattern, and a pattern might be parenthesized,
63 // it's a bit trickier. We'll try to parse a query first, and if it fails, then
64 // it's a query that starts with a pattern. Once the pattern is parsed, we can
65 // check if the parentheses are ended there, or if there's an `=` or `in`, which
66 // would indicate that it's actually a query
67 OParen => match ParenthesizedQuery::parse_or_pattern(parser)? {
68 Ok(query) => Ok(Self::Parenthesized(Box::new(query))),
69 Err(pattern) => Self::unification(parser, pattern),
70 },
71 KwNot => Ok(Self::Not(Box::new(NotQuery::parse(parser)?))),
72 Identifier => {
73 // When it's an identifier it may be a lookup (which starts with any expression),
74 // or just a very long and complicated pattern. Parse it as an expression until
75 // it cannot be, then assume it is a pattern. If the expression completes
76 match Expression::parse_or_pattern(parser)? {
77 Ok(expr) if parser.check(OParen).is_ok() => {
78 // If the next character is `(`, then this is a lookup
79 Ok(Self::Lookup(Box::new(Lookup::parse_rest(parser, expr)?)))
80 }
81 Ok(expr) => {
82 // It was not a lookup, so let's try to convert it to a pattern
83 let pattern = expr.try_into().inspect_err(|err: &SyntaxError| {
84 parser.error(err.clone());
85 })?;
86 // It was not an expression, so is a pattern. It's not necessarily the whole pattern
87 // yet though, as we don't accept `and` and `or` in expressions as per the note in
88 // the expression parsing code.
89 let pattern =
90 Pattern::parse_suffix(parser, pattern::Precedence::None, pattern)?;
91 Self::unification(parser, pattern)
92 }
93 Err(pattern) => Self::unification(parser, pattern),
94 }
95 }
96 _ => {
97 // Patterns could look like a lot of things, we'll just let the
98 // pattern parser handle the errors
99 let pattern = Pattern::parse(parser)?;
100 Self::unification(parser, pattern)
101 }
102 }
103 }
104
105 fn unification(parser: &mut Parser, pattern: Pattern) -> SyntaxResult<Self> {
106 use TokenType::*;
107 let token = parser.peek();
108 match token.token_type {
109 OpEq => Ok(Self::Direct(Box::new(DirectUnification::parse(
110 parser, pattern,
111 )?))),
112 KwIn => Ok(Self::Element(Box::new(ElementUnification::parse(
113 parser, pattern,
114 )?))),
115 _ => {
116 let error = SyntaxError::new(token.span, "unexpected token in query");
117 parser.error(error.clone());
118 Err(error)
119 }
120 }
121 }
122
123 pub(crate) fn parse_precedence(
124 parser: &mut Parser,
125 precedence: Precedence,
126 ) -> SyntaxResult<Self> {
127 let lhs = Self::parse_prefix(parser)?;
128 Self::parse_precedence_followers(parser, precedence, lhs)
129 }
130
131 pub(crate) fn parse_precedence_followers(
132 parser: &mut Parser,
133 precedence: Precedence,
134 mut lhs: Query,
135 ) -> SyntaxResult<Self> {
136 loop {
137 match Self::parse_follow(parser, precedence, lhs)? {
138 Ok(updated) => lhs = updated,
139 Err(query) => return Ok(query),
140 }
141 }
142 }
143
144 pub(crate) fn parse(parser: &mut Parser) -> SyntaxResult<Self> {
145 Self::parse_precedence(parser, Precedence::None)
146 }
147
148 pub(crate) fn parse_no_seq(parser: &mut Parser) -> SyntaxResult<Self> {
149 Self::parse_precedence(parser, Precedence::None)
150 }
151
152 pub(crate) fn parse_or_pattern_parenthesized(
153 parser: &mut Parser,
154 ) -> SyntaxResult<Result<Self, Pattern>> {
155 use TokenType::*;
156 if parser.check([KwIf, KwPass, KwEnd, KwIs, KwNot]).is_ok() {
157 // Definitely a query
158 Self::parse_precedence(parser, Precedence::None).map(Ok)
159 } else if parser.check(OParen).is_ok() {
160 // Nested again!
161 Ok(ParenthesizedQuery::parse_or_pattern(parser)?
162 .map(|query| Self::Parenthesized(Box::new(query))))
163 } else {
164 // Starts with a pattern, but might be a unification or lookup
165 let expression_or_pattern = Expression::parse_or_pattern(parser)?;
166 let pattern = match expression_or_pattern {
167 Ok(expression) if parser.check(OParen).is_ok() => {
168 // If the next character is `(`, then this is a lookup
169 let lookup = Self::Lookup(Box::new(Lookup::parse_rest(parser, expression)?));
170 return Ok(Ok(Self::parse_precedence_followers(
171 parser,
172 Precedence::None,
173 lookup,
174 )?));
175 }
176 Ok(expression) if expression.is_pattern() => expression.try_into().unwrap(),
177 Ok(expression) => {
178 let error = SyntaxError::new(
179 expression.span(),
180 "bare expressions are not valid in queries",
181 );
182 parser.error(error.clone());
183 return Err(error);
184 }
185 Err(pattern) => pattern,
186 };
187 if parser.check(CParen).is_ok() {
188 // Some parentheses have ended, the caller is going to be expecting to handle
189 // that.
190 Ok(Err(pattern))
191 } else {
192 // This pattern is part of a unification, so let's finish that unification, and then
193 // carry on with the rest of a query until the parentheses are finally closed.
194 let unification = Self::unification(parser, pattern)?;
195 Ok(Ok(Self::parse_precedence_followers(
196 parser,
197 Precedence::None,
198 unification,
199 )?))
200 }
201 }
202 }
203}