qbe_parser/ast/functions/
parse.rs

1use crate::ast::data::Constant;
2use crate::ast::functions::{
3    CallArgument, CallInstruction, EnvironmentParamDef, FunctionBlock, FunctionBody, FunctionDef,
4    InsnDestInfo, JumpInstruction, JumpInstructionKind, ParamDef, PhiArg, PhiInstruction,
5    RegularCallArgument, RegularInstruction, RegularParamDef, SimpleInstruction, ThreadLocalRef,
6    Value, VariadicParamDef,
7};
8use crate::ast::linkage::Linkage;
9use crate::ast::types::{AbiType, BaseType};
10use crate::ast::{BlockName, GlobalName, Ident, TemporaryName};
11use crate::lexer::{Operator, Token, TokenParser, keyword, operator};
12use crate::parse::{Parse, impl_fromstr_via_parse, maybe_newline};
13use chumsky::prelude::*;
14
15impl Parse for ThreadLocalRef {
16    const DESC: &'static str = "thread-local ref";
17    fn parser<'a>() -> impl TokenParser<'a, Self> {
18        keyword!(thread)
19            .parser()
20            .ignore_then(GlobalName::parser())
21            .map_with(|name, extra| ThreadLocalRef {
22                name,
23                span: extra.span(),
24            })
25    }
26}
27impl_fromstr_via_parse!(ThreadLocalRef);
28impl Parse for Value {
29    const DESC: &'static str = "value";
30    fn parser<'a>() -> impl TokenParser<'a, Self> {
31        choice((
32            TemporaryName::parser().map(Value::Temporary),
33            ThreadLocalRef::parser().map(Value::ThreadLocalRef),
34            Constant::parser().map(Value::Constant),
35        ))
36        .labelled(Self::DESC)
37    }
38}
39impl_fromstr_via_parse!(Value);
40impl JumpInstructionKind {
41    /// Parse an exact match for only this specific kind of jump instruction,
42    /// rejecting all others.
43    fn parser_exact<'a>(&self) -> impl TokenParser<'a, JumpInstructionKind> {
44        let expected = *self;
45        <JumpInstructionKind as Parse>::parser().filter(move |kind| *kind == expected)
46    }
47}
48impl Parse for JumpInstructionKind {
49    const DESC: &'static str = "jump instruction name";
50    fn parser<'a>() -> impl TokenParser<'a, Self> {
51        choice([
52            keyword!(jmp).parser().to(JumpInstructionKind::Jump),
53            keyword!(jnz).parser().to(JumpInstructionKind::JumpNonZero),
54            keyword!(ret).parser().to(JumpInstructionKind::Return),
55            keyword!(hlt).parser().to(JumpInstructionKind::Halt),
56        ])
57        .labelled(Self::DESC)
58    }
59}
60impl Parse for JumpInstruction {
61    const DESC: &'static str = "jump instruction";
62    fn parser<'a>() -> impl TokenParser<'a, Self> {
63        choice((
64            JumpInstructionKind::Jump
65                .parser_exact()
66                .ignore_then(BlockName::parser())
67                .map_with(|target, extra| JumpInstruction::Jump {
68                    target,
69                    span: extra.span(),
70                }),
71            JumpInstructionKind::JumpNonZero
72                .parser_exact()
73                .ignore_then(Value::parser())
74                .then_ignore(Operator::Comma.parser())
75                .then(BlockName::parser())
76                .then_ignore(Operator::Comma.parser())
77                .then(BlockName::parser())
78                .map_with(
79                    |((op, target), fallthrough), extra| JumpInstruction::JumpNonZero {
80                        op,
81                        target,
82                        fallthrough,
83                        span: extra.span(),
84                    },
85                ),
86            JumpInstructionKind::Return
87                .parser_exact()
88                .ignore_then(Value::parser().or_not())
89                .map_with(|value, extra| JumpInstruction::Return {
90                    span: extra.span(),
91                    value,
92                }),
93            JumpInstructionKind::Halt
94                .parser_exact()
95                .map_with(|_kind, extra| JumpInstruction::Halt { span: extra.span() }),
96        ))
97        .labelled(Self::DESC)
98    }
99}
100impl_fromstr_via_parse!(JumpInstruction);
101
102impl Parse for RegularParamDef {
103    const DESC: &'static str = "regular parameter";
104    fn parser<'a>() -> impl TokenParser<'a, Self> {
105        AbiType::parser()
106            .then(TemporaryName::parser())
107            .map_with(|(ty, name), extra| RegularParamDef {
108                ty,
109                name,
110                span: extra.span(),
111            })
112            .labelled(Self::DESC)
113    }
114}
115impl Parse for EnvironmentParamDef {
116    const DESC: &'static str = "environment parameter";
117    fn parser<'a>() -> impl TokenParser<'a, Self> {
118        keyword!(env)
119            .parser()
120            .ignore_then(TemporaryName::parser())
121            .map_with(|name, extra| EnvironmentParamDef {
122                name,
123                span: extra.span(),
124            })
125            .labelled(Self::DESC)
126    }
127}
128impl Parse for VariadicParamDef {
129    const DESC: &'static str = "variadic parameter";
130    fn parser<'a>() -> impl TokenParser<'a, Self> {
131        operator!(...)
132            .parser()
133            .to_span()
134            .map(|span| VariadicParamDef { span })
135            .labelled(Self::DESC)
136    }
137}
138impl Parse for ParamDef {
139    const DESC: &'static str = "parameter definition";
140    fn parser<'a>() -> impl TokenParser<'a, Self> {
141        choice((
142            RegularParamDef::parser().map(ParamDef::Regular),
143            EnvironmentParamDef::parser().map(ParamDef::Environment),
144            VariadicParamDef::parser().map(ParamDef::Variadic),
145        ))
146        .labelled(Self::DESC)
147    }
148}
149
150impl Parse for FunctionDef {
151    const DESC: &'static str = "function definition";
152
153    fn parser<'a>() -> impl TokenParser<'a, Self> {
154        let params = ParamDef::parser()
155            .separated_by(operator!(,).parser())
156            .allow_trailing()
157            .collect()
158            .delimited_by(just(Token::OpenParen), just(Token::CloseParen))
159            .labelled("function parameters");
160        Linkage::parser()
161            .then_ignore(keyword!(function).parser())
162            .then(AbiType::parser().or_not().labelled("return type"))
163            .then(GlobalName::parser())
164            .then(params)
165            .then_ignore(maybe_newline())
166            .then(FunctionBody::parser())
167            .labelled(Self::DESC)
168            .map_with(
169                |((((linkage, return_type), name), params), body), extra| FunctionDef {
170                    span: extra.span(),
171                    linkage,
172                    name,
173                    params,
174                    body,
175                    return_type,
176                },
177            )
178            .labelled(Self::DESC)
179    }
180}
181impl_fromstr_via_parse!(FunctionDef);
182impl Parse for FunctionBody {
183    const DESC: &'static str = "function body";
184    fn parser<'a>() -> impl TokenParser<'a, Self> {
185        just(Token::OpenBrace)
186            .then_ignore(just(Token::Newline))
187            .ignore_then(
188                FunctionBlock::parser()
189                    .repeated()
190                    .at_least(1)
191                    .collect::<Vec<_>>(),
192            )
193            .then_ignore(just(Token::CloseBrace))
194            .map_with(|blocks, extra| FunctionBody {
195                blocks,
196                span: extra.span(),
197            })
198    }
199}
200
201impl Parse for FunctionBlock {
202    const DESC: &'static str = "block";
203    fn parser<'a>() -> impl TokenParser<'a, Self> {
204        BlockName::parser()
205            .labelled("block label")
206            .then_ignore(just(Token::Newline))
207            .then(
208                PhiInstruction::parser()
209                    .then_ignore(just(Token::Newline))
210                    .repeated()
211                    .collect::<Vec<_>>(),
212            )
213            .then(
214                RegularInstruction::parser()
215                    .then_ignore(just(Token::Newline))
216                    .repeated()
217                    .collect::<Vec<_>>(),
218            )
219            .then(
220                JumpInstruction::parser()
221                    .then_ignore(just(Token::Newline))
222                    .or_not(),
223            )
224            .map_with(
225                |(((label, phis), instructions), terminator), extra| FunctionBlock {
226                    span: extra.span(),
227                    label,
228                    instructions,
229                    phis,
230                    terminator,
231                },
232            )
233    }
234}
235impl_fromstr_via_parse!(FunctionBlock);
236
237impl Parse for PhiInstruction {
238    const DESC: &'static str = "phi instruction";
239    fn parser<'a>() -> impl TokenParser<'a, Self> {
240        InsnDestInfo::parser()
241            .then_ignore(keyword!(phi).parser())
242            .then(
243                PhiArg::parser()
244                    .separated_by(operator!(,).parser())
245                    .at_least(1)
246                    .collect::<Vec<_>>(),
247            )
248            .map_with(|(dest_info, args), extra| PhiInstruction {
249                span: extra.span(),
250                dest_info,
251                args,
252            })
253            .labelled(Self::DESC)
254    }
255}
256impl_fromstr_via_parse!(PhiInstruction);
257impl Parse for PhiArg {
258    const DESC: &'static str = "phi argument";
259    fn parser<'a>() -> impl TokenParser<'a, Self> {
260        BlockName::parser()
261            .then(Value::parser())
262            .map_with(|(block, value), extra| PhiArg {
263                value,
264                span: extra.span(),
265                block,
266            })
267            .labelled(Self::DESC)
268    }
269}
270impl Parse for RegularInstruction {
271    const DESC: &'static str = "regular instruction";
272    fn parser<'a>() -> impl TokenParser<'a, Self> {
273        choice((
274            SimpleInstruction::parser().map(RegularInstruction::Simple),
275            CallInstruction::parser().map(RegularInstruction::Call),
276        ))
277        .labelled(Self::DESC)
278    }
279}
280impl_fromstr_via_parse!(RegularInstruction);
281impl Parse for SimpleInstruction {
282    const DESC: &'static str = "simple instruction";
283    fn parser<'a>() -> impl TokenParser<'a, Self> {
284        let values = Value::parser()
285            .separated_by(operator!(,).parser())
286            .at_least(1)
287            .allow_trailing()
288            .collect::<Vec<_>>();
289        InsnDestInfo::parser()
290            .or_not()
291            .then(Ident::parser())
292            .then(values)
293            .map_with(|((dest, name), args), extra| SimpleInstruction {
294                span: extra.span(),
295                dest_info: dest,
296                name,
297                args,
298            })
299    }
300}
301impl_fromstr_via_parse!(SimpleInstruction);
302impl Parse for CallInstruction {
303    const DESC: &'static str = "call instruction";
304    fn parser<'a>() -> impl TokenParser<'a, Self> {
305        let args = CallArgument::parser()
306            .separated_by(operator!(,).parser())
307            .collect::<Vec<_>>()
308            .delimited_by(just(Token::OpenParen), just(Token::CloseParen));
309        InsnDestInfo::parser()
310            .or_not()
311            .then(keyword!(call).parser().to_span())
312            .then(Value::parser())
313            .then(args)
314            .map_with(
315                |(((dest_info, call_kw_span), target), args), extra| CallInstruction {
316                    span: extra.span(),
317                    call_kw_span,
318                    target,
319                    args,
320                    dest_info,
321                },
322            )
323    }
324}
325impl Parse for CallArgument {
326    const DESC: &'static str = "call argument";
327    fn parser<'a>() -> impl TokenParser<'a, Self> {
328        choice((
329            RegularCallArgument::parser().map(CallArgument::Regular),
330            keyword!(env)
331                .parser()
332                .ignore_then(Value::parser())
333                .map(CallArgument::Environment),
334            operator!(...)
335                .parser()
336                .to_span()
337                .map(CallArgument::VariadicMarker),
338        ))
339    }
340}
341impl Parse for RegularCallArgument {
342    const DESC: &'static str = "regular call argument";
343    fn parser<'a>() -> impl TokenParser<'a, Self> {
344        AbiType::parser()
345            .then(Value::parser())
346            .map_with(|(ty, value), extra| RegularCallArgument {
347                ty,
348                value,
349                span: extra.span(),
350            })
351    }
352}
353impl Parse for InsnDestInfo {
354    const DESC: &'static str = "instruction destination";
355    fn parser<'a>() -> impl TokenParser<'a, Self> {
356        TemporaryName::parser()
357            .then_ignore(operator!(=).parser())
358            .then(BaseType::parser())
359            .map_with(|(dest, ty), extra| InsnDestInfo {
360                dest,
361                ty,
362                span: extra.span(),
363            })
364    }
365}