duskphantom_frontend/parse/
typed.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 super::*;
18
19pub fn atom_type(input: &mut &str) -> PResult<Type> {
20    alt((
21        token("void").value(Type::Void),
22        token("int").value(Type::Int),
23        token("float").value(Type::Float),
24        token("string").value(Type::String),
25        token("char").value(Type::Char),
26        token("bool").value(Type::Bool),
27        (token("enum"), ident).map(|(_, ty)| Type::Enum(ty)),
28        (token("union"), ident).map(|(_, ty)| Type::Union(ty)),
29        (token("struct"), ident).map(|(_, ty)| Type::Struct(ty)),
30    ))
31    .parse_next(input)
32}
33
34/// Parser of an left value.
35pub fn lval(input: &mut &str) -> PResult<LVal> {
36    let atom = alt((
37        pad(ident).map(LVal::Var),
38        paren(lval),
39        empty.value(LVal::Nothing),
40    ));
41    let access_tail = alt((
42        bracket(opt(pad(expr))).map(|x| {
43            // Empty bracket is pointer, non-empty bracket is index.
44            BoxF::new(move |acc| match x {
45                Some(ix) => LVal::Index(acc, ix.into()),
46                None => LVal::Pointer(acc),
47            })
48        }),
49        paren(vec_typed).map(|x| BoxF::new(|acc| LVal::Call(acc, x))),
50    ));
51    let access = lrec(atom, repeat(0.., access_tail));
52    let unary_init = token("*").map(|_op| BoxF::new(LVal::Pointer));
53    rrec(repeat(0.., unary_init), access).parse_next(input)
54}
55
56/// Accumulate usage to type, so that it becomes a TypedIdent.
57/// For example, `int (*x)(float)` becomes `{int (*)(float), x}`
58pub fn acc_lval(ty: Type, usage: LVal) -> TypedIdent {
59    match usage {
60        LVal::Nothing => TypedIdent::new(ty, None),
61        LVal::Var(id) => TypedIdent::new(ty, Some(id)),
62        LVal::Index(inner, ix) => acc_lval(Type::Array(Box::new(ty), ix), *inner),
63        LVal::Call(inner, arg) => acc_lval(Type::Function(Box::new(ty), arg), *inner),
64        LVal::Pointer(inner) => acc_lval(Type::Pointer(Box::new(ty)), *inner),
65    }
66}
67
68/// Parser of a TypedIdent.
69pub fn typed_ident(input: &mut &str) -> PResult<TypedIdent> {
70    let ty = atom_type.parse_next(input)?;
71    let us = lval.parse_next(input)?;
72    Ok(acc_lval(ty, us))
73}
74
75/// Parser of a single type.
76pub fn single_type(input: &mut &str) -> PResult<Type> {
77    typed_ident.map(|ti| ti.ty).parse_next(input)
78}
79
80/// Parser of a box of type.
81pub fn box_type(input: &mut &str) -> PResult<Box<Type>> {
82    single_type.map(Box::new).parse_next(input)
83}
84
85/// Parser of a vector of type.
86pub fn vec_typed(input: &mut &str) -> PResult<Vec<TypedIdent>> {
87    separated(0.., typed_ident, token(",")).parse_next(input)
88}
89
90// Unit tests
91#[cfg(test)]
92pub mod tests_typed {
93    use super::*;
94
95    #[test]
96    fn test_atom() {
97        let code = "int";
98        match atom_type.parse(code) {
99            Ok(result) => assert_eq!(result, Type::Int),
100            Err(err) => panic!("failed to parse {}: {}", code, err),
101        }
102    }
103
104    #[test]
105    fn test_space() {
106        // Pointer to a function.
107        let code = "int  (  *  )  (  int  u  )";
108        match single_type.parse(code) {
109            Ok(result) => assert_eq!(
110                result,
111                Type::Pointer(Box::new(Type::Function(
112                    Box::new(Type::Int),
113                    vec![TypedIdent::new(Type::Int, Some("u".to_string()))],
114                )))
115            ),
116            Err(err) => panic!("failed to parse {}: {}", code, err),
117        }
118    }
119
120    #[test]
121    fn test_function_pointer() {
122        let code = "int (*)(int)";
123        match single_type.parse(code) {
124            Ok(result) => assert_eq!(
125                result,
126                Type::Pointer(Box::new(Type::Function(
127                    Box::new(Type::Int),
128                    vec![TypedIdent::new(Type::Int, None)],
129                )))
130            ),
131            Err(err) => panic!("failed to parse {}: {}", code, err),
132        }
133    }
134
135    #[test]
136    fn test_name_pointer_function() {
137        // Function that returns a pointer.
138        let code = "int *u(int)";
139        match single_type.parse(code) {
140            Ok(result) => assert_eq!(
141                result,
142                Type::Function(
143                    Box::new(Type::Pointer(Box::new(Type::Int))),
144                    vec![TypedIdent::new(Type::Int, None)],
145                )
146            ),
147            Err(err) => panic!("failed to parse {}: {}", code, err),
148        }
149    }
150
151    #[test]
152    fn test_argname_pointer_function() {
153        let code = "int *(int u)";
154        match single_type.parse(code) {
155            Ok(result) => assert_eq!(
156                result,
157                Type::Function(
158                    Box::new(Type::Pointer(Box::new(Type::Int))),
159                    vec![TypedIdent::new(Type::Int, Some("u".to_string()))],
160                )
161            ),
162            Err(err) => panic!("failed to parse {}: {}", code, err),
163        }
164    }
165
166    #[test]
167    fn test_usage() {
168        let code = "*(int)";
169        match lval.parse(code) {
170            Ok(result) => assert_eq!(
171                result,
172                LVal::Pointer(Box::new(LVal::Call(
173                    Box::new(LVal::Nothing),
174                    vec![TypedIdent::new(Type::Int, None)],
175                )))
176            ),
177            Err(err) => panic!("failed to parse {}: {}", code, err),
178        }
179    }
180
181    #[test]
182    fn test_pointer_function() {
183        let code = "int *(int)";
184        match single_type.parse(code) {
185            Ok(result) => assert_eq!(
186                result,
187                Type::Function(
188                    Box::new(Type::Pointer(Box::new(Type::Int))),
189                    vec![TypedIdent::new(Type::Int, None)],
190                )
191            ),
192            Err(err) => panic!("failed to parse {}: {}", code, err),
193        }
194    }
195
196    #[test]
197    fn test_array_pointer() {
198        let code = "int x[][4]";
199        match single_type.parse(code) {
200            Ok(result) => assert_eq!(
201                result,
202                Type::Pointer(Box::new(Type::Array(
203                    Box::new(Type::Int),
204                    Box::new(Expr::Int(4))
205                )))
206            ),
207            Err(err) => panic!("failed to parse {}: {}", code, err),
208        }
209    }
210
211    #[test]
212    fn test_complicated() {
213        // (*(*app)(f))(x) === f(x)
214        // app: *(*(int -> int) -> *(int -> int))
215        let code = "int (*(*app)(int (*)(int)))(int)";
216        match typed_ident.parse(code) {
217            Ok(result) => assert_eq!(
218                result,
219                TypedIdent::new(
220                    Type::Pointer(Box::new(Type::Function(
221                        Box::new(Type::Pointer(Box::new(Type::Function(
222                            Box::new(Type::Int),
223                            vec![TypedIdent::new(Type::Int, None)],
224                        )))),
225                        vec![TypedIdent::new(
226                            Type::Pointer(Box::new(Type::Function(
227                                Box::new(Type::Int),
228                                vec![TypedIdent::new(Type::Int, None)],
229                            ))),
230                            None
231                        )],
232                    ))),
233                    Some("app".to_string()),
234                ),
235            ),
236            Err(err) => panic!("failed to parse {}: {}", code, err),
237        }
238    }
239}