• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TyRoXx / NonlocalityOS / 15093856571

18 May 2025 08:02AM UTC coverage: 72.396% (+0.3%) from 72.054%
15093856571

Pull #245

github

web-flow
Merge 84b21f68a into 4e7b17925
Pull Request #245: GH-244: multiple parameters actually work

135 of 157 new or added lines in 7 files covered. (85.99%)

2 existing lines in 1 file now uncovered.

3218 of 4445 relevant lines covered (72.4%)

2231.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.09
/lambda_compiler/src/type_checking.rs
1
use crate::{
2
    ast,
3
    compilation::{CompilerOutput, SourceLocation},
4
};
5
use astraea::{
6
    storage::{StoreError, StoreTree},
7
    tree::{HashedTree, Tree},
8
};
9
use lambda::{
10
    expressions::{DeepExpression, Expression},
11
    name::{Name, NamespaceId},
12
};
13
use std::{collections::BTreeMap, sync::Arc};
14

15
pub fn combine_parameter_names(parameter_names: &[Name], namespace_id: &NamespaceId) -> Name {
18✔
16
    let mut combined = String::new();
18✔
17
    for name in parameter_names {
40✔
18
        if !combined.is_empty() {
2✔
19
            combined.push('_');
2✔
20
        }
21
        combined.push_str(&name.key);
22
    }
23
    Name::new(*namespace_id, combined)
18✔
24
}
25

26
async fn check_tree_construction_or_argument_list(
9✔
27
    arguments: &[ast::Expression],
28
    generated_name_namespace: &NamespaceId,
29
    locals: &mut LocalVariables,
30
    storage: &dyn StoreTree,
31
) -> Result<CompilerOutput, StoreError> {
32
    let mut errors = Vec::new();
9✔
33
    let mut checked_arguments = Vec::new();
9✔
34
    for argument in arguments {
25✔
35
        let output = Box::pin(check_types(
16✔
36
            argument,
8✔
37
            generated_name_namespace,
8✔
38
            locals,
8✔
39
            storage,
8✔
40
        ))
41
        .await?;
8✔
42
        errors.extend(output.errors);
43
        if let Some(checked) = output.entry_point {
8✔
44
            checked_arguments.push(Arc::new(checked));
45
        } else {
46
            return Ok(CompilerOutput::new(None, errors));
×
47
        }
48
    }
49
    Ok(CompilerOutput {
9✔
50
        entry_point: Some(lambda::expressions::DeepExpression(
9✔
51
            lambda::expressions::Expression::ConstructTree(checked_arguments),
9✔
52
        )),
53
        errors,
9✔
54
    })
55
}
56

57
pub struct LocalVariable {}
58

59
pub struct LocalVariables {
60
    names: BTreeMap<Name, LocalVariable>,
61
}
62

63
impl LocalVariables {
64
    pub fn new() -> Self {
16✔
65
        Self {
66
            names: BTreeMap::new(),
16✔
67
        }
68
    }
69

70
    pub fn declare_arguments(&mut self, argument_names: &[Name]) {
15✔
71
        for name in argument_names {
31✔
72
            let pre_existed = self.names.insert(name.clone(), LocalVariable {});
8✔
73
            if pre_existed.is_some() {
8✔
74
                todo!("Duplicate argument name: {}", name);
75
            }
76
        }
77
    }
78

79
    pub fn read(&mut self, name: &Name, location: &SourceLocation) -> CompilerOutput {
9✔
80
        self.names.get(name).map_or_else(
9✔
81
            || {
1✔
82
                CompilerOutput::new(
1✔
83
                    None,
1✔
84
                    vec![crate::compilation::CompilerError::new(
1✔
85
                        format!("Identifier {} not found", name),
1✔
86
                        *location,
1✔
87
                    )],
88
                )
89
            },
90
            |_| {
8✔
91
                CompilerOutput::new(
8✔
92
                    Some(DeepExpression(
8✔
93
                        Expression::make_argument(), /*TODO: access nth child*/
8✔
94
                    )),
95
                    Vec::new(),
8✔
96
                )
97
            },
98
        )
99
    }
100
}
101

