Actually just three programming languages in a trenchcoat
at main 203 lines 8.5 kB view raw
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}