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 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}