102
pub async fn check_types(
46✔
103
    syntax_tree: &ast::Expression,
104
    generated_name_namespace: &NamespaceId,
105
    locals: &mut LocalVariables,
106
    storage: &dyn StoreTree,
107
) -> Result<CompilerOutput, StoreError> {
108
    match syntax_tree {
46✔
109
        ast::Expression::Identifier(name, location) => Ok(locals.read(name, location)),
9✔
110
        ast::Expression::StringLiteral(value) => Ok(CompilerOutput::new(
16✔
111
            Some(lambda::expressions::DeepExpression(
112
                lambda::expressions::Expression::Literal(
113
                    storage
8✔
114
                        .store_tree(&HashedTree::from(Arc::new(
8✔
115
                            Tree::from_string(value).unwrap(/*TODO*/),
8✔
116
                        )))
117
                        .await?,
8✔
118
                ),
119
            )),
120
            Vec::new(),
121
        )),
122
        ast::Expression::Apply { callee, arguments } => {
3✔
123
            let callee_output = Box::pin(check_types(
6✔
124
                callee,
3✔
125
                generated_name_namespace,
3✔
126
                locals,
3✔
127
                storage,
3✔
128
            ))
129
            .await?;
3✔
130

131
            let argument_output = if arguments.len() == 1 {
3✔
132
                // For N=1 we don't need an indirection.
133
                Box::pin(check_types(
3✔
134
                    &arguments[0],
3✔
135
                    generated_name_namespace,
3✔
136
                    locals,
3✔
137
                    storage,
3✔
138
                ))
139
                .await?
3✔
140
            } else {
NEW
141
                Box::pin(check_tree_construction_or_argument_list(
×
NEW
142
                    &arguments[..],
×
NEW
143
                    generated_name_namespace,
×
NEW
144
                    locals,
×
NEW
145
                    storage,
×
146
                ))
NEW
147
                .await?
×
148
            };
149
            let errors = callee_output
150
                .errors
151
                .into_iter()
152
                .chain(argument_output.errors)
153
                .collect();
154
            match (callee_output.entry_point, argument_output.entry_point) {
155
                (Some(callee_checked), Some(argument_checked)) => Ok(CompilerOutput {
3✔
156
                    entry_point: Some(lambda::expressions::DeepExpression(
3✔
157
                        lambda::expressions::Expression::Apply {
3✔
158
                            callee: Arc::new(callee_checked),
3✔
159
                            argument: Arc::new(argument_checked),
3✔
160
                        },
161
                    )),
162
                    errors,
3✔
163
                }),
164
                (None, _) | (_, None) => Ok(CompilerOutput::new(None, errors)),
×
165
            }
166
        }
167
        ast::Expression::Lambda {
168
            parameter_names,
15✔
169
            body,
15✔
170
        } => {
15✔
171
            locals.declare_arguments(parameter_names);
15✔
172
            let body_output =
15✔
173
                Box::pin(check_types(body, generated_name_namespace, locals, storage)).await?;
15✔
174
            match body_output.entry_point {
175
                Some(body_checked) => Ok(CompilerOutput {
15✔
176
                    entry_point: Some(lambda::expressions::DeepExpression(
177
                        lambda::expressions::Expression::Lambda {
178
                            // TODO: capture variables
179
                            environment: Arc::new(DeepExpression(Expression::make_literal(
15✔
180
                                storage
15✔
181
                                    .store_tree(&HashedTree::from(Arc::new(Tree::empty())))
15✔
182
                                    .await?,
15✔
183
                            ))),
184
                            parameter_name: combine_parameter_names(
185
                                &parameter_names[..],
186
                                generated_name_namespace,
187
                            ),
188
                            body: Arc::new(body_checked),
189
                        },
190
                    )),
191
                    errors: body_output.errors,
192
                }),
193
                None => Ok(CompilerOutput::new(None, body_output.errors)),
×
194
            }
195
        }
196
        ast::Expression::ConstructTree(arguments) => {
9✔
197
            check_tree_construction_or_argument_list(
198
                &arguments[..],
9✔
199
                generated_name_namespace,
9✔
200
                locals,
9✔
201
                storage,
9✔
202
            )
203
            .await
9✔
204
        }
205
        ast::Expression::Braces(expression) => {
2✔
206
            let output = Box::pin(check_types(
4✔
207
                expression,
2✔
208
                generated_name_namespace,
2✔
209
                locals,
2✔
210
                storage,
2✔
211
            ))
212
            .await?;
2✔
213
            Ok(output)
214
        }
215
    }
216
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc