sphinx/parser/
expr.rs

1use crate::debug::DebugSymbol;
2use crate::parser::operator::{BinaryOp, UnaryOp};
3use crate::parser::primary::{Atom, Primary};
4use crate::parser::lvalue::Assignment;
5use crate::parser::fundefs::FunctionDef;
6use crate::parser::stmt::{StmtMeta, Stmt, Label, StmtList};
7
8// TODO replace Vecs with boxed slices
9#[derive(Debug, Clone)]
10pub enum Expr {
11    
12    Atom(Atom),
13    
14    Primary(Primary),
15    
16    UnaryOp(UnaryOp, Box<Expr>),
17    
18    BinaryOp(BinaryOp, Box<(Expr, Expr)>),
19    
20    Assignment(Box<Assignment>),
21    
22    Tuple(Box<[ExprMeta]>),
23    
24    Unpack(Option<Box<Expr>>),
25    
26    // ObjectCtor(Box<ObjectConstructor>),
27    
28    IfExpr {
29        branches: Box<[ConditionalBranch]>,
30        else_clause: Option<Box<ExprBlock>>,
31    },
32    
33    Block {
34        label: Option<Label>, 
35        suite: Box<ExprBlock>,
36    },
37    
38    FunctionDef(FunctionDef),
39    
40    // ClassDef
41    
42}
43
44
45/// represents a statement list used as an expression
46#[derive(Debug, Clone)]
47pub struct ExprBlock {
48    stmt_list: StmtList,
49    result: Option<ExprMeta>,
50}
51
52impl From<StmtList> for ExprBlock {
53    fn from(stmt_list: StmtList) -> Self {
54        let (mut suite, control) = stmt_list.take();
55        
56        let mut result = None;
57        if control.is_none() && !suite.is_empty() {
58            match ExprMeta::try_from(suite.pop().unwrap()) {
59                Err(stmt) => suite.push(stmt), // put it back
60                Ok(expr) => { result.replace(expr); },
61            }
62        }
63        
64        let stmt_list = StmtList::new(suite, control);
65        Self { stmt_list, result }
66    }
67}
68
69impl ExprBlock {
70    pub fn stmt_list(&self) -> &StmtList { &self.stmt_list }
71    pub fn result(&self) -> Option<&ExprMeta> { self.result.as_ref() }
72}
73
74
75
76#[derive(Debug, Clone)]
77pub struct ConditionalBranch {
78    condition: Expr,
79    suite: ExprBlock,
80}
81
82impl ConditionalBranch {
83    pub fn new(condition: Expr, suite: ExprBlock) -> Self {
84        Self { condition, suite }
85    }
86    
87    pub fn condition(&self) -> &Expr { &self.condition }
88    pub fn suite(&self) -> &ExprBlock { &self.suite }
89}
90
91
92/// An `Expr` plus a `DebugSymbol`
93#[derive(Debug, Clone)]
94pub struct ExprMeta {
95    variant: Expr,
96    symbol: DebugSymbol,
97}
98
99impl ExprMeta {
100    pub fn new(variant: Expr, symbol: DebugSymbol) -> Self {
101        ExprMeta { variant, symbol }
102    }
103    
104    pub fn variant(&self) -> &Expr { &self.variant }
105    pub fn take_variant(self) -> Expr { self.variant }
106    
107    pub fn debug_symbol(&self) -> &DebugSymbol { &self.symbol }
108    pub fn take_symbol(self) -> DebugSymbol { self.symbol }
109    
110    pub fn take(self) -> (Expr, DebugSymbol) { (self.variant, self.symbol) }
111}
112
113impl From<ExprMeta> for (Expr, DebugSymbol) {
114    fn from(expr: ExprMeta) -> Self { (expr.variant, expr.symbol) }
115}
116
117
118
119// conversion to/from expression-statements
120
121impl From<Expr> for Stmt {
122    #[inline]
123    fn from(expr: Expr) -> Self { Stmt::Expression(expr) }
124}
125
126impl TryFrom<Stmt> for Expr {
127    type Error = Stmt;
128    
129    #[inline]
130    fn try_from(stmt: Stmt) -> Result<Self, Stmt> {
131        if let Stmt::Expression(expr) = stmt { Ok(expr) }
132        else { Err(stmt) }
133    }
134}
135
136impl TryFrom<StmtMeta> for Expr {
137    type Error = StmtMeta;
138    
139    #[inline]
140    fn try_from(stmt: StmtMeta) -> Result<Self, StmtMeta> {
141        let (stmt, symbol) = stmt.take();
142        if let Stmt::Expression(expr) = stmt { Ok(expr) }
143        else { Err(StmtMeta::new(stmt, symbol)) }
144    }
145}
146
147
148impl From<ExprMeta> for StmtMeta {
149    #[inline]
150    fn from(expr: ExprMeta) -> Self {
151        let (expr, symbol) = expr.take();
152        StmtMeta::new(expr.into(), symbol)
153    }
154}
155
156impl TryFrom<StmtMeta> for ExprMeta {
157    type Error = StmtMeta;
158    
159    #[inline]
160    fn try_from(stmt: StmtMeta) -> Result<Self, StmtMeta> {
161        let (stmt, symbol) = stmt.take();
162        match Expr::try_from(stmt) {
163            Ok(expr) => Ok(ExprMeta::new(expr, symbol)),
164            Err(stmt) => Err(StmtMeta::new(stmt, symbol)),
165        }
166    }
167}