1use serde::{Deserialize, Serialize};
4use std::fmt;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
8pub struct Span {
9 pub start: usize,
10 pub end: usize,
11}
12
13impl Span {
14 #[must_use]
15 pub fn new(start: usize, end: usize) -> Self {
16 Self { start, end }
17 }
18
19 #[must_use]
20 pub fn merge(self, other: Self) -> Self {
21 Self {
22 start: self.start.min(other.start),
23 end: self.end.max(other.end),
24 }
25 }
26}
27
28#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
30pub struct CatchClause {
31 pub pattern: Pattern, pub body: Box<Expr>, }
34
35#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
37pub struct Expr {
38 pub kind: ExprKind,
39 pub span: Span,
40 pub attributes: Vec<Attribute>,
41}
42
43impl Expr {
44 #[must_use]
45 pub fn new(kind: ExprKind, span: Span) -> Self {
46 Self {
47 kind,
48 span,
49 attributes: Vec::new(),
50 }
51 }
52
53 #[must_use]
54 pub fn with_attributes(kind: ExprKind, span: Span, attributes: Vec<Attribute>) -> Self {
55 Self {
56 kind,
57 span,
58 attributes,
59 }
60 }
61}
62
63#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
64pub enum ExprKind {
65 Literal(Literal),
66 Identifier(String),
67 QualifiedName {
68 module: String,
69 name: String,
70 },
71 StringInterpolation {
72 parts: Vec<StringPart>,
73 },
74 Binary {
75 left: Box<Expr>,
76 op: BinaryOp,
77 right: Box<Expr>,
78 },
79 Unary {
80 op: UnaryOp,
81 operand: Box<Expr>,
82 },
83 Throw {
84 expr: Box<Expr>,
85 },
86 TryCatch {
87 try_block: Box<Expr>,
88 catch_clauses: Vec<CatchClause>,
89 finally_block: Option<Box<Expr>>,
90 },
91 Ok {
92 value: Box<Expr>,
93 },
94 Err {
95 error: Box<Expr>,
96 },
97 Some {
98 value: Box<Expr>,
99 },
100 None,
101 TypeCast {
102 expr: Box<Expr>,
103 target_type: String,
104 },
105 Try {
106 expr: Box<Expr>,
107 },
108 Await {
109 expr: Box<Expr>,
110 },
111 AsyncBlock {
112 body: Box<Expr>,
113 },
114 If {
115 condition: Box<Expr>,
116 then_branch: Box<Expr>,
117 else_branch: Option<Box<Expr>>,
118 },
119 IfLet {
120 pattern: Pattern,
121 expr: Box<Expr>,
122 then_branch: Box<Expr>,
123 else_branch: Option<Box<Expr>>,
124 },
125 Let {
126 name: String,
127 type_annotation: Option<Type>,
128 value: Box<Expr>,
129 body: Box<Expr>,
130 is_mutable: bool,
131 },
132 LetPattern {
133 pattern: Pattern,
134 type_annotation: Option<Type>,
135 value: Box<Expr>,
136 body: Box<Expr>,
137 is_mutable: bool,
138 },
139 Function {
140 name: String,
141 type_params: Vec<String>,
142 params: Vec<Param>,
143 return_type: Option<Type>,
144 body: Box<Expr>,
145 is_async: bool,
146 is_pub: bool,
147 },
148 Lambda {
149 params: Vec<Param>,
150 body: Box<Expr>,
151 },
152 Struct {
153 name: String,
154 type_params: Vec<String>,
155 fields: Vec<StructField>,
156 is_pub: bool,
157 },
158 Enum {
159 name: String,
160 type_params: Vec<String>,
161 variants: Vec<EnumVariant>,
162 is_pub: bool,
163 },
164 StructLiteral {
165 name: String,
166 fields: Vec<(String, Expr)>,
167 },
168 ObjectLiteral {
169 fields: Vec<ObjectField>,
170 },
171 FieldAccess {
172 object: Box<Expr>,
173 field: String,
174 },
175 OptionalFieldAccess {
176 object: Box<Expr>,
177 field: String,
178 },
179 IndexAccess {
180 object: Box<Expr>,
181 index: Box<Expr>,
182 },
183 Slice {
184 object: Box<Expr>,
185 start: Option<Box<Expr>>,
186 end: Option<Box<Expr>>,
187 },
188 Trait {
189 name: String,
190 type_params: Vec<String>,
191 methods: Vec<TraitMethod>,
192 is_pub: bool,
193 },
194 Impl {
195 type_params: Vec<String>,
196 trait_name: Option<String>,
197 for_type: String,
198 methods: Vec<ImplMethod>,
199 is_pub: bool,
200 },
201 Actor {
202 name: String,
203 state: Vec<StructField>,
204 handlers: Vec<ActorHandler>,
205 },
206 Send {
207 actor: Box<Expr>,
208 message: Box<Expr>,
209 },
210 Command {
211 program: String,
212 args: Vec<String>,
213 env: Vec<(String, String)>,
214 working_dir: Option<String>,
215 },
216 Ask {
217 actor: Box<Expr>,
218 message: Box<Expr>,
219 timeout: Option<Box<Expr>>,
220 },
221 ActorSend {
223 actor: Box<Expr>,
224 message: Box<Expr>,
225 },
226 ActorQuery {
228 actor: Box<Expr>,
229 message: Box<Expr>,
230 },
231 Call {
232 func: Box<Expr>,
233 args: Vec<Expr>,
234 },
235 Macro {
236 name: String,
237 args: Vec<Expr>,
238 },
239 MethodCall {
240 receiver: Box<Expr>,
241 method: String,
242 args: Vec<Expr>,
243 },
244 OptionalMethodCall {
245 receiver: Box<Expr>,
246 method: String,
247 args: Vec<Expr>,
248 },
249 Block(Vec<Expr>),
250 Pipeline {
251 expr: Box<Expr>,
252 stages: Vec<PipelineStage>,
253 },
254 Match {
255 expr: Box<Expr>,
256 arms: Vec<MatchArm>,
257 },
258 List(Vec<Expr>),
259 ArrayInit {
260 value: Box<Expr>,
261 size: Box<Expr>,
262 },
263 Tuple(Vec<Expr>),
264 Spread {
265 expr: Box<Expr>,
266 },
267 ListComprehension {
268 element: Box<Expr>,
269 variable: String,
270 iterable: Box<Expr>,
271 condition: Option<Box<Expr>>,
272 },
273 DataFrame {
274 columns: Vec<DataFrameColumn>,
275 },
276 DataFrameOperation {
277 source: Box<Expr>,
278 operation: DataFrameOp,
279 },
280 For {
281 var: String, pattern: Option<Pattern>, iter: Box<Expr>,
284 body: Box<Expr>,
285 },
286 While {
287 condition: Box<Expr>,
288 body: Box<Expr>,
289 },
290 WhileLet {
291 pattern: Pattern,
292 expr: Box<Expr>,
293 body: Box<Expr>,
294 },
295 Loop {
296 body: Box<Expr>,
297 },
298 Range {
299 start: Box<Expr>,
300 end: Box<Expr>,
301 inclusive: bool,
302 },
303 Import {
304 path: String,
305 items: Vec<ImportItem>,
306 },
307 Module {
308 name: String,
309 body: Box<Expr>,
310 },
311 Export {
312 items: Vec<String>,
313 },
314 Break {
315 label: Option<String>,
316 },
317 Continue {
318 label: Option<String>,
319 },
320 Return {
321 value: Option<Box<Expr>>,
322 },
323 Assign {
324 target: Box<Expr>,
325 value: Box<Expr>,
326 },
327 CompoundAssign {
328 target: Box<Expr>,
329 op: BinaryOp,
330 value: Box<Expr>,
331 },
332 PreIncrement {
333 target: Box<Expr>,
334 },
335 PostIncrement {
336 target: Box<Expr>,
337 },
338 PreDecrement {
339 target: Box<Expr>,
340 },
341 PostDecrement {
342 target: Box<Expr>,
343 },
344 Extension {
345 target_type: String,
346 methods: Vec<ImplMethod>,
347 },
348}
349
350#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
351pub enum Literal {
352 Integer(i64),
353 Float(f64),
354 String(String),
355 Bool(bool),
356 Char(char),
357 Unit,
358}
359
360impl Literal {
361 pub fn from_value(value: &crate::runtime::repl::Value) -> Self {
363 use crate::runtime::repl::Value;
364 match value {
365 Value::Int(i) => Literal::Integer(*i),
366 Value::Float(f) => Literal::Float(*f),
367 Value::String(s) => Literal::String(s.clone()),
368 Value::Bool(b) => Literal::Bool(*b),
369 Value::Char(c) => Literal::Char(*c),
370 Value::Unit => Literal::Unit,
371 _ => Literal::Unit, }
373 }
374}
375
376#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
378pub enum StringPart {
379 Text(String),
381 Expr(Box<Expr>),
383 ExprWithFormat {
385 expr: Box<Expr>,
386 format_spec: String,
387 },
388}
389
390#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
391pub enum BinaryOp {
392 Add,
394 Subtract,
395 Multiply,
396 Divide,
397 Modulo,
398 Power,
399
400 Equal,
402 NotEqual,
403 Less,
404 LessEqual,
405 Greater,
406 GreaterEqual,
407
408 And,
410 Or,
411 NullCoalesce,
412
413 BitwiseAnd,
415 BitwiseOr,
416 BitwiseXor,
417 LeftShift,
418}
419
420#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
421pub enum UnaryOp {
422 Not,
423 Negate,
424 BitwiseNot,
425 Reference,
426}
427
428#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
429pub struct Param {
430 pub pattern: Pattern,
431 pub ty: Type,
432 pub span: Span,
433 pub is_mutable: bool,
434 pub default_value: Option<Box<Expr>>,
435}
436
437impl Param {
438 #[must_use]
442 pub fn name(&self) -> String {
443 self.pattern.primary_name()
444 }
445}
446
447#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
448pub struct StructField {
449 pub name: String,
450 pub ty: Type,
451 pub is_pub: bool,
452}
453
454#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
455pub struct EnumVariant {
456 pub name: String,
457 pub fields: Option<Vec<Type>>, pub discriminant: Option<i64>, }
460
461#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
462pub enum ObjectField {
463 KeyValue { key: String, value: Expr },
464 Spread { expr: Expr },
465}
466
467#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
468pub struct TraitMethod {
469 pub name: String,
470 pub params: Vec<Param>,
471 pub return_type: Option<Type>,
472 pub body: Option<Box<Expr>>, pub is_pub: bool,
474}
475
476#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
477pub struct ImplMethod {
478 pub name: String,
479 pub params: Vec<Param>,
480 pub return_type: Option<Type>,
481 pub body: Box<Expr>,
482 pub is_pub: bool,
483}
484
485#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
486pub struct ActorHandler {
487 pub message_type: String,
488 pub params: Vec<Param>,
489 pub body: Box<Expr>,
490}
491
492#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
493pub struct Type {
494 pub kind: TypeKind,
495 pub span: Span,
496}
497
498#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
499pub enum TypeKind {
500 Named(String),
501 Generic { base: String, params: Vec<Type> },
502 Optional(Box<Type>),
503 List(Box<Type>),
504 Array { elem_type: Box<Type>, size: usize },
505 Tuple(Vec<Type>),
506 Function { params: Vec<Type>, ret: Box<Type> },
507 DataFrame { columns: Vec<(String, Type)> },
508 Series { dtype: Box<Type> },
509 Reference { is_mut: bool, inner: Box<Type> },
510}
511
512#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
513pub struct PipelineStage {
514 pub op: Box<Expr>,
515 pub span: Span,
516}
517
518#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
519pub struct MatchArm {
520 pub pattern: Pattern,
521 pub guard: Option<Box<Expr>>, pub body: Box<Expr>,
523 pub span: Span,
524}
525
526#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
527pub enum Pattern {
528 Wildcard,
529 Literal(Literal),
530 Identifier(String),
531 QualifiedName(Vec<String>), Tuple(Vec<Pattern>),
533 List(Vec<Pattern>),
534 Struct {
535 name: String,
536 fields: Vec<StructPatternField>,
537 has_rest: bool,
538 },
539 Range {
540 start: Box<Pattern>,
541 end: Box<Pattern>,
542 inclusive: bool,
543 },
544 Or(Vec<Pattern>),
545 Rest, RestNamed(String), WithDefault {
548 pattern: Box<Pattern>,
549 default: Box<Expr>,
550 }, Ok(Box<Pattern>),
552 Err(Box<Pattern>),
553 Some(Box<Pattern>),
554 None,
555}
556
557impl Pattern {
558 #[must_use]
561 pub fn primary_name(&self) -> String {
562 match self {
563 Pattern::Identifier(name) => name.clone(),
564 Pattern::QualifiedName(path) => path.join("::"),
565 Pattern::Tuple(patterns) => {
566 patterns
568 .first()
569 .map_or_else(|| "_tuple".to_string(), Pattern::primary_name)
570 }
571 Pattern::List(patterns) => {
572 patterns
574 .first()
575 .map_or_else(|| "_list".to_string(), Pattern::primary_name)
576 }
577 Pattern::Struct { name, fields, .. } => {
578 if name.is_empty() {
580 fields.first().map_or_else(|| "_struct".to_string(), |f| f.name.clone())
581 } else {
582 name.clone()
583 }
584 }
585 Pattern::Ok(inner) | Pattern::Err(inner) | Pattern::Some(inner) => inner.primary_name(),
586 Pattern::None => "_none".to_string(),
587 Pattern::Or(patterns) => {
588 patterns
590 .first()
591 .map_or_else(|| "_or".to_string(), Pattern::primary_name)
592 }
593 Pattern::Wildcard => "_".to_string(),
594 Pattern::Rest => "_rest".to_string(),
595 Pattern::RestNamed(name) => name.clone(),
596 Pattern::WithDefault { pattern, .. } => pattern.primary_name(),
597 Pattern::Literal(lit) => format!("_literal_{lit:?}"),
598 Pattern::Range { .. } => "_range".to_string(),
599 }
600 }
601}
602
603#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
604pub struct StructPatternField {
605 pub name: String,
606 pub pattern: Option<Pattern>, }
608
609
610#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
612pub struct ErrorTypeDef {
613 pub name: String,
614 pub fields: Vec<StructField>,
615 pub extends: Option<String>, }
617
618#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
620pub struct Attribute {
621 pub name: String,
622 pub args: Vec<String>,
623 pub span: Span,
624}
625
626#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
627pub struct DataFrameColumn {
628 pub name: String,
629 pub values: Vec<Expr>,
630}
631
632#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
633pub enum DataFrameOp {
634 Filter(Box<Expr>),
635 Select(Vec<String>),
636 GroupBy(Vec<String>),
637 Sort(Vec<String>),
638 Join {
639 other: Box<Expr>,
640 on: Vec<String>,
641 how: JoinType,
642 },
643 Aggregate(Vec<AggregateOp>),
644 Limit(usize),
645 Head(usize),
646 Tail(usize),
647}
648
649#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
650pub enum JoinType {
651 Inner,
652 Left,
653 Right,
654 Outer,
655}
656
657#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
658pub enum ImportItem {
659 Named(String),
661 Aliased { name: String, alias: String },
663 Wildcard,
665}
666
667impl ImportItem {
668 pub fn is_url_import(path: &str) -> bool {
670 path.starts_with("https://") || path.starts_with("http://")
671 }
672}
673
674#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
675pub enum AggregateOp {
676 Sum(String),
677 Mean(String),
678 Min(String),
679 Max(String),
680 Count(String),
681 Std(String),
682 Var(String),
683}
684
685impl fmt::Display for BinaryOp {
686 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
687 match self {
688 Self::Add => write!(f, "+"),
689 Self::Subtract => write!(f, "-"),
690 Self::Multiply => write!(f, "*"),
691 Self::Divide => write!(f, "/"),
692 Self::Modulo => write!(f, "%"),
693 Self::Power => write!(f, "**"),
694 Self::Equal => write!(f, "=="),
695 Self::NotEqual => write!(f, "!="),
696 Self::Less => write!(f, "<"),
697 Self::LessEqual => write!(f, "<="),
698 Self::Greater => write!(f, ">"),
699 Self::GreaterEqual => write!(f, ">="),
700 Self::And => write!(f, "&&"),
701 Self::Or => write!(f, "||"),
702 Self::NullCoalesce => write!(f, "??"),
703 Self::BitwiseAnd => write!(f, "&"),
704 Self::BitwiseOr => write!(f, "|"),
705 Self::BitwiseXor => write!(f, "^"),
706 Self::LeftShift => write!(f, "<<"),
707 }
708 }
709}
710
711impl fmt::Display for UnaryOp {
712 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
713 match self {
714 Self::Not => write!(f, "!"),
715 Self::Negate => write!(f, "-"),
716 Self::BitwiseNot => write!(f, "~"),
717 Self::Reference => write!(f, "&"),
718 }
719 }
720}
721
722#[cfg(test)]
723#[allow(clippy::unwrap_used, clippy::panic, clippy::expect_used)]
724#[allow(clippy::unwrap_used)]
725#[allow(clippy::panic)]
726mod tests {
727 use super::*;
728 use proptest::prelude::*;
729
730 proptest! {
731 #[test]
732 fn test_span_merge(start1 in 0usize..1000, end1 in 0usize..1000,
733 start2 in 0usize..1000, end2 in 0usize..1000) {
734 let span1 = Span::new(start1, end1);
735 let span2 = Span::new(start2, end2);
736 let merged = span1.merge(span2);
737
738 prop_assert!(merged.start <= span1.start);
739 prop_assert!(merged.start <= span2.start);
740 prop_assert!(merged.end >= span1.end);
741 prop_assert!(merged.end >= span2.end);
742 }
743 }
744
745 #[test]
746 fn test_ast_size() {
747 let expr_size = std::mem::size_of::<Expr>();
749 let kind_size = std::mem::size_of::<ExprKind>();
750 assert!(expr_size <= 192, "Expr too large: {expr_size} bytes");
753 assert!(kind_size <= 152, "ExprKind too large: {kind_size} bytes");
754 }
755
756 #[test]
757 fn test_span_creation() {
758 let span = Span::new(10, 20);
759 assert_eq!(span.start, 10);
760 assert_eq!(span.end, 20);
761 }
762
763 #[test]
764 fn test_span_merge_simple() {
765 let span1 = Span::new(5, 10);
766 let span2 = Span::new(8, 15);
767 let merged = span1.merge(span2);
768 assert_eq!(merged.start, 5);
769 assert_eq!(merged.end, 15);
770 }
771
772 #[test]
773 fn test_span_merge_disjoint() {
774 let span1 = Span::new(0, 5);
775 let span2 = Span::new(10, 15);
776 let merged = span1.merge(span2);
777 assert_eq!(merged.start, 0);
778 assert_eq!(merged.end, 15);
779 }
780
781 #[test]
782 fn test_expr_creation() {
783 let span = Span::new(0, 10);
784 let expr = Expr::new(ExprKind::Literal(Literal::Integer(42)), span);
785 assert_eq!(expr.span.start, 0);
786 assert_eq!(expr.span.end, 10);
787 match expr.kind {
788 ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 42),
789 _ => panic!("Wrong expression kind"),
790 }
791 }
792
793 #[test]
794 fn test_literal_variants() {
795 let literals = vec![
796 Literal::Integer(42),
797 #[allow(clippy::approx_constant)]
798 Literal::Float(3.14), Literal::String("hello".to_string()),
800 Literal::Bool(true),
801 Literal::Unit,
802 ];
803
804 for lit in literals {
805 let expr = Expr::new(ExprKind::Literal(lit.clone()), Span::new(0, 0));
806 match expr.kind {
807 ExprKind::Literal(l) => assert_eq!(l, lit),
808 _ => panic!("Expected literal"),
809 }
810 }
811 }
812
813 #[test]
814 fn test_binary_op_display() {
815 assert_eq!(BinaryOp::Add.to_string(), "+");
816 assert_eq!(BinaryOp::Subtract.to_string(), "-");
817 assert_eq!(BinaryOp::Multiply.to_string(), "*");
818 assert_eq!(BinaryOp::Divide.to_string(), "/");
819 assert_eq!(BinaryOp::Modulo.to_string(), "%");
820 assert_eq!(BinaryOp::Power.to_string(), "**");
821 assert_eq!(BinaryOp::Equal.to_string(), "==");
822 assert_eq!(BinaryOp::NotEqual.to_string(), "!=");
823 assert_eq!(BinaryOp::Less.to_string(), "<");
824 assert_eq!(BinaryOp::LessEqual.to_string(), "<=");
825 assert_eq!(BinaryOp::Greater.to_string(), ">");
826 assert_eq!(BinaryOp::GreaterEqual.to_string(), ">=");
827 assert_eq!(BinaryOp::And.to_string(), "&&");
828 assert_eq!(BinaryOp::Or.to_string(), "||");
829 assert_eq!(BinaryOp::BitwiseAnd.to_string(), "&");
830 assert_eq!(BinaryOp::BitwiseOr.to_string(), "|");
831 assert_eq!(BinaryOp::BitwiseXor.to_string(), "^");
832 assert_eq!(BinaryOp::LeftShift.to_string(), "<<");
833 }
834
835 #[test]
836 fn test_unary_op_display() {
837 assert_eq!(UnaryOp::Not.to_string(), "!");
838 assert_eq!(UnaryOp::Negate.to_string(), "-");
839 assert_eq!(UnaryOp::BitwiseNot.to_string(), "~");
840 assert_eq!(UnaryOp::Reference.to_string(), "&");
841 }
842
843 #[test]
844 fn test_binary_expression() {
845 let left = Box::new(Expr::new(
846 ExprKind::Literal(Literal::Integer(1)),
847 Span::new(0, 1),
848 ));
849 let right = Box::new(Expr::new(
850 ExprKind::Literal(Literal::Integer(2)),
851 Span::new(4, 5),
852 ));
853 let expr = Expr::new(
854 ExprKind::Binary {
855 left,
856 op: BinaryOp::Add,
857 right,
858 },
859 Span::new(0, 5),
860 );
861
862 match expr.kind {
863 ExprKind::Binary {
864 left: l,
865 op,
866 right: r,
867 } => {
868 assert_eq!(op, BinaryOp::Add);
869 match l.kind {
870 ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 1),
871 _ => panic!("Wrong left operand"),
872 }
873 match r.kind {
874 ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 2),
875 _ => panic!("Wrong right operand"),
876 }
877 }
878 _ => panic!("Expected binary expression"),
879 }
880 }
881
882 #[test]
883 fn test_unary_expression() {
884 let operand = Box::new(Expr::new(
885 ExprKind::Literal(Literal::Bool(true)),
886 Span::new(1, 5),
887 ));
888 let expr = Expr::new(
889 ExprKind::Unary {
890 op: UnaryOp::Not,
891 operand,
892 },
893 Span::new(0, 5),
894 );
895
896 match expr.kind {
897 ExprKind::Unary { op, operand } => {
898 assert_eq!(op, UnaryOp::Not);
899 match operand.kind {
900 ExprKind::Literal(Literal::Bool(b)) => assert!(b),
901 _ => panic!("Wrong operand"),
902 }
903 }
904 _ => panic!("Expected unary expression"),
905 }
906 }
907
908 #[test]
909 fn test_if_expression() {
910 let condition = Box::new(Expr::new(
911 ExprKind::Literal(Literal::Bool(true)),
912 Span::new(3, 7),
913 ));
914 let then_branch = Box::new(Expr::new(
915 ExprKind::Literal(Literal::Integer(1)),
916 Span::new(10, 11),
917 ));
918 let else_branch = Some(Box::new(Expr::new(
919 ExprKind::Literal(Literal::Integer(2)),
920 Span::new(17, 18),
921 )));
922
923 let expr = Expr::new(
924 ExprKind::If {
925 condition,
926 then_branch,
927 else_branch,
928 },
929 Span::new(0, 18),
930 );
931
932 match expr.kind {
933 ExprKind::If {
934 condition: c,
935 then_branch: t,
936 else_branch: e,
937 } => {
938 match c.kind {
939 ExprKind::Literal(Literal::Bool(b)) => assert!(b),
940 _ => panic!("Wrong condition"),
941 }
942 match t.kind {
943 ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 1),
944 _ => panic!("Wrong then branch"),
945 }
946 assert!(e.is_some());
947 if let Some(else_expr) = e {
948 match else_expr.kind {
949 ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 2),
950 _ => panic!("Wrong else branch"),
951 }
952 }
953 }
954 _ => panic!("Expected if expression"),
955 }
956 }
957
958 #[test]
959 fn test_let_expression() {
960 let value = Box::new(Expr::new(
961 ExprKind::Literal(Literal::Integer(42)),
962 Span::new(8, 10),
963 ));
964 let body = Box::new(Expr::new(
965 ExprKind::Identifier("x".to_string()),
966 Span::new(14, 15),
967 ));
968
969 let expr = Expr::new(
970 ExprKind::Let {
971 name: "x".to_string(),
972 type_annotation: None,
973 value,
974 body,
975 is_mutable: false,
976 },
977 Span::new(0, 15),
978 );
979
980 match expr.kind {
981 ExprKind::Let {
982 name,
983 value: v,
984 body: b,
985 ..
986 } => {
987 assert_eq!(name, "x");
988 match v.kind {
989 ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 42),
990 _ => panic!("Wrong value"),
991 }
992 match b.kind {
993 ExprKind::Identifier(id) => assert_eq!(id, "x"),
994 _ => panic!("Wrong body"),
995 }
996 }
997 _ => panic!("Expected let expression"),
998 }
999 }
1000
1001 #[test]
1002 fn test_function_expression() {
1003 let params = vec![Param {
1004 pattern: Pattern::Identifier("x".to_string()),
1005 ty: Type {
1006 kind: TypeKind::Named("i32".to_string()),
1007 span: Span::new(10, 13),
1008 },
1009 span: Span::new(8, 13),
1010 is_mutable: false,
1011 default_value: None,
1012 }];
1013 let body = Box::new(Expr::new(
1014 ExprKind::Identifier("x".to_string()),
1015 Span::new(20, 21),
1016 ));
1017
1018 let expr = Expr::new(
1019 ExprKind::Function {
1020 name: "identity".to_string(),
1021 type_params: vec![],
1022 params,
1023 return_type: Some(Type {
1024 kind: TypeKind::Named("i32".to_string()),
1025 span: Span::new(16, 19),
1026 }),
1027 body,
1028 is_async: false,
1029 is_pub: false,
1030 },
1031 Span::new(0, 22),
1032 );
1033
1034 match expr.kind {
1035 ExprKind::Function {
1036 name,
1037 params: p,
1038 return_type,
1039 body: b,
1040 ..
1041 } => {
1042 assert_eq!(name, "identity");
1043 assert_eq!(p.len(), 1);
1044 assert_eq!(p[0].name(), "x");
1045 assert!(return_type.is_some());
1046 match b.kind {
1047 ExprKind::Identifier(id) => assert_eq!(id, "x"),
1048 _ => panic!("Wrong body"),
1049 }
1050 }
1051 _ => panic!("Expected function expression"),
1052 }
1053 }
1054
1055 #[test]
1056 fn test_call_expression() {
1057 let func = Box::new(Expr::new(
1058 ExprKind::Identifier("add".to_string()),
1059 Span::new(0, 3),
1060 ));
1061 let args = vec![
1062 Expr::new(ExprKind::Literal(Literal::Integer(1)), Span::new(4, 5)),
1063 Expr::new(ExprKind::Literal(Literal::Integer(2)), Span::new(7, 8)),
1064 ];
1065
1066 let expr = Expr::new(ExprKind::Call { func, args }, Span::new(0, 9));
1067
1068 match expr.kind {
1069 ExprKind::Call { func: f, args: a } => {
1070 match f.kind {
1071 ExprKind::Identifier(name) => assert_eq!(name, "add"),
1072 _ => panic!("Wrong function"),
1073 }
1074 assert_eq!(a.len(), 2);
1075 }
1076 _ => panic!("Expected call expression"),
1077 }
1078 }
1079
1080 #[test]
1081 fn test_block_expression() {
1082 let exprs = vec![
1083 Expr::new(ExprKind::Literal(Literal::Integer(1)), Span::new(2, 3)),
1084 Expr::new(ExprKind::Literal(Literal::Integer(2)), Span::new(5, 6)),
1085 ];
1086
1087 let expr = Expr::new(ExprKind::Block(exprs), Span::new(0, 8));
1088
1089 match expr.kind {
1090 ExprKind::Block(block) => {
1091 assert_eq!(block.len(), 2);
1092 }
1093 _ => panic!("Expected block expression"),
1094 }
1095 }
1096
1097 #[test]
1098 fn test_list_expression() {
1099 let items = vec![
1100 Expr::new(ExprKind::Literal(Literal::Integer(1)), Span::new(1, 2)),
1101 Expr::new(ExprKind::Literal(Literal::Integer(2)), Span::new(4, 5)),
1102 Expr::new(ExprKind::Literal(Literal::Integer(3)), Span::new(7, 8)),
1103 ];
1104
1105 let expr = Expr::new(ExprKind::List(items), Span::new(0, 9));
1106
1107 match expr.kind {
1108 ExprKind::List(list) => {
1109 assert_eq!(list.len(), 3);
1110 }
1111 _ => panic!("Expected list expression"),
1112 }
1113 }
1114
1115 #[test]
1116 fn test_for_expression() {
1117 let iter = Box::new(Expr::new(
1118 ExprKind::Range {
1119 start: Box::new(Expr::new(
1120 ExprKind::Literal(Literal::Integer(0)),
1121 Span::new(10, 11),
1122 )),
1123 end: Box::new(Expr::new(
1124 ExprKind::Literal(Literal::Integer(10)),
1125 Span::new(13, 15),
1126 )),
1127 inclusive: false,
1128 },
1129 Span::new(10, 15),
1130 ));
1131 let body = Box::new(Expr::new(
1132 ExprKind::Identifier("i".to_string()),
1133 Span::new(20, 21),
1134 ));
1135
1136 let expr = Expr::new(
1137 ExprKind::For {
1138 var: "i".to_string(),
1139 pattern: None,
1140 iter,
1141 body,
1142 },
1143 Span::new(0, 22),
1144 );
1145
1146 match expr.kind {
1147 ExprKind::For {
1148 var,
1149 iter: it,
1150 body: b,
1151 ..
1152 } => {
1153 assert_eq!(var, "i");
1154 match it.kind {
1155 ExprKind::Range { .. } => {}
1156 _ => panic!("Wrong iterator"),
1157 }
1158 match b.kind {
1159 ExprKind::Identifier(id) => assert_eq!(id, "i"),
1160 _ => panic!("Wrong body"),
1161 }
1162 }
1163 _ => panic!("Expected for expression"),
1164 }
1165 }
1166
1167 #[test]
1168 fn test_range_expression() {
1169 let start = Box::new(Expr::new(
1170 ExprKind::Literal(Literal::Integer(1)),
1171 Span::new(0, 1),
1172 ));
1173 let end = Box::new(Expr::new(
1174 ExprKind::Literal(Literal::Integer(10)),
1175 Span::new(3, 5),
1176 ));
1177
1178 let expr = Expr::new(
1179 ExprKind::Range {
1180 start,
1181 end,
1182 inclusive: false,
1183 },
1184 Span::new(0, 5),
1185 );
1186
1187 match expr.kind {
1188 ExprKind::Range {
1189 start: s,
1190 end: e,
1191 inclusive,
1192 } => {
1193 assert!(!inclusive);
1194 match s.kind {
1195 ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 1),
1196 _ => panic!("Wrong start"),
1197 }
1198 match e.kind {
1199 ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 10),
1200 _ => panic!("Wrong end"),
1201 }
1202 }
1203 _ => panic!("Expected range expression"),
1204 }
1205 }
1206
1207 #[test]
1208 fn test_import_expression() {
1209 let expr = Expr::new(
1210 ExprKind::Import {
1211 path: "std::collections".to_string(),
1212 items: vec![
1213 ImportItem::Named("HashMap".to_string()),
1214 ImportItem::Named("HashSet".to_string()),
1215 ],
1216 },
1217 Span::new(0, 30),
1218 );
1219
1220 match expr.kind {
1221 ExprKind::Import { path, items } => {
1222 assert_eq!(path, "std::collections");
1223 assert_eq!(items.len(), 2);
1224 assert_eq!(items[0], ImportItem::Named("HashMap".to_string()));
1225 assert_eq!(items[1], ImportItem::Named("HashSet".to_string()));
1226 }
1227 _ => panic!("Expected import expression"),
1228 }
1229 }
1230
1231 #[test]
1232 fn test_pipeline_expression() {
1233 let expr_start = Box::new(Expr::new(
1234 ExprKind::List(vec![
1235 Expr::new(ExprKind::Literal(Literal::Integer(1)), Span::new(1, 2)),
1236 Expr::new(ExprKind::Literal(Literal::Integer(2)), Span::new(4, 5)),
1237 ]),
1238 Span::new(0, 6),
1239 ));
1240 let stages = vec![PipelineStage {
1241 op: Box::new(Expr::new(
1242 ExprKind::Identifier("filter".to_string()),
1243 Span::new(10, 16),
1244 )),
1245 span: Span::new(10, 16),
1246 }];
1247
1248 let expr = Expr::new(
1249 ExprKind::Pipeline {
1250 expr: expr_start,
1251 stages,
1252 },
1253 Span::new(0, 16),
1254 );
1255
1256 match expr.kind {
1257 ExprKind::Pipeline { expr: e, stages: s } => {
1258 assert_eq!(s.len(), 1);
1259 match e.kind {
1260 ExprKind::List(list) => assert_eq!(list.len(), 2),
1261 _ => panic!("Wrong pipeline start"),
1262 }
1263 }
1264 _ => panic!("Expected pipeline expression"),
1265 }
1266 }
1267
1268 #[test]
1269 fn test_match_expression() {
1270 let expr_to_match = Box::new(Expr::new(
1271 ExprKind::Identifier("x".to_string()),
1272 Span::new(6, 7),
1273 ));
1274 let arms = vec![
1275 MatchArm {
1276 pattern: Pattern::Literal(Literal::Integer(1)),
1277 guard: None,
1278 body: Box::new(Expr::new(
1279 ExprKind::Literal(Literal::String("one".to_string())),
1280 Span::new(15, 20),
1281 )),
1282 span: Span::new(10, 20),
1283 },
1284 MatchArm {
1285 pattern: Pattern::Wildcard,
1286 guard: None,
1287 body: Box::new(Expr::new(
1288 ExprKind::Literal(Literal::String("other".to_string())),
1289 Span::new(28, 35),
1290 )),
1291 span: Span::new(25, 35),
1292 },
1293 ];
1294
1295 let expr = Expr::new(
1296 ExprKind::Match {
1297 expr: expr_to_match,
1298 arms,
1299 },
1300 Span::new(0, 36),
1301 );
1302
1303 match expr.kind {
1304 ExprKind::Match { expr: e, arms: a } => {
1305 assert_eq!(a.len(), 2);
1306 match e.kind {
1307 ExprKind::Identifier(id) => assert_eq!(id, "x"),
1308 _ => panic!("Wrong match expression"),
1309 }
1310 }
1311 _ => panic!("Expected match expression"),
1312 }
1313 }
1314
1315 #[test]
1316 fn test_pattern_variants() {
1317 let patterns = vec![
1318 Pattern::Wildcard,
1319 Pattern::Literal(Literal::Integer(42)),
1320 Pattern::Identifier("x".to_string()),
1321 Pattern::Tuple(vec![
1322 Pattern::Literal(Literal::Integer(1)),
1323 Pattern::Identifier("x".to_string()),
1324 ]),
1325 Pattern::List(vec![
1326 Pattern::Literal(Literal::Integer(1)),
1327 Pattern::Literal(Literal::Integer(2)),
1328 ]),
1329 Pattern::Struct {
1330 name: "Point".to_string(),
1331 fields: vec![StructPatternField {
1332 name: "x".to_string(),
1333 pattern: Some(Pattern::Identifier("x".to_string())),
1334 }],
1335 has_rest: false,
1336 },
1337 Pattern::Range {
1338 start: Box::new(Pattern::Literal(Literal::Integer(1))),
1339 end: Box::new(Pattern::Literal(Literal::Integer(10))),
1340 inclusive: true,
1341 },
1342 Pattern::Or(vec![
1343 Pattern::Literal(Literal::Integer(1)),
1344 Pattern::Literal(Literal::Integer(2)),
1345 ]),
1346 Pattern::Rest,
1347 ];
1348
1349 for pattern in patterns {
1350 match pattern {
1351 Pattern::Tuple(list) | Pattern::List(list) => assert!(!list.is_empty()),
1352 Pattern::Struct { fields, .. } => assert!(!fields.is_empty()),
1353 Pattern::Or(patterns) => assert!(!patterns.is_empty()),
1354 Pattern::Range { .. }
1355 | Pattern::Wildcard
1356 | Pattern::Literal(_)
1357 | Pattern::Identifier(_)
1358 | Pattern::Rest
1359 | Pattern::RestNamed(_)
1360 | Pattern::Ok(_)
1361 | Pattern::Err(_)
1362 | Pattern::Some(_)
1363 | Pattern::None
1364 | Pattern::QualifiedName(_)
1365 | Pattern::WithDefault { .. } => {} }
1367 }
1368 }
1369
1370 #[test]
1371 fn test_type_kinds() {
1372 let types = vec![
1373 Type {
1374 kind: TypeKind::Named("i32".to_string()),
1375 span: Span::new(0, 3),
1376 },
1377 Type {
1378 kind: TypeKind::Optional(Box::new(Type {
1379 kind: TypeKind::Named("String".to_string()),
1380 span: Span::new(0, 6),
1381 })),
1382 span: Span::new(0, 7),
1383 },
1384 Type {
1385 kind: TypeKind::List(Box::new(Type {
1386 kind: TypeKind::Named("f64".to_string()),
1387 span: Span::new(1, 4),
1388 })),
1389 span: Span::new(0, 5),
1390 },
1391 Type {
1392 kind: TypeKind::Function {
1393 params: vec![Type {
1394 kind: TypeKind::Named("i32".to_string()),
1395 span: Span::new(0, 3),
1396 }],
1397 ret: Box::new(Type {
1398 kind: TypeKind::Named("String".to_string()),
1399 span: Span::new(7, 13),
1400 }),
1401 },
1402 span: Span::new(0, 13),
1403 },
1404 ];
1405
1406 for ty in types {
1407 match ty.kind {
1408 TypeKind::Named(name) => assert!(!name.is_empty()),
1409 TypeKind::Generic { base, params } => {
1410 assert!(!base.is_empty());
1411 assert!(!params.is_empty());
1412 }
1413 TypeKind::Optional(_) | TypeKind::List(_) | TypeKind::Series { .. } => {}
1414 TypeKind::Function { params, .. } => assert!(!params.is_empty()),
1415 TypeKind::DataFrame { columns } => assert!(!columns.is_empty()),
1416 TypeKind::Tuple(ref types) => assert!(!types.is_empty()),
1417 TypeKind::Reference { is_mut: _, ref inner } => {
1418 if let TypeKind::Named(ref name) = inner.kind {
1420 assert!(!name.is_empty());
1421 }
1422 }
1423 TypeKind::Array { elem_type: _, size } => {
1424 assert!(size > 0);
1426 }
1427 }
1428 }
1429 }
1430
1431 #[test]
1432 fn test_param_creation() {
1433 let param = Param {
1434 pattern: Pattern::Identifier("count".to_string()),
1435 ty: Type {
1436 kind: TypeKind::Named("usize".to_string()),
1437 span: Span::new(6, 11),
1438 },
1439 span: Span::new(0, 11),
1440 is_mutable: false,
1441 default_value: None,
1442 };
1443
1444 assert_eq!(param.name(), "count");
1445 match param.ty.kind {
1446 TypeKind::Named(name) => assert_eq!(name, "usize"),
1447 _ => panic!("Wrong type kind"),
1448 }
1449 }
1450}