sphinx/parser/
lvalue.rs

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// TODO rename to Pattern?
17#[derive(Debug, Clone)]
18pub enum LValue {
19    Identifier(InternSymbol),
20    Attribute(Box<AttributeTarget>), // receiver, attribute name
21    Index(Box<IndexTarget>), // receiver, index expression
22    Tuple(Box<[LValue]>),
23    Pack(Option<Box<LValue>>),
24    
25    Modifier {
26        modifier: AssignType,
27        lvalue: Box<LValue>,
28    },
29}
30
31// LValue Data
32
33#[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// Assignments
46
47#[derive(Debug, Clone)]
48pub struct Assignment {
49    pub lhs: LValue,
50    pub modifier: AssignType,
51    pub op: Option<BinaryOp>, // e.g. for +=, -=, *=, ...
52    pub rhs: Expr,
53}
54
55// Convert expressions to LValues...
56
57/*
58    lvalue ::= identifier | primary index-access | primary member-access ;
59
60    lvalue-expression ::= lvalue | lvalue-list | "(" lvalue ")" ;   (* basically just lvalues, and tuples of lvalues *)
61    lvalue-list ::= lvalue-expression ( "," lvalue-expression )* ;
62*/
63
64pub 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        // remove the last item so that primary will eval to the reciever
94        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}