1use crate::ast::*;
4use lex_syntax::token::{lex, Token, TokenKind};
5
6#[derive(Debug, thiserror::Error)]
7#[error("spec parse error at byte {pos}: {msg}")]
8pub struct SpecParseError {
9 pub pos: usize,
10 pub msg: String,
11}
12
13pub fn parse_spec(src: &str) -> Result<Spec, SpecParseError> {
14 let toks = lex(src).map_err(|e| SpecParseError {
15 pos: e.span.start, msg: format!("lex: {}", e.snippet),
16 })?;
17 let mut p = Parser { toks, idx: 0 };
18 let spec = p.parse_spec()?;
19 p.skip_newlines();
20 if !p.at_eof() {
21 return Err(p.err("trailing input after spec"));
22 }
23 Ok(spec)
24}
25
26struct Parser {
27 toks: Vec<Token>,
28 idx: usize,
29}
30
31impl Parser {
32 fn at_eof(&self) -> bool { self.idx >= self.toks.len() }
33
34 fn peek(&self) -> Option<&TokenKind> { self.toks.get(self.idx).map(|t| &t.kind) }
35
36 fn bump(&mut self) -> Option<Token> {
37 let t = self.toks.get(self.idx).cloned();
38 if t.is_some() { self.idx += 1; }
39 t
40 }
41
42 fn pos(&self) -> usize {
43 self.toks.get(self.idx).map(|t| t.span.start).unwrap_or(0)
44 }
45
46 fn err(&self, m: impl Into<String>) -> SpecParseError {
47 SpecParseError { pos: self.pos(), msg: m.into() }
48 }
49
50 fn skip_newlines(&mut self) {
51 while matches!(self.peek(), Some(TokenKind::Newline) | Some(TokenKind::Semi)) {
52 self.idx += 1;
53 }
54 }
55
56 fn eat(&mut self, k: &TokenKind) -> bool {
57 self.skip_newlines();
58 if let Some(cur) = self.peek() {
59 if std::mem::discriminant(cur) == std::mem::discriminant(k) {
60 self.bump();
61 return true;
62 }
63 }
64 false
65 }
66
67 fn expect_ident(&mut self, ctx: &str) -> Result<String, SpecParseError> {
68 self.skip_newlines();
69 match self.peek() {
70 Some(TokenKind::Ident(_)) => match self.bump().unwrap().kind {
71 TokenKind::Ident(n) => Ok(n), _ => unreachable!(),
72 },
73 other => Err(self.err(format!("expected ident {ctx}, got {other:?}"))),
74 }
75 }
76
77 fn expect_keyword(&mut self, kw: &str) -> Result<(), SpecParseError> {
78 let id = self.expect_ident(&format!("(keyword `{kw}`)"))?;
81 if id != kw {
82 return Err(self.err(format!("expected `{kw}`, got `{id}`")));
83 }
84 Ok(())
85 }
86
87 fn parse_spec(&mut self) -> Result<Spec, SpecParseError> {
88 self.expect_keyword("spec")?;
90 let name = self.expect_ident("for spec name")?;
91 if !self.eat(&TokenKind::LBrace) {
92 return Err(self.err("expected `{` after spec name"));
93 }
94 self.expect_keyword("forall")?;
95
96 let mut quantifiers = Vec::new();
97 loop {
98 quantifiers.push(self.parse_quantifier()?);
99 self.skip_newlines();
100 if self.eat(&TokenKind::Comma) {
101 continue;
102 }
103 break;
104 }
105
106 if let Some(TokenKind::Ident(n)) = self.peek() {
108 if n == "where" {
109 self.bump();
110 let c = self.parse_expr()?;
111 if let Some(last) = quantifiers.last_mut() {
112 last.constraint = Some(c);
113 }
114 }
115 }
116
117 if !self.eat(&TokenKind::Colon) && !self.eat(&TokenKind::FatArrow) {
119 return Err(self.err("expected `:` or `=>` before spec body"));
120 }
121
122 let body = self.parse_body_block()?;
123 if !self.eat(&TokenKind::RBrace) {
124 return Err(self.err("expected `}` to close spec"));
125 }
126 Ok(Spec { name, quantifiers, body })
127 }
128
129 fn parse_quantifier(&mut self) -> Result<Quantifier, SpecParseError> {
130 let name = self.expect_ident("for quantifier var")?;
131 if !self.eat(&TokenKind::ColonColon) {
132 return Err(self.err("expected `::` after quantifier var"));
133 }
134 let ty_name = self.expect_ident("for quantifier type")?;
135 let ty = match ty_name.as_str() {
136 "Int" => SpecType::Int,
137 "Float" => SpecType::Float,
138 "Bool" => SpecType::Bool,
139 "Str" => SpecType::Str,
140 other => return Err(self.err(format!("unknown spec type `{other}`"))),
141 };
142 Ok(Quantifier { name, ty, constraint: None })
143 }
144
145 fn parse_body_block(&mut self) -> Result<SpecExpr, SpecParseError> {
148 self.skip_newlines();
150 let mut lets: Vec<(String, SpecExpr)> = Vec::new();
151 while matches!(self.peek(), Some(TokenKind::Let)) {
152 self.bump(); let name = self.expect_ident("after `let`")?;
154 if self.eat(&TokenKind::ColonColon) {
156 let _ = self.expect_ident("after `::`")?;
157 }
158 if !self.eat(&TokenKind::ColonEq) {
159 return Err(self.err("expected `:=` in let"));
160 }
161 let value = self.parse_expr()?;
162 lets.push((name, value));
163 self.skip_newlines();
164 }
165 let mut body = self.parse_expr()?;
166 for (name, value) in lets.into_iter().rev() {
168 body = SpecExpr::Let { name, value: Box::new(value), body: Box::new(body) };
169 }
170 Ok(body)
171 }
172
173 fn parse_expr(&mut self) -> Result<SpecExpr, SpecParseError> {
176 self.parse_or()
177 }
178
179 fn parse_or(&mut self) -> Result<SpecExpr, SpecParseError> {
180 let mut lhs = self.parse_and()?;
181 while self.peek_kw("or") {
182 self.bump();
183 let rhs = self.parse_and()?;
184 lhs = SpecExpr::BinOp { op: SpecOp::Or, lhs: Box::new(lhs), rhs: Box::new(rhs) };
185 }
186 Ok(lhs)
187 }
188
189 fn parse_and(&mut self) -> Result<SpecExpr, SpecParseError> {
190 let mut lhs = self.parse_cmp()?;
191 while self.peek_kw("and") {
192 self.bump();
193 let rhs = self.parse_cmp()?;
194 lhs = SpecExpr::BinOp { op: SpecOp::And, lhs: Box::new(lhs), rhs: Box::new(rhs) };
195 }
196 Ok(lhs)
197 }
198
199 fn parse_cmp(&mut self) -> Result<SpecExpr, SpecParseError> {
200 let lhs = self.parse_add()?;
201 let op = match self.peek() {
202 Some(TokenKind::EqEq) => Some(SpecOp::Eq),
203 Some(TokenKind::BangEq) => Some(SpecOp::Neq),
204 Some(TokenKind::Lt) => Some(SpecOp::Lt),
205 Some(TokenKind::LtEq) => Some(SpecOp::Le),
206 Some(TokenKind::Gt) => Some(SpecOp::Gt),
207 Some(TokenKind::GtEq) => Some(SpecOp::Ge),
208 _ => None,
209 };
210 if let Some(op) = op {
211 self.bump();
212 let rhs = self.parse_add()?;
213 return Ok(SpecExpr::BinOp { op, lhs: Box::new(lhs), rhs: Box::new(rhs) });
214 }
215 Ok(lhs)
216 }
217
218 fn parse_add(&mut self) -> Result<SpecExpr, SpecParseError> {
219 let mut lhs = self.parse_mul()?;
220 loop {
221 let op = match self.peek() {
222 Some(TokenKind::Plus) => SpecOp::Add,
223 Some(TokenKind::Minus) => SpecOp::Sub,
224 _ => break,
225 };
226 self.bump();
227 let rhs = self.parse_mul()?;
228 lhs = SpecExpr::BinOp { op, lhs: Box::new(lhs), rhs: Box::new(rhs) };
229 }
230 Ok(lhs)
231 }
232
233 fn parse_mul(&mut self) -> Result<SpecExpr, SpecParseError> {
234 let mut lhs = self.parse_unary()?;
235 loop {
236 let op = match self.peek() {
237 Some(TokenKind::Star) => SpecOp::Mul,
238 Some(TokenKind::Slash) => SpecOp::Div,
239 Some(TokenKind::Percent) => SpecOp::Mod,
240 _ => break,
241 };
242 self.bump();
243 let rhs = self.parse_unary()?;
244 lhs = SpecExpr::BinOp { op, lhs: Box::new(lhs), rhs: Box::new(rhs) };
245 }
246 Ok(lhs)
247 }
248
249 fn parse_unary(&mut self) -> Result<SpecExpr, SpecParseError> {
250 if self.peek_kw("not") {
251 self.bump();
252 let e = self.parse_unary()?;
253 return Ok(SpecExpr::Not { expr: Box::new(e) });
254 }
255 self.parse_postfix()
256 }
257
258 fn parse_postfix(&mut self) -> Result<SpecExpr, SpecParseError> {
259 let mut e = self.parse_primary()?;
260 while matches!(self.peek(), Some(TokenKind::LParen)) {
261 self.bump();
262 let mut args = Vec::new();
263 self.skip_newlines();
264 if !matches!(self.peek(), Some(TokenKind::RParen)) {
265 args.push(self.parse_expr()?);
266 while self.eat(&TokenKind::Comma) { args.push(self.parse_expr()?); }
267 }
268 if !self.eat(&TokenKind::RParen) {
269 return Err(self.err("expected `)` to close call"));
270 }
271 let func = match e {
272 SpecExpr::Var { name } => name,
273 other => return Err(self.err(format!("only ident-callable; got {other:?}"))),
274 };
275 e = SpecExpr::Call { func, args };
276 }
277 Ok(e)
278 }
279
280 fn parse_primary(&mut self) -> Result<SpecExpr, SpecParseError> {
281 self.skip_newlines();
282 match self.peek() {
283 Some(TokenKind::Int(_)) => match self.bump().unwrap().kind {
284 TokenKind::Int(n) => Ok(SpecExpr::IntLit { value: n }), _ => unreachable!(),
285 },
286 Some(TokenKind::Float(_)) => match self.bump().unwrap().kind {
287 TokenKind::Float(n) => Ok(SpecExpr::FloatLit { value: n }), _ => unreachable!(),
288 },
289 Some(TokenKind::Str(_)) => match self.bump().unwrap().kind {
290 TokenKind::Str(s) => Ok(SpecExpr::StrLit { value: s }), _ => unreachable!(),
291 },
292 Some(TokenKind::True) => { self.bump(); Ok(SpecExpr::BoolLit { value: true }) }
293 Some(TokenKind::False) => { self.bump(); Ok(SpecExpr::BoolLit { value: false }) }
294 Some(TokenKind::Ident(_)) => {
295 let name = self.expect_ident("")?;
296 Ok(SpecExpr::Var { name })
297 }
298 Some(TokenKind::LParen) => {
299 self.bump();
300 let e = self.parse_expr()?;
301 if !self.eat(&TokenKind::RParen) {
302 return Err(self.err("expected `)`"));
303 }
304 Ok(e)
305 }
306 other => Err(self.err(format!("expected primary expression, got {other:?}"))),
307 }
308 }
309
310 fn peek_kw(&self, name: &str) -> bool {
311 match self.toks.get(self.idx).map(|t| &t.kind) {
312 Some(TokenKind::Ident(n)) => n == name,
313 Some(TokenKind::And) => name == "and",
314 Some(TokenKind::Or) => name == "or",
315 Some(TokenKind::Not) => name == "not",
316 _ => false,
317 }
318 }
319}