py_ast/parse/
stmt.rs

1use crate::complex_pu;
2
3use super::*;
4
5use py_lex::syntax::Symbol;
6
7#[derive(Debug, Clone)]
8pub struct VarAssign {
9    pub val: Expr,
10}
11
12impl ParseUnit<Token> for VarAssign {
13    type Target = VarAssign;
14
15    fn parse(p: &mut Parser<Token>) -> ParseResult<Self, Token> {
16        p.r#match(Symbol::Assign)?;
17        let val = p.parse::<Expr>()?;
18        Ok(Self { val })
19    }
20}
21
22#[derive(Debug, Clone)]
23pub struct VarDefine {
24    pub ty: PU<types::TypeDefine>,
25    pub name: Ident,
26    pub init: Option<VarAssign>,
27}
28
29impl ParseUnit<Token> for VarDefine {
30    type Target = VarDefine;
31
32    fn parse(p: &mut Parser<Token>) -> ParseResult<Self, Token> {
33        let ty = p.parse::<PU<types::TypeDefine>>()?;
34        let name = p.parse::<Ident>()?;
35        let init = p.parse::<VarAssign>().apply(mapper::Try)?;
36        Ok(Self { ty, name, init })
37    }
38}
39
40#[derive(Debug, Clone)]
41pub struct VarStore {
42    pub name: Ident,
43    pub assign: PU<VarAssign>,
44}
45
46impl ParseUnit<Token> for VarStore {
47    type Target = VarStore;
48
49    fn parse(p: &mut Parser<Token>) -> ParseResult<Self, Token> {
50        let name = p.parse::<Ident>()?;
51        let assign = p.parse::<PU<VarAssign>>()?;
52        Ok(VarStore { name, assign })
53    }
54}
55
56#[derive(Debug, Clone)]
57pub struct Parameter {
58    /// so to make semantic cheaking easier
59    inner: VarDefine,
60}
61
62impl std::ops::Deref for Parameter {
63    type Target = VarDefine;
64
65    fn deref(&self) -> &Self::Target {
66        &self.inner
67    }
68}
69
70impl ParseUnit<Token> for Parameter {
71    type Target = Parameter;
72
73    fn parse(p: &mut Parser<Token>) -> ParseResult<Self, Token> {
74        let ty = p.parse::<PU<types::TypeDefine>>()?;
75        let name = p.parse::<Ident>()?;
76        let inner = VarDefine {
77            ty,
78            name,
79            init: None,
80        };
81        Ok(Parameter { inner })
82    }
83}
84
85#[derive(Debug, Clone)]
86pub struct Parameters {
87    pub params: Vec<PU<Parameter>>,
88}
89
90impl std::ops::Deref for Parameters {
91    type Target = Vec<PU<Parameter>>;
92
93    fn deref(&self) -> &Self::Target {
94        &self.params
95    }
96}
97
98impl ParseUnit<Token> for Parameters {
99    type Target = Parameters;
100
101    fn parse(p: &mut Parser<Token>) -> ParseResult<Self, Token> {
102        p.r#match(Symbol::Parameter)?;
103        let Some(arg) = p.parse::<PU<Parameter>>().apply(mapper::Try)? else {
104            p.r#match(Symbol::EndOfBlock).apply(mapper::MustMatch)?;
105
106            return Ok(Parameters { params: vec![] });
107        };
108
109        let mut params = vec![arg];
110
111        while p.r#match(Symbol::Semicolon).is_ok() {
112            params.push(p.parse::<PU<Parameter>>()?);
113        }
114
115        p.r#match(Symbol::EndOfBlock).apply(mapper::MustMatch)?;
116        Ok(Parameters { params })
117    }
118}
119
120/// however, this is the "best" way
121macro_rules! statement_wrapper {
122    (
123        $(
124            $(#[$metas:meta])*
125            $from:ident => $into:ident,
126        )*
127    ) => {
128        $(
129        #[derive(Debug, Clone)]
130        $(#[$metas])*
131        pub struct $into(py_lex::PU<$from>);
132
133        impl terl::ParseUnit<py_lex::Token> for $into {
134            type Target = $into;
135
136            fn parse(p: &mut terl::Parser<py_lex::Token>) -> terl::ParseResult<Self, py_lex::Token> {
137
138                let inner = p.parse::<py_lex::PU<$from>>()?;
139                p.r#match(py_lex::syntax::Symbol::Semicolon).apply(terl::mapper::MustMatch)?;
140                Ok($into(inner))
141            }
142        }
143
144        impl std::ops::Deref for $into {
145            type Target =  py_lex::PU<$from>;
146
147            fn deref(&self) -> &Self::Target {
148                &self.0
149            }
150        }
151
152        impl std::ops::DerefMut for $into {
153            fn deref_mut(&mut self) -> &mut Self::Target {
154                &mut self.0
155            }
156        }
157
158        )*
159    };
160}
161
162statement_wrapper! {
163    VarDefine => VarDefineStmt,
164    FnCall => FnCallStmt,
165    VarStore => VarStoreStmt,
166}
167
168/// be different from [`crate::complex_pu`], this version using box to make [`Statement`] enum smaller
169macro_rules! statements {
170    (
171        $(#[$metas:meta])*
172        stmt $enum_name:ident {
173        $(
174            $(#[$v_metas:meta])*
175            $variant:ident
176        ),*
177    }) => {
178        #[derive(Debug, Clone)]
179        $(#[$metas])*
180        pub enum $enum_name {
181            $(
182                $(#[$v_metas])*
183                $variant(Box<$variant>),
184            )*
185        }
186
187        $(
188        impl From<$variant> for $enum_name {
189             fn from(v: $variant) -> $enum_name {
190                <$enum_name>::$variant(Box::new(v))
191            }
192        }
193        )*
194
195        impl terl::ParseUnit<py_lex::Token> for $enum_name {
196            type Target = $enum_name;
197
198            fn parse(p: &mut terl::Parser<py_lex::Token>) -> terl::ParseResult<Self, py_lex::Token>
199            {
200                terl::Try::<$enum_name ,_>::new(p)
201                $(
202                .or_try::<Self, _>(|p| {
203                    p.once_no_try::<$variant ,_>($variant::parse)
204                        .map(Box::new).map(<$enum_name>::$variant)
205                })
206                )*
207                .finish()
208            }
209        }
210    };
211}
212
213statements! {
214    stmt Statement {
215
216        // $name (...)
217        FnCallStmt,
218        // $name = $expr
219        VarStoreStmt,
220
221        // $ty $name
222        VarDefineStmt,
223        If,
224        While,
225        Return,
226        Comment,
227        CodeBlock
228    }
229}
230
231complex_pu! {
232    cpu Item {
233        // $ty $name (...)
234        FnDefine,
235        Comment
236    }
237}
238
239#[cfg(test)]
240mod tests {
241    use crate::parse_test;
242
243    use super::*;
244
245    #[test]
246    fn variable_define() {
247        parse_test("kuan1 32 zheng3 a", |p| {
248            p.parse::<VarDefine>()?;
249            Ok(())
250        })
251    }
252
253    #[test]
254    fn variable_define_init() {
255        let src = "kuan1 32 zheng3 a wei2 114514 fen1";
256        parse_test(src, |p| {
257            p.parse::<VarDefine>()?;
258            Ok(())
259        });
260        parse_test(src, |p| {
261            p.parse::<Statement>()?;
262            Ok(())
263        });
264    }
265
266    #[test]
267    fn variable_reassign() {
268        parse_test("a wei2 114514 fen1", |p| {
269            p.parse::<Statement>()?;
270            Ok(())
271        });
272        parse_test("a wei2 114514 fen1", |p| {
273            p.parse::<VarStore>()?;
274            Ok(())
275        });
276    }
277}