1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use super::*;
use py_lex::syntax::Symbol;

#[derive(Debug, Clone)]
pub struct Comment;

impl ParseUnit<Token> for Comment {
    type Target = Comment;

    fn parse(p: &mut Parser<Token>) -> ParseResult<Self, Token> {
        p.r#match(Symbol::Comment)?;

        loop {
            let str = p
                .parse::<Token>()
                .map_err(|e| e.append("comment without ending"))?;

            if &*str == "jie2" {
                return Ok(Comment {});
            }
        }
    }
}

#[derive(Debug, Clone)]
pub struct FnDefine {
    pub export: Option<Span>,
    pub ty: types::TypeDefine,
    pub name: Ident,
    pub params: Parameters,
    pub codes: CodeBlock,
    pub retty_span: Span,
    pub sign_span: Span,
}

impl ParseUnit<Token> for FnDefine {
    type Target = FnDefine;

    fn parse(p: &mut Parser<Token>) -> ParseResult<Self, Token> {
        let export = p
            .r#match(RPU(Symbol::Export))
            .apply(mapper::Try)?
            .map(|pu| pu.get_span());
        let ty = p.parse::<PU<types::TypeDefine>>()?;
        let name = p.parse::<Ident>()?;
        let params = p.parse::<PU<Parameters>>()?;
        let codes = p.parse::<CodeBlock>().apply(mapper::MustMatch)?;

        Ok(Self {
            export,
            retty_span: ty.get_span(),
            sign_span: ty.get_span().merge(params.get_span()),
            ty: ty.take(),
            name,
            params: params.take(),
            codes,
        })
    }
}

#[derive(Debug, Clone)]
pub struct CodeBlock {
    pub stmts: Vec<Statement>,
}

impl ParseUnit<Token> for CodeBlock {
    type Target = CodeBlock;

    fn parse(p: &mut Parser<Token>) -> ParseResult<Self, Token> {
        p.r#match(Symbol::Block)?;
        let mut stmts = vec![];
        while let Some(stmt) = p.parse::<Statement>().apply(mapper::Try)? {
            stmts.push(stmt)
        }
        p.r#match(Symbol::EndOfBlock)?;
        Ok(Self { stmts })
    }
}

#[cfg(test)]
mod tests {
    use crate::parse_test;

    use super::*;

    #[test]
    fn code_block() {
        parse_test("han2 jie2", |p| {
            p.parse::<CodeBlock>()?;
            Ok(())
        });
    }

    #[test]
    fn function_define() {
        parse_test(
            "zheng3 zhu3 can1 zheng3 argc fen1 zhi3 zhi3 zi4 argv jie2
                    han2
                    jie2",
            |p| {
                p.parse::<FnDefine>()?;
                Ok(())
            },
        );
    }

    #[test]
    fn complex_funcion_define() {
        parse_test(
            "zheng3 zhu3 can1 zheng3 argc fen1 zhi3 zu3 zi4 argv jie2 
                    han2
                        ruo4 can1 jie2 1 da4 0 he2 huo4 jie2 2 xiao3 3 he2 yu3 fei1 fou3 jie2
                        han2 
                            shi4 if ((1>0)||(2<3)&&!false){} else{} jie2
                        jie2 ze2 han2 

                        jie2
                    jie2",
            |p| {
                p.parse::<FnDefine>()?;
                Ok(())
            },
        )
    }

    #[test]
    fn comment() {
        parse_test("shi4 ehhhaaaaaaaaaaaaaaaaaaaaaaaa jie2", |p| {
            p.parse::<Comment>()?;
            Ok(())
        });
    }

    #[test]
    #[should_panic]
    fn comment_without_ending() {
        parse_test("shi4 ehhhaaaaaaaaaaaaaaaaaaaaaaaa ajie2", |p| {
            p.parse::<CodeBlock>()?;
            Ok(())
        });
    }
}