1
use crate::ast::{
2
    BuiltinTypeKind, Decl, FuncDecl, IntegerLiteral, Param, TranslationUnit, Type, VarDecl,
3
};
4
use crate::constant_parser::{parse_numeric_constant, NumConst};
5
use crate::diagnostics::Diag;
6
use crate::scanner::{Bracket, Scanner, Token, TokenKind};
7
use crate::source_map::{SourceFile, Spanned};
8

            
9
pub(crate) struct Parser<'src> {
10
    scanner: Scanner<'src>,
11
    source_file: SourceFile<'src>,
12
    cached_peek_tok: Option<Spanned<Token>>,
13
}
14

            
15
impl<'src> Parser<'src> {
16
524
    pub(crate) fn new(scanner: Scanner<'src>, source_file: SourceFile<'src>) -> Parser<'src> {
17
524
        Parser {
18
524
            scanner,
19
524
            source_file,
20
524
            cached_peek_tok: None,
21
524
        }
22
524
    }
23

            
24
524
    pub(crate) fn parse_translation_unit(&mut self) -> Result<TranslationUnit, Vec<Diag>> {
25
524
        let tok = self.consume_tok().unwrap();
26
524

            
27
524
        if tok == Token::eof() {
28
1
            Err(vec![Diag::EmptyTranslationUnit])
29
        } else {
30
523
            let mut external_decls = vec![];
31
523
            let mut diagnostics = vec![];
32
523

            
33
523
            match self.parse_decl(*tok) {
34
519
                Ok(decl) => external_decls.push(decl),
35
4
                Err(decl_diags) => diagnostics.extend(decl_diags),
36
            }
37

            
38
523
            if diagnostics.is_empty() {
39
519
                let translation_unit = TranslationUnit { external_decls };
40
519

            
41
519
                Ok(translation_unit)
42
            } else {
43
4
                Err(diagnostics)
44
            }
45
        }
46
524
    }
47

            
48
523
    fn parse_decl(&mut self, type_spec_tok: Token) -> Result<Decl, Vec<Diag>> {
49
        debug_assert!(
50
523
            type_spec_tok.kind == TokenKind::KwInt || type_spec_tok.kind == TokenKind::KwLong
51
        );
52
523
        let type_spec = map_token_kind_to_type(type_spec_tok.kind);
53
523

            
54
523
        let ident_tok = self.consume_tok().unwrap();
55
523
        debug_assert!(ident_tok.kind == TokenKind::Identifier);
56

            
57
523
        let lexeme = self.source_file.get_text_snippet(ident_tok);
58
523
        let next_tok = self.consume_tok().unwrap();
59
523

            
60
523
        if next_tok.kind == TokenKind::Open(Bracket::Round) {
61
9
            let mut parameters = vec![];
62
9
            let mut decl_diags = vec![];
63

            
64
22
            loop {
65
22
                let tok = self.consume_tok().unwrap();
66
22

            
67
22
                match tok.kind {
68
7
                    TokenKind::Closed(Bracket::Round) => break,
69
                    TokenKind::Semicolon => {
70
2
                        decl_diags.push(Diag::MissingClosingParen);
71
2
                        break;
72
                    }
73
11
                    TokenKind::KwInt => {
74
11
                        let identifier = if self.peek_tok().unwrap().kind == TokenKind::Identifier {
75
5
                            let ident_tok = self.consume_tok().unwrap();
76
5
                            let lexeme = self.source_file.get_text_snippet(ident_tok);
77
5

            
78
5
                            Some(lexeme.to_owned())
79
                        } else {
80
6
                            None
81
                        };
82

            
83
11
                        parameters.push(Param {
84
11
                            type_specifier: Type::BuiltinType(BuiltinTypeKind::Int),
85
11
                            identifier,
86
11
                        });
87
                    }
88
2
                    unknown_kind => {
89
2
                        decl_diags.push(Diag::ExpectedButGot {
90
2
                            expected: TokenKind::KwInt,
91
2
                            got: unknown_kind,
92
2
                        });
93
2
                        continue;
94
                    }
95
                }
96

            
97
11
                let next_tok = self.peek_tok().unwrap();
98
11

            
99
11
                if next_tok.kind != TokenKind::Closed(Bracket::Round) {
100
6
                    if next_tok.kind == TokenKind::Comma {
101
4
                        self.consume_tok().unwrap();
102
4
                    } else {
103
2
                        decl_diags.push(Diag::ExpectedButGot {
104
2
                            expected: TokenKind::Comma,
105
2
                            got: next_tok.kind,
106
2
                        });
107
2
                    }
108
5
                }
109
            }
110

            
111
9
            if decl_diags.is_empty() {
112
5
                Ok(Decl::Func(FuncDecl {
113
5
                    ret_type_specifier: type_spec,
114
5
                    identifier: lexeme.to_owned(),
115
5
                    parameters,
116
5
                }))
117
            } else {
118
4
                Err(decl_diags)
119
            }
120
        } else {
121
514
            let initializer = if next_tok.kind == TokenKind::Equal {
122
257
                Some(self.parse_initializer())
123
            } else {
124
257
                None
125
            };
126

            
127
514
            Ok(Decl::Var(VarDecl {
128
514
                type_specifier: type_spec,
129
514
                identifier: lexeme.to_owned(),
130
514
                initializer,
131
514
            }))
132
        }
133
523
    }
