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 = self.parse_spec_type()?;
135 Ok(Quantifier { name, ty, constraint: None })
136 }
137
138 fn parse_spec_type(&mut self) -> Result<SpecType, SpecParseError> {
142 if self.eat(&TokenKind::LBrace) {
143 let mut fields: Vec<(String, SpecType)> = Vec::new();
145 self.skip_newlines();
146 if !matches!(self.peek(), Some(TokenKind::RBrace)) {
147 loop {
148 let field_name = self.expect_ident("for record field name")?;
149 if !self.eat(&TokenKind::ColonColon) {
150 return Err(self.err("expected `::` after record field name"));
151 }
152 let field_ty = self.parse_spec_type()?;
153 fields.push((field_name, field_ty));
154 self.skip_newlines();
155 if !self.eat(&TokenKind::Comma) { break; }
156 self.skip_newlines();
157 }
158 }
159 if !self.eat(&TokenKind::RBrace) {
160 return Err(self.err("expected `}` to close record type"));
161 }
162 return Ok(SpecType::Record { fields });
163 }
164 let ty_name = self.expect_ident("for quantifier type")?;
165 match ty_name.as_str() {
166 "Int" => Ok(SpecType::Int),
167 "Float" => Ok(SpecType::Float),
168 "Bool" => Ok(SpecType::Bool),
169 "Str" => Ok(SpecType::Str),
170 "List" => {
171 if !self.eat(&TokenKind::LBracket) {
173 return Err(self.err("expected `[` after `List`"));
174 }
175 let elem = self.parse_spec_type()?;
176 if !self.eat(&TokenKind::RBracket) {
177 return Err(self.err("expected `]` to close `List[...]`"));
178 }
179 Ok(SpecType::List { element: Box::new(elem) })
180 }
181 other if other.chars().next().is_some_and(|c| c.is_ascii_uppercase()) => {
187 Ok(SpecType::Named { name: other.to_string() })
188 }
189 other => Err(self.err(format!("unknown spec type `{other}`"))),
190 }
191 }
192
193 fn parse_body_block(&mut self) -> Result<SpecExpr, SpecParseError> {
196 self.skip_newlines();
198 let mut lets: Vec<(String, SpecExpr)> = Vec::new();
199 while matches!(self.peek(), Some(TokenKind::Let)) {
200 self.bump(); let name = self.expect_ident("after `let`")?;
202 if self.eat(&TokenKind::ColonColon) {
204 let _ = self.expect_ident("after `::`")?;
205 }
206 if !self.eat(&TokenKind::ColonEq) {
207 return Err(self.err("expected `:=` in let"));
208 }
209 let value = self.parse_expr()?;
210 lets.push((name, value));
211 self.skip_newlines();
212 }
213 let mut body = self.parse_expr()?;
214 for (name, value) in lets.into_iter().rev() {
216 body = SpecExpr::Let { name, value: Box::new(value), body: Box::new(body) };
217 }
218 Ok(body)
219 }
220
221 fn parse_expr(&mut self) -> Result<SpecExpr, SpecParseError> {
224 self.parse_or()
225 }
226
227 fn parse_or(&mut self) -> Result<SpecExpr, SpecParseError> {
228 let mut lhs = self.parse_and()?;
229 while self.peek_kw("or") {
230 self.bump();
231 let rhs = self.parse_and()?;
232 lhs = SpecExpr::BinOp { op: SpecOp::Or, lhs: Box::new(lhs), rhs: Box::new(rhs) };
233 }
234 Ok(lhs)
235 }
236
237 fn parse_and(&mut self) -> Result<SpecExpr, SpecParseError> {
238 let mut lhs = self.parse_cmp()?;
239 while self.peek_kw("and") {
240 self.bump();
241 let rhs = self.parse_cmp()?;
242 lhs = SpecExpr::BinOp { op: SpecOp::And, lhs: Box::new(lhs), rhs: Box::new(rhs) };
243 }
244 Ok(lhs)
245 }
246
247 fn parse_cmp(&mut self) -> Result<SpecExpr, SpecParseError> {
248 let lhs = self.parse_add()?;
249 let op = match self.peek() {
250 Some(TokenKind::EqEq) => Some(SpecOp::Eq),
251 Some(TokenKind::BangEq) => Some(SpecOp::Neq),
252 Some(TokenKind::Lt) => Some(SpecOp::Lt),
253 Some(TokenKind::LtEq) => Some(SpecOp::Le),
254 Some(TokenKind::Gt) => Some(SpecOp::Gt),
255 Some(TokenKind::GtEq) => Some(SpecOp::Ge),
256 _ => None,
257 };
258 if let Some(op) = op {
259 self.bump();
260 let rhs = self.parse_add()?;
261 return Ok(SpecExpr::BinOp { op, lhs: Box::new(lhs), rhs: Box::new(rhs) });
262 }
263 Ok(lhs)
264 }
265
266 fn parse_add(&mut self) -> Result<SpecExpr, SpecParseError> {
267 let mut lhs = self.parse_mul()?;
268 loop {
269 let op = match self.peek() {
270 Some(TokenKind::Plus) => SpecOp::Add,
271 Some(TokenKind::Minus) => SpecOp::Sub,
272 _ => break,
273 };
274 self.bump();
275 let rhs = self.parse_mul()?;
276 lhs = SpecExpr::BinOp { op, lhs: Box::new(lhs), rhs: Box::new(rhs) };
277 }
278 Ok(lhs)
279 }
280
281 fn parse_mul(&mut self) -> Result<SpecExpr, SpecParseError> {
282 let mut lhs = self.parse_unary()?;
283 loop {
284 let op = match self.peek() {
285 Some(TokenKind::Star) => SpecOp::Mul,
286 Some(TokenKind::Slash) => SpecOp::Div,
287 Some(TokenKind::Percent) => SpecOp::Mod,
288 _ => break,
289 };
290 self.bump();
291 let rhs = self.parse_unary()?;
292 lhs = SpecExpr::BinOp { op, lhs: Box::new(lhs), rhs: Box::new(rhs) };
293 }
294 Ok(lhs)
295 }
296
297 fn parse_unary(&mut self) -> Result<SpecExpr, SpecParseError> {
298 if self.peek_kw("not") {
299 self.bump();
300 let e = self.parse_unary()?;
301 return Ok(SpecExpr::Not { expr: Box::new(e) });
302 }
303 self.parse_postfix()
304 }
305
306 fn parse_postfix(&mut self) -> Result<SpecExpr, SpecParseError> {
307 let mut e = self.parse_primary()?;
308 loop {
309 match self.peek() {
310 Some(TokenKind::LParen) => {
311 self.bump();
312 let mut args = Vec::new();
313 self.skip_newlines();
314 if !matches!(self.peek(), Some(TokenKind::RParen)) {
315 args.push(self.parse_expr()?);
316 while self.eat(&TokenKind::Comma) { args.push(self.parse_expr()?); }
317 }
318 if !self.eat(&TokenKind::RParen) {
319 return Err(self.err("expected `)` to close call"));
320 }
321 let func = match e {
322 SpecExpr::Var { name } => name,
323 other => return Err(self.err(format!("only ident-callable; got {other:?}"))),
324 };
325 e = SpecExpr::Call { func, args };
326 }
327 Some(TokenKind::Dot) => {
328 self.bump();
329 let field = self.expect_ident("after `.`")?;
330 e = SpecExpr::FieldAccess { value: Box::new(e), field };
331 }
332 Some(TokenKind::LBracket) => {
333 self.bump();
337 let index = self.parse_expr()?;
338 if !self.eat(&TokenKind::RBracket) {
339 return Err(self.err("expected `]` to close index"));
340 }
341 e = SpecExpr::Index { list: Box::new(e), index: Box::new(index) };
342 }
343 _ => break,
344 }
345 }
346 Ok(e)
347 }
348
349 fn parse_primary(&mut self) -> Result<SpecExpr, SpecParseError> {
350 self.skip_newlines();
351 match self.peek() {
352 Some(TokenKind::Int(_)) => match self.bump().unwrap().kind {
353 TokenKind::Int(n) => Ok(SpecExpr::IntLit { value: n }), _ => unreachable!(),
354 },
355 Some(TokenKind::Float(_)) => match self.bump().unwrap().kind {
356 TokenKind::Float(n) => Ok(SpecExpr::FloatLit { value: n }), _ => unreachable!(),
357 },
358 Some(TokenKind::Str(_)) => match self.bump().unwrap().kind {
359 TokenKind::Str(s) => Ok(SpecExpr::StrLit { value: s }), _ => unreachable!(),
360 },
361 Some(TokenKind::True) => { self.bump(); Ok(SpecExpr::BoolLit { value: true }) }
362 Some(TokenKind::False) => { self.bump(); Ok(SpecExpr::BoolLit { value: false }) }
363 Some(TokenKind::Match) => self.parse_match(),
364 Some(TokenKind::Ident(_)) => {
365 let name = self.expect_ident("")?;
366 Ok(SpecExpr::Var { name })
367 }
368 Some(TokenKind::LParen) => {
369 self.bump();
370 let e = self.parse_expr()?;
371 if !self.eat(&TokenKind::RParen) {
372 return Err(self.err("expected `)`"));
373 }
374 Ok(e)
375 }
376 other => Err(self.err(format!("expected primary expression, got {other:?}"))),
377 }
378 }
379
380 fn parse_match(&mut self) -> Result<SpecExpr, SpecParseError> {
383 self.bump(); let scrutinee = self.parse_expr()?;
385 if !self.eat(&TokenKind::LBrace) {
386 return Err(self.err("expected `{` after match scrutinee"));
387 }
388 let mut arms: Vec<crate::ast::MatchArm> = Vec::new();
389 self.skip_newlines();
390 while !matches!(self.peek(), Some(TokenKind::RBrace)) {
391 let pattern = self.parse_pattern()?;
392 if !self.eat(&TokenKind::FatArrow) {
393 return Err(self.err("expected `=>` after match pattern"));
394 }
395 let body = self.parse_expr()?;
396 arms.push(crate::ast::MatchArm { pattern, body });
397 self.skip_newlines();
398 if !self.eat(&TokenKind::Comma) { break; }
399 self.skip_newlines();
400 }
401 if !self.eat(&TokenKind::RBrace) {
402 return Err(self.err("expected `}` to close match"));
403 }
404 Ok(SpecExpr::Match {
405 scrutinee: Box::new(scrutinee),
406 arms,
407 })
408 }
409
410 fn parse_pattern(&mut self) -> Result<crate::ast::SpecPattern, SpecParseError> {
412 self.skip_newlines();
413 if self.eat(&TokenKind::Underscore) {
414 return Ok(crate::ast::SpecPattern::Wildcard);
415 }
416 let name = self.expect_ident("for variant pattern")?;
417 let bindings = if self.eat(&TokenKind::LParen) {
418 let mut bs = Vec::new();
419 self.skip_newlines();
420 if !matches!(self.peek(), Some(TokenKind::RParen)) {
421 bs.push(self.parse_variant_binding()?);
422 while self.eat(&TokenKind::Comma) {
423 bs.push(self.parse_variant_binding()?);
424 }
425 }
426 if !self.eat(&TokenKind::RParen) {
427 return Err(self.err("expected `)` to close variant pattern"));
428 }
429 bs
430 } else {
431 Vec::new()
432 };
433 Ok(crate::ast::SpecPattern::Variant { name, bindings })
434 }
435
436 fn parse_variant_binding(&mut self) -> Result<String, SpecParseError> {
441 if self.eat(&TokenKind::Underscore) {
442 return Ok("_".to_string());
443 }
444 self.expect_ident("for variant binding")
445 }
446
447 fn peek_kw(&self, name: &str) -> bool {
448 match self.toks.get(self.idx).map(|t| &t.kind) {
449 Some(TokenKind::Ident(n)) => n == name,
450 Some(TokenKind::And) => name == "and",
451 Some(TokenKind::Or) => name == "or",
452 Some(TokenKind::Not) => name == "not",
453 _ => false,
454 }
455 }
456}