duskphantom_frontend/parse/
decl.rs1use winnow::error::{ErrMode, ErrorKind};
18
19use super::*;
20
21pub fn make_const(decl: Decl) -> Decl {
22 match decl {
23 Decl::Var(ty, id, expr) => Decl::Const(ty, id, expr),
24 _ => decl,
25 }
26}
27
28pub fn decl(input: &mut &str) -> PResult<Decl> {
29 if input.starts_with('#') {
31 return alt((
32 (token("#include"), opt(take_until(0.., '\n')), blank).value(Decl::Stack(vec![])),
33 (token("#define"), pad(ident), expr)
34 .map(|(_, id, expr)| Decl::Const(Type::Int, id, Some(expr))),
35 ))
36 .parse_next(input);
37 }
38
39 let is_const = opt(token("const")).parse_next(input)?.is_some();
41
42 opt(token("extern")).parse_next(input)?;
44
45 let left_type = atom_type.parse_next(input)?;
47
48 let mut decls: Vec<Decl> = separated(
50 1..,
51 |input: &mut &str| assignment(input, left_type.clone()),
52 token(","),
53 )
54 .parse_next(input)?;
55
56 if let Some(Decl::Func(_, _, Some(_))) = decls.last() {
58 } else {
60 token(";").parse_next(input)?;
61 }
62
63 if is_const {
65 decls = decls.into_iter().map(make_const).collect();
66 }
67
68 match decls.len() {
70 1 => Ok(decls.pop().unwrap()),
71 _ => Ok(Decl::Stack(decls)),
72 }
73}
74
75pub fn assignment(input: &mut &str, left_type: Type) -> PResult<Decl> {
76 let left_val = lval.parse_next(input)?;
77 let typed_ident = acc_lval(left_type, left_val);
78 let Some(id) = typed_ident.id else {
79 return Err(ErrMode::from_error_kind(input, ErrorKind::Verify).cut());
80 };
81
82 if let Some(expr) = opt(preceded(token("="), expr)).parse_next(input)? {
84 return Ok(Decl::Var(typed_ident.ty, id, Some(expr)));
85 };
86
87 if let Some(body) = opt(curly(vec_stmt)).parse_next(input)? {
89 return Ok(Decl::Func(
90 typed_ident.ty,
91 id,
92 Some(Box::new(Stmt::Block(body))),
93 ));
94 };
95
96 match typed_ident.ty {
98 Type::Function(_, _) => Ok(Decl::Func(typed_ident.ty, id, None)),
99 _ => Ok(Decl::Var(typed_ident.ty, id, None)),
100 }
101}