duskphantom_frontend/parse/
decl.rs

1// Copyright 2024 Duskphantom Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// SPDX-License-Identifier: Apache-2.0
16
17use 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    // Attempt to match a macro.
30    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    // Match const token.
40    let is_const = opt(token("const")).parse_next(input)?.is_some();
41
42    // Consume extern token.
43    opt(token("extern")).parse_next(input)?;
44
45    // Parse type.
46    let left_type = atom_type.parse_next(input)?;
47
48    // Parse lval and optional assignment expression.
49    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    // Require semicolon if the last declaration is not function implementation
57    if let Some(Decl::Func(_, _, Some(_))) = decls.last() {
58        // Do nothing
59    } else {
60        token(";").parse_next(input)?;
61    }
62
63    // Make constant if necessary
64    if is_const {
65        decls = decls.into_iter().map(make_const).collect();
66    }
67
68    // Return declaration according to count
69    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    // Parse optional assignment.
83    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    // Parse optional function implementation.
88    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    // Return declaration according to real type
97    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}