spade_parser/
item_type.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use local_impl::local_impl;
use spade_ast::UnitKind;
use spade_common::location_info::Loc;
use spade_diagnostics::Diagnostic;

fn not_allowed_in_function(message: &str, at: Loc<()>, what: &str, kw_loc: Loc<()>) -> Diagnostic {
    Diagnostic::error(at, message)
        .primary_label(format!("{what} not allowed here"))
        .secondary_label(kw_loc, "this is a function")
        .note("functions can only contain combinatorial logic")
        .span_suggest_replace("consider making the function an entity", kw_loc, "entity")
}

fn bug_no_item_context(at: Loc<()>) -> Diagnostic {
    Diagnostic::bug(
        at,
        "attempted to parse something which requires an item context, but no item context exists",
    )
}

fn stage_ref_in(what: &str, at: Loc<()>, kw_loc: Loc<()>) -> Diagnostic {
    Diagnostic::error(at, format!("pipeline stage reference in {what}"))
        .primary_label("pipeline stage reference not allowed here")
        .secondary_label(kw_loc, format!("this is a {what}"))
        .note("only pipelines can contain pipeline stage references")
        .span_suggest_replace(
            format!("consider making the {} a pipeline", what),
            kw_loc,
            "pipeline(/* depth */)",
        )
}

#[local_impl]
impl UnitKindLocal for Option<Loc<UnitKind>> {
    fn allows_reg(&self, at: Loc<()>) -> Result<(), Diagnostic> {
        match self.as_ref().map(|x| x.split_loc_ref()) {
            Some((UnitKind::Function, kw_loc)) => Err(not_allowed_in_function(
                "register declared in function",
                at,
                "register",
                kw_loc,
            )),
            Some((UnitKind::Entity | UnitKind::Pipeline(_), _)) => Ok(()),
            None => Err(bug_no_item_context(at)),
        }
    }

    fn allows_inst(&self, at: Loc<()>) -> Result<(), Diagnostic> {
        match self.as_ref().map(|x| x.split_loc_ref()) {
            // FIXME: Choose "entities" or "pipelines" depending on what we try to instantiate
            Some((UnitKind::Function, kw_loc)) => Err(not_allowed_in_function(
                "cannot instantiate entities and pipelines in functions",
                at,
                "inst",
                kw_loc,
            )),
            Some((UnitKind::Entity | UnitKind::Pipeline(_), _)) => Ok(()),
            None => Err(bug_no_item_context(at)),
        }
    }

    fn allows_pipeline_ref(&self, at: Loc<()>) -> Result<(), Diagnostic> {
        match self.as_ref().map(|x| x.split_loc_ref()) {
            Some((UnitKind::Function, kw_loc)) => Err(stage_ref_in("function", at, kw_loc)),
            Some((UnitKind::Entity, kw_loc)) => Err(stage_ref_in("entity", at, kw_loc)),
            Some((UnitKind::Pipeline(_), _)) => Ok(()),
            None => Err(bug_no_item_context(at)),
        }
    }
}