diff options
Diffstat (limited to 'compiler/src/ast')
| -rw-r--r-- | compiler/src/ast/models.rs | 5 | ||||
| -rw-r--r-- | compiler/src/ast/parser.rs | 33 | ||||
| -rw-r--r-- | compiler/src/ast/tests.rs | 311 |
3 files changed, 346 insertions, 3 deletions
diff --git a/compiler/src/ast/models.rs b/compiler/src/ast/models.rs index 64fec19..1cb705d 100644 --- a/compiler/src/ast/models.rs +++ b/compiler/src/ast/models.rs | |||
| @@ -31,6 +31,11 @@ pub enum Expr { | |||
| 31 | vars: Vec<Spanned<LetVar>>, | 31 | vars: Vec<Spanned<LetVar>>, |
| 32 | body: Vec<Spanned<Expr>>, | 32 | body: Vec<Spanned<Expr>>, |
| 33 | }, | 33 | }, |
| 34 | If { | ||
| 35 | condition: Spanned<Box<Expr>>, | ||
| 36 | then_expr: Spanned<Box<Expr>>, | ||
| 37 | else_expr: Option<Spanned<Box<Expr>>>, | ||
| 38 | }, | ||
| 34 | For { | 39 | For { |
| 35 | loop_var: Spanned<Rc<str>>, | 40 | loop_var: Spanned<Rc<str>>, |
| 36 | from: Spanned<Box<Expr>>, | 41 | from: Spanned<Box<Expr>>, |
diff --git a/compiler/src/ast/parser.rs b/compiler/src/ast/parser.rs index 12a6f0d..88ba8c7 100644 --- a/compiler/src/ast/parser.rs +++ b/compiler/src/ast/parser.rs | |||
| @@ -244,14 +244,40 @@ where | |||
| 244 | Ok(Spanned::new(let_vars, span)) | 244 | Ok(Spanned::new(let_vars, span)) |
| 245 | } | 245 | } |
| 246 | 246 | ||
| 247 | fn parse_if(&mut self, open_span: Span) -> Result<Spanned<Expr>, Spanned<Error>> { | ||
| 248 | self.consume()?; | ||
| 249 | |||
| 250 | let condition = self.parse_expr()?.map(Into::into); | ||
| 251 | let then_expr = self.parse_expr()?.map(Into::into); | ||
| 252 | let else_expr = match self.peek_token()?.inner { | ||
| 253 | Token::RightPar => { | ||
| 254 | self.consume()?; | ||
| 255 | None | ||
| 256 | } | ||
| 257 | _ => { | ||
| 258 | let expr = self.parse_expr()?.map(Into::into); | ||
| 259 | self.require_right_par()?; | ||
| 260 | Some(expr) | ||
| 261 | } | ||
| 262 | }; | ||
| 263 | |||
| 264 | let if_stmt = Expr::If { | ||
| 265 | condition, | ||
| 266 | then_expr, | ||
| 267 | else_expr, | ||
| 268 | }; | ||
| 269 | let span = Span::new(open_span.start, self.last_token_span.end); | ||
| 270 | Ok(Spanned::new(if_stmt, span)) | ||
| 271 | } | ||
| 272 | |||
| 247 | fn parse_for(&mut self, open_span: Span) -> Result<Spanned<Expr>, Spanned<Error>> { | 273 | fn parse_for(&mut self, open_span: Span) -> Result<Spanned<Expr>, Spanned<Error>> { |
| 248 | self.consume()?; | 274 | self.consume()?; |
| 249 | 275 | ||
| 250 | let loop_var = self.parse_sym()?.map(Into::into); | 276 | let loop_var = self.parse_sym()?.map(Into::into); |
| 251 | self.require_sym("from")?; | 277 | self.require_sym("from")?; |
| 252 | let from = self.parse_expr()?.map(Box::new); | 278 | let from = self.parse_expr()?.map(Into::into); |
| 253 | self.require_sym("to")?; | 279 | self.require_sym("to")?; |
| 254 | let to = self.parse_expr()?.map(Box::new); | 280 | let to = self.parse_expr()?.map(Into::into); |
| 255 | let body = self.parse_body(open_span, true)?; | 281 | let body = self.parse_body(open_span, true)?; |
| 256 | 282 | ||
| 257 | let for_loop = Expr::For { | 283 | let for_loop = Expr::For { |
| @@ -268,7 +294,7 @@ where | |||
| 268 | self.consume()?; | 294 | self.consume()?; |
| 269 | 295 | ||
| 270 | let target_var = self.parse_sym()?.map(Into::into); | 296 | let target_var = self.parse_sym()?.map(Into::into); |
| 271 | let expr = self.parse_expr()?.map(Box::new); | 297 | let expr = self.parse_expr()?.map(Into::into); |
| 272 | self.require_right_par()?; | 298 | self.require_right_par()?; |
| 273 | 299 | ||
| 274 | let set = Expr::Set { target_var, expr }; | 300 | let set = Expr::Set { target_var, expr }; |
| @@ -312,6 +338,7 @@ where | |||
| 312 | "fn" => self.parse_fn(open_span), | 338 | "fn" => self.parse_fn(open_span), |
| 313 | "const" => self.parse_const(open_span), | 339 | "const" => self.parse_const(open_span), |
| 314 | "let" => self.parse_let(open_span), | 340 | "let" => self.parse_let(open_span), |
| 341 | "if" => self.parse_if(open_span), | ||
| 315 | "for" => self.parse_for(open_span), | 342 | "for" => self.parse_for(open_span), |
| 316 | "set" => self.parse_set(open_span), | 343 | "set" => self.parse_set(open_span), |
| 317 | "do" => self.parse_do(open_span), | 344 | "do" => self.parse_do(open_span), |
diff --git a/compiler/src/ast/tests.rs b/compiler/src/ast/tests.rs index 5b2399f..d2a27a1 100644 --- a/compiler/src/ast/tests.rs +++ b/compiler/src/ast/tests.rs | |||
| @@ -16,6 +16,7 @@ enum E { | |||
| 16 | Fn(&'static str, Vec<&'static str>, Vec<E>), | 16 | Fn(&'static str, Vec<&'static str>, Vec<E>), |
| 17 | Const(Vec<(&'static str, E)>), | 17 | Const(Vec<(&'static str, E)>), |
| 18 | Let(Vec<(&'static str, E)>, Vec<E>), | 18 | Let(Vec<(&'static str, E)>, Vec<E>), |
| 19 | If(Box<E>, Box<E>, Option<Box<E>>), | ||
| 19 | For(&'static str, Box<E>, Box<E>, Vec<E>), | 20 | For(&'static str, Box<E>, Box<E>, Vec<E>), |
| 20 | Set(&'static str, Box<E>), | 21 | Set(&'static str, Box<E>), |
| 21 | Do(Vec<E>), | 22 | Do(Vec<E>), |
| @@ -50,6 +51,15 @@ impl From<Expr> for E { | |||
| 50 | vars.into_iter().map(|v| convert_var(v.inner)).collect(), | 51 | vars.into_iter().map(|v| convert_var(v.inner)).collect(), |
| 51 | body.into_iter().map(|e| e.inner.into()).collect(), | 52 | body.into_iter().map(|e| e.inner.into()).collect(), |
| 52 | ), | 53 | ), |
| 54 | Expr::If { | ||
| 55 | condition, | ||
| 56 | then_expr, | ||
| 57 | else_expr, | ||
| 58 | } => If( | ||
| 59 | Box::new(E::from(*condition.inner)), | ||
| 60 | Box::new(E::from(*then_expr.inner)), | ||
| 61 | else_expr.map(|e| Box::new(E::from(*e.inner))), | ||
| 62 | ), | ||
| 53 | Expr::For { | 63 | Expr::For { |
| 54 | loop_var, | 64 | loop_var, |
| 55 | from, | 65 | from, |
| @@ -388,6 +398,141 @@ fn test_let() { | |||
| 388 | } | 398 | } |
| 389 | 399 | ||
| 390 | #[test] | 400 | #[test] |
| 401 | fn test_if() { | ||
| 402 | let cases = vec![ | ||
| 403 | // (if true 1 2) | ||
| 404 | ( | ||
| 405 | vec![ | ||
| 406 | LeftPar, | ||
| 407 | Symbol("if"), | ||
| 408 | Symbol("true"), | ||
| 409 | Number("1"), | ||
| 410 | Number("2"), | ||
| 411 | RightPar, | ||
| 412 | ], | ||
| 413 | vec![If( | ||
| 414 | Box::new(Bool(true)), | ||
| 415 | Box::new(Int(1)), | ||
| 416 | Some(Box::new(Int(2))), | ||
| 417 | )], | ||
| 418 | ), | ||
| 419 | // (if true 1) | ||
| 420 | ( | ||
| 421 | vec![LeftPar, Symbol("if"), Symbol("true"), Number("1"), RightPar], | ||
| 422 | vec![If(Box::new(Bool(true)), Box::new(Int(1)), None)], | ||
| 423 | ), | ||
| 424 | // (if (= x 0) a b) | ||
| 425 | ( | ||
| 426 | vec![ | ||
| 427 | LeftPar, | ||
| 428 | Symbol("if"), | ||
| 429 | LeftPar, | ||
| 430 | Symbol("="), | ||
| 431 | Symbol("x"), | ||
| 432 | Number("0"), | ||
| 433 | RightPar, | ||
| 434 | Symbol("a"), | ||
| 435 | Symbol("b"), | ||
| 436 | RightPar, | ||
| 437 | ], | ||
| 438 | vec![If( | ||
| 439 | Box::new(Call("=", vec![Sym("x"), Int(0)])), | ||
| 440 | Box::new(Sym("a")), | ||
| 441 | Some(Box::new(Sym("b"))), | ||
| 442 | )], | ||
| 443 | ), | ||
| 444 | // (if true (do 1 2) (do 3 4)) | ||
| 445 | ( | ||
| 446 | vec![ | ||
| 447 | LeftPar, | ||
| 448 | Symbol("if"), | ||
| 449 | Symbol("true"), | ||
| 450 | LeftPar, | ||
| 451 | Symbol("do"), | ||
| 452 | Number("1"), | ||
| 453 | Number("2"), | ||
| 454 | RightPar, | ||
| 455 | LeftPar, | ||
| 456 | Symbol("do"), | ||
| 457 | Number("3"), | ||
| 458 | Number("4"), | ||
| 459 | RightPar, | ||
| 460 | RightPar, | ||
| 461 | ], | ||
| 462 | vec![If( | ||
| 463 | Box::new(Bool(true)), | ||
| 464 | Box::new(Do(vec![Int(1), Int(2)])), | ||
| 465 | Some(Box::new(Do(vec![Int(3), Int(4)]))), | ||
| 466 | )], | ||
| 467 | ), | ||
| 468 | // (if nil nil) | ||
| 469 | ( | ||
| 470 | vec![ | ||
| 471 | LeftPar, | ||
| 472 | Symbol("if"), | ||
| 473 | Symbol("nil"), | ||
| 474 | Symbol("nil"), | ||
| 475 | RightPar, | ||
| 476 | ], | ||
| 477 | vec![If(Box::new(Nil), Box::new(Nil), None)], | ||
| 478 | ), | ||
| 479 | // (if true (if false 1 2) 3) | ||
| 480 | ( | ||
| 481 | vec![ | ||
| 482 | LeftPar, | ||
| 483 | Symbol("if"), | ||
| 484 | Symbol("true"), | ||
| 485 | LeftPar, | ||
| 486 | Symbol("if"), | ||
| 487 | Symbol("false"), | ||
| 488 | Number("1"), | ||
| 489 | Number("2"), | ||
| 490 | RightPar, | ||
| 491 | Number("3"), | ||
| 492 | RightPar, | ||
| 493 | ], | ||
| 494 | vec![If( | ||
| 495 | Box::new(Bool(true)), | ||
| 496 | Box::new(If( | ||
| 497 | Box::new(Bool(false)), | ||
| 498 | Box::new(Int(1)), | ||
| 499 | Some(Box::new(Int(2))), | ||
| 500 | )), | ||
| 501 | Some(Box::new(Int(3))), | ||
| 502 | )], | ||
| 503 | ), | ||
| 504 | // (if true 1 (if false 2 3)) | ||
| 505 | ( | ||
| 506 | vec![ | ||
| 507 | LeftPar, | ||
| 508 | Symbol("if"), | ||
| 509 | Symbol("true"), | ||
| 510 | Number("1"), | ||
| 511 | LeftPar, | ||
| 512 | Symbol("if"), | ||
| 513 | Symbol("false"), | ||
| 514 | Number("2"), | ||
| 515 | Number("3"), | ||
| 516 | RightPar, | ||
| 517 | RightPar, | ||
| 518 | ], | ||
| 519 | vec![If( | ||
| 520 | Box::new(Bool(true)), | ||
| 521 | Box::new(Int(1)), | ||
| 522 | Some(Box::new(If( | ||
| 523 | Box::new(Bool(false)), | ||
| 524 | Box::new(Int(2)), | ||
| 525 | Some(Box::new(Int(3))), | ||
| 526 | ))), | ||
| 527 | )], | ||
| 528 | ), | ||
| 529 | ]; | ||
| 530 | for (tokens, ast) in cases { | ||
| 531 | assert_eq!(parse(tokens.clone()), ast, "input: {tokens:?}"); | ||
| 532 | } | ||
| 533 | } | ||
| 534 | |||
| 535 | #[test] | ||
| 391 | fn test_for() { | 536 | fn test_for() { |
| 392 | let cases = vec![ | 537 | let cases = vec![ |
| 393 | // (for i from 0 to 10 i) | 538 | // (for i from 0 to 10 i) |
| @@ -947,6 +1092,9 @@ fn test_keyword_prefixed_symbols() { | |||
| 947 | (vec![Symbol("set?")], vec![Sym("set?")]), | 1092 | (vec![Symbol("set?")], vec![Sym("set?")]), |
| 948 | (vec![Symbol("for-each")], vec![Sym("for-each")]), | 1093 | (vec![Symbol("for-each")], vec![Sym("for-each")]), |
| 949 | (vec![Symbol("const-x")], vec![Sym("const-x")]), | 1094 | (vec![Symbol("const-x")], vec![Sym("const-x")]), |
| 1095 | (vec![Symbol("if-then")], vec![Sym("if-then")]), | ||
| 1096 | (vec![Symbol("iffy")], vec![Sym("iffy")]), | ||
| 1097 | (vec![Symbol("if?")], vec![Sym("if?")]), | ||
| 950 | // (fn-foo 1) | 1098 | // (fn-foo 1) |
| 951 | ( | 1099 | ( |
| 952 | vec![LeftPar, Symbol("fn-foo"), Number("1"), RightPar], | 1100 | vec![LeftPar, Symbol("fn-foo"), Number("1"), RightPar], |
| @@ -1150,6 +1298,16 @@ fn test_special_form_errors() { | |||
| 1150 | vec![LeftPar, Symbol("const"), LeftPar, RightPar, RightPar], | 1298 | vec![LeftPar, Symbol("const"), LeftPar, RightPar, RightPar], |
| 1151 | Error::UnexpectedToken, | 1299 | Error::UnexpectedToken, |
| 1152 | ), | 1300 | ), |
| 1301 | // (if) | ||
| 1302 | ( | ||
| 1303 | vec![LeftPar, Symbol("if"), RightPar], | ||
| 1304 | Error::UnexpectedClosePar, | ||
| 1305 | ), | ||
| 1306 | // (if true) | ||
| 1307 | ( | ||
| 1308 | vec![LeftPar, Symbol("if"), Symbol("true"), RightPar], | ||
| 1309 | Error::UnexpectedClosePar, | ||
| 1310 | ), | ||
| 1153 | ]; | 1311 | ]; |
| 1154 | for (tokens, expected) in cases { | 1312 | for (tokens, expected) in cases { |
| 1155 | assert_eq!(parse_err(tokens.clone()), expected, "input: {tokens:?}"); | 1313 | assert_eq!(parse_err(tokens.clone()), expected, "input: {tokens:?}"); |
| @@ -1301,6 +1459,79 @@ fn test_nested_special_forms() { | |||
| 1301 | vec![Sym("x"), Call("+", vec![Sym("x"), Int(1)])], | 1459 | vec![Sym("x"), Call("+", vec![Sym("x"), Int(1)])], |
| 1302 | )], | 1460 | )], |
| 1303 | ), | 1461 | ), |
| 1462 | // (if (if a b c) (if d e) (if f g h)) | ||
| 1463 | ( | ||
| 1464 | vec![ | ||
| 1465 | LeftPar, | ||
| 1466 | Symbol("if"), | ||
| 1467 | LeftPar, | ||
| 1468 | Symbol("if"), | ||
| 1469 | Symbol("a"), | ||
| 1470 | Symbol("b"), | ||
| 1471 | Symbol("c"), | ||
| 1472 | RightPar, | ||
| 1473 | LeftPar, | ||
| 1474 | Symbol("if"), | ||
| 1475 | Symbol("d"), | ||
| 1476 | Symbol("e"), | ||
| 1477 | RightPar, | ||
| 1478 | LeftPar, | ||
| 1479 | Symbol("if"), | ||
| 1480 | Symbol("f"), | ||
| 1481 | Symbol("g"), | ||
| 1482 | Symbol("h"), | ||
| 1483 | RightPar, | ||
| 1484 | RightPar, | ||
| 1485 | ], | ||
| 1486 | vec![If( | ||
| 1487 | Box::new(If( | ||
| 1488 | Box::new(Sym("a")), | ||
| 1489 | Box::new(Sym("b")), | ||
| 1490 | Some(Box::new(Sym("c"))), | ||
| 1491 | )), | ||
| 1492 | Box::new(If(Box::new(Sym("d")), Box::new(Sym("e")), None)), | ||
| 1493 | Some(Box::new(If( | ||
| 1494 | Box::new(Sym("f")), | ||
| 1495 | Box::new(Sym("g")), | ||
| 1496 | Some(Box::new(Sym("h"))), | ||
| 1497 | ))), | ||
| 1498 | )], | ||
| 1499 | ), | ||
| 1500 | // (fn abs (x) (if (< x 0) (- 0 x) x)) | ||
| 1501 | ( | ||
| 1502 | vec![ | ||
| 1503 | LeftPar, | ||
| 1504 | Symbol("fn"), | ||
| 1505 | Symbol("abs"), | ||
| 1506 | LeftPar, | ||
| 1507 | Symbol("x"), | ||
| 1508 | RightPar, | ||
| 1509 | LeftPar, | ||
| 1510 | Symbol("if"), | ||
| 1511 | LeftPar, | ||
| 1512 | Symbol("<"), | ||
| 1513 | Symbol("x"), | ||
| 1514 | Number("0"), | ||
| 1515 | RightPar, | ||
| 1516 | LeftPar, | ||
| 1517 | Symbol("-"), | ||
| 1518 | Number("0"), | ||
| 1519 | Symbol("x"), | ||
| 1520 | RightPar, | ||
| 1521 | Symbol("x"), | ||
| 1522 | RightPar, | ||
| 1523 | RightPar, | ||
| 1524 | ], | ||
| 1525 | vec![Fn( | ||
| 1526 | "abs", | ||
| 1527 | vec!["x"], | ||
| 1528 | vec![If( | ||
| 1529 | Box::new(Call("<", vec![Sym("x"), Int(0)])), | ||
| 1530 | Box::new(Call("-", vec![Int(0), Sym("x")])), | ||
| 1531 | Some(Box::new(Sym("x"))), | ||
| 1532 | )], | ||
| 1533 | )], | ||
| 1534 | ), | ||
| 1304 | ]; | 1535 | ]; |
| 1305 | for (tokens, ast) in cases { | 1536 | for (tokens, ast) in cases { |
| 1306 | assert_eq!(parse(tokens.clone()), ast, "input: {tokens:?}"); | 1537 | assert_eq!(parse(tokens.clone()), ast, "input: {tokens:?}"); |
| @@ -1471,6 +1702,86 @@ fn test_span_let() { | |||
| 1471 | } | 1702 | } |
| 1472 | 1703 | ||
| 1473 | #[test] | 1704 | #[test] |
| 1705 | fn test_span_if() { | ||
| 1706 | // (if true 1 2) | ||
| 1707 | let lp = sp((1, 0, 0), (1, 1, 1)); | ||
| 1708 | let kw = sp((1, 1, 1), (1, 3, 3)); | ||
| 1709 | let cond = sp((1, 4, 4), (1, 8, 8)); | ||
| 1710 | let then_t = sp((1, 9, 9), (1, 10, 10)); | ||
| 1711 | let else_t = sp((1, 11, 11), (1, 12, 12)); | ||
| 1712 | let rp = sp((1, 12, 12), (1, 13, 13)); | ||
| 1713 | |||
| 1714 | let tokens = vec![ | ||
| 1715 | tsp(LeftPar, lp), | ||
| 1716 | tsp(Symbol("if"), kw), | ||
| 1717 | tsp(Symbol("true"), cond), | ||
| 1718 | tsp(Number("1"), then_t), | ||
| 1719 | tsp(Number("2"), else_t), | ||
| 1720 | tsp(RightPar, rp), | ||
| 1721 | ]; | ||
| 1722 | let prog = parse_sp(tokens.clone()); | ||
| 1723 | |||
| 1724 | assert_eq!( | ||
| 1725 | prog[0].span, | ||
| 1726 | sp((1, 0, 0), (1, 13, 13)), | ||
| 1727 | "input: {tokens:?}" | ||
| 1728 | ); | ||
| 1729 | if let Expr::If { | ||
| 1730 | condition, | ||
| 1731 | then_expr, | ||
| 1732 | else_expr, | ||
| 1733 | } = &prog[0].inner | ||
| 1734 | { | ||
| 1735 | assert_eq!(condition.span, cond, "input: {tokens:?}"); | ||
| 1736 | assert_eq!(then_expr.span, then_t, "input: {tokens:?}"); | ||
| 1737 | assert_eq!( | ||
| 1738 | else_expr.as_ref().unwrap().span, | ||
| 1739 | else_t, | ||
| 1740 | "input: {tokens:?}" | ||
| 1741 | ); | ||
| 1742 | } else { | ||
| 1743 | panic!("expected If, input: {tokens:?}"); | ||
| 1744 | } | ||
| 1745 | } | ||
| 1746 | |||
| 1747 | #[test] | ||
| 1748 | fn test_span_if_no_else() { | ||
| 1749 | // (if true 1) | ||
| 1750 | let lp = sp((1, 0, 0), (1, 1, 1)); | ||
| 1751 | let kw = sp((1, 1, 1), (1, 3, 3)); | ||
| 1752 | let cond = sp((1, 4, 4), (1, 8, 8)); | ||
| 1753 | let then_t = sp((1, 9, 9), (1, 10, 10)); | ||
| 1754 | let rp = sp((1, 10, 10), (1, 11, 11)); | ||
| 1755 | |||
| 1756 | let tokens = vec![ | ||
| 1757 | tsp(LeftPar, lp), | ||
| 1758 | tsp(Symbol("if"), kw), | ||
| 1759 | tsp(Symbol("true"), cond), | ||
| 1760 | tsp(Number("1"), then_t), | ||
| 1761 | tsp(RightPar, rp), | ||
| 1762 | ]; | ||
| 1763 | let prog = parse_sp(tokens.clone()); | ||
| 1764 | |||
| 1765 | assert_eq!( | ||
| 1766 | prog[0].span, | ||
| 1767 | sp((1, 0, 0), (1, 11, 11)), | ||
| 1768 | "input: {tokens:?}" | ||
| 1769 | ); | ||
| 1770 | if let Expr::If { | ||
| 1771 | condition, | ||
| 1772 | then_expr, | ||
| 1773 | else_expr, | ||
| 1774 | } = &prog[0].inner | ||
| 1775 | { | ||
| 1776 | assert_eq!(condition.span, cond, "input: {tokens:?}"); | ||
| 1777 | assert_eq!(then_expr.span, then_t, "input: {tokens:?}"); | ||
| 1778 | assert!(else_expr.is_none(), "input: {tokens:?}"); | ||
| 1779 | } else { | ||
| 1780 | panic!("expected If, input: {tokens:?}"); | ||
| 1781 | } | ||
| 1782 | } | ||
| 1783 | |||
| 1784 | #[test] | ||
| 1474 | fn test_span_for() { | 1785 | fn test_span_for() { |
| 1475 | // (for i from 0 to 10 i) | 1786 | // (for i from 0 to 10 i) |
| 1476 | let lp = sp((1, 0, 0), (1, 1, 1)); | 1787 | let lp = sp((1, 0, 0), (1, 1, 1)); |