134

            
135
257
    fn parse_initializer(&mut self) -> IntegerLiteral {
136
257
        let init_tok = self.consume_tok().unwrap();
137
257
        debug_assert!(init_tok.kind == TokenKind::NumericConstant);
138

            
139
257
        let parse_result = parse_numeric_constant(self.source_file.get_text_snippet(init_tok));
140
257
        debug_assert!(!parse_result.has_overflowed);
141

            
142
257
        match parse_result.num_const {
143
257
            NumConst::Int(int_const) => {
144
257
                debug_assert!(!int_const.is_unsigned);
145

            
146
257
                IntegerLiteral {
147
257
                    value: int_const.value,
148
257
                    ty: Type::BuiltinType(BuiltinTypeKind::Int),
149
257
                }
150
257
            }
151
257
        }
152
257
    }
153

            
154
1858
    fn consume_tok(&mut self) -> Result<Spanned<Token>, Diag> {
155
1858
        // Guarantees that `self.cached_peek_tok` has a peeked token.
156
1858
        self.peek_tok()?;
157
1858
        debug_assert!(self.cached_peek_tok.is_some());
158

            
159
1858
        let peeked_tok = self.cached_peek_tok.unwrap();
160
1858

            
161
1858
        if peeked_tok != Token::eof() {
162
1857
            self.cached_peek_tok = None;
163
1857
        }
164

            
165
1858
        Ok(peeked_tok)
166
1858
    }
167

            
168
1880
    fn peek_tok(&mut self) -> Result<Spanned<Token>, Diag> {
169
1880
        match self.cached_peek_tok {
170
22
            Some(peeked_tok) => Ok(peeked_tok),
171
            _ => {
172
1858
                let peeked_tok = self.scanner.scan_next_token()?;
173
1858
                self.cached_peek_tok = Some(peeked_tok);
174
1858

            
175
1858
                Ok(peeked_tok)
176
            }
177
        }
178
1880
    }
179
}
180

            
181
523
fn map_token_kind_to_type(tok_kind: TokenKind) -> Type {
182
523
    match tok_kind {
183
269
        TokenKind::KwInt => Type::BuiltinType(BuiltinTypeKind::Int),
184
254
        TokenKind::KwLong => Type::BuiltinType(BuiltinTypeKind::Long),
185
        _ => unimplemented!("missing impl of other types"),
186
    }
187
523
}