1
2use crate::language::InternSymbol;
3use crate::parser::primary::{Primary, AccessItem, Atom};
4use crate::parser::operator::BinaryOp;
5use crate::parser::expr::{Expr, ExprMeta};
6
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub enum AssignType {
10 AssignLocal,
11 AssignNonLocal,
12 DeclImmutable,
13 DeclMutable,
14}
15
16#[derive(Debug, Clone)]
18pub enum LValue {
19 Identifier(InternSymbol),
20 Attribute(Box<AttributeTarget>), Index(Box<IndexTarget>), Tuple(Box<[LValue]>),
23 Pack(Option<Box<LValue>>),
24
25 Modifier {
26 modifier: AssignType,
27 lvalue: Box<LValue>,
28 },
29}
30
31#[derive(Debug, Clone)]
34pub struct AttributeTarget {
35 pub receiver: Primary,
36 pub name: InternSymbol,
37}
38
39#[derive(Debug, Clone)]
40pub struct IndexTarget {
41 pub receiver: Primary,
42 pub index: ExprMeta,
43}
44
45#[derive(Debug, Clone)]
48pub struct Assignment {
49 pub lhs: LValue,
50 pub modifier: AssignType,
51 pub op: Option<BinaryOp>, pub rhs: Expr,
53}
54
55pub struct IntoLValueError;
65
66impl TryFrom<Atom> for LValue {
67 type Error = IntoLValueError;
68 fn try_from(atom: Atom) -> Result<Self, Self::Error> {
69 match atom {
70 Atom::Identifier(name) => Ok(LValue::Identifier(name)),
71
72 Atom::Group { modifier, inner } => {
73 let lvalue = (*inner).try_into()?;
74
75 if let Some(modifier) = modifier {
76 Ok(Self::Modifier {
77 modifier,
78 lvalue: Box::new(lvalue),
79 })
80 } else {
81 Ok(lvalue)
82 }
83 },
84
85 _ => Err(IntoLValueError)
86 }
87 }
88}
89
90impl TryFrom<Primary> for LValue {
91 type Error = IntoLValueError;
92 fn try_from(primary: Primary) -> Result<Self, Self::Error> {
93 let (atom, mut path) = primary.take();
95 let tail = path.pop();
96 let receiver = Primary::new(atom, path);
97
98 let lvalue = match tail {
99 Some(AccessItem::Attribute(name))
100 => LValue::Attribute(Box::new(AttributeTarget { receiver, name })),
101 Some(AccessItem::Index(index))
102 => LValue::Index(Box::new(IndexTarget { receiver, index })),
103 _ => return Err(IntoLValueError),
104 };
105
106 Ok(lvalue)
107 }
108}
109
110impl TryFrom<Expr> for LValue {
111 type Error = IntoLValueError;
112 fn try_from(expr: Expr) -> Result<Self, Self::Error> {
113 match expr {
114 Expr::Atom(atom) => atom.try_into(),
115
116 Expr::Primary(primary) => primary.try_into(),
117
118 Expr::Unpack(Some(expr)) => {
119 let inner = LValue::try_from(*expr)?;
120 Ok(Self::Pack(Some(Box::new(inner))))
121 }
122 Expr::Unpack(None) => Ok(Self::Pack(None)),
123
124 Expr::Tuple(items) if !items.is_empty() => {
125 let mut lvalue_items = Vec::new();
126 for expr in items.into_vec().into_iter() {
127 let lvalue = LValue::try_from(expr.take_variant())?;
128 lvalue_items.push(lvalue);
129 }
130
131 Ok(Self::Tuple(lvalue_items.into_boxed_slice()))
132 },
133
134 _ => Err(IntoLValueError),
135 }
136 }
137}