spade_parser/
item_type.rs

1use local_impl::local_impl;
2use spade_ast::UnitKind;
3use spade_common::location_info::Loc;
4use spade_diagnostics::Diagnostic;
5
6fn not_allowed_in_function(message: &str, at: Loc<()>, what: &str, kw_loc: Loc<()>) -> Diagnostic {
7    Diagnostic::error(at, message)
8        .primary_label(format!("{what} not allowed here"))
9        .secondary_label(kw_loc, "this is a function")
10        .note("functions can only contain combinatorial logic")
11        .span_suggest_replace("consider making the function an entity", kw_loc, "entity")
12}
13
14fn bug_no_item_context(at: Loc<()>) -> Diagnostic {
15    Diagnostic::bug(
16        at,
17        "attempted to parse something which requires an item context, but no item context exists",
18    )
19}
20
21fn stage_ref_in(what: &str, at: Loc<()>, kw_loc: Loc<()>) -> Diagnostic {
22    Diagnostic::error(at, format!("pipeline stage reference in {what}"))
23        .primary_label("pipeline stage reference not allowed here")
24        .secondary_label(kw_loc, format!("this is a {what}"))
25        .note("only pipelines can contain pipeline stage references")
26        .span_suggest_replace(
27            format!("consider making the {} a pipeline", what),
28            kw_loc,
29            "pipeline(/* depth */)",
30        )
31}
32
33#[local_impl]
34impl UnitKindLocal for Option<Loc<UnitKind>> {
35    fn allows_reg(&self, at: Loc<()>) -> Result<(), Diagnostic> {
36        match self.as_ref().map(|x| x.split_loc_ref()) {
37            Some((UnitKind::Function, kw_loc)) => Err(not_allowed_in_function(
38                "register declared in function",
39                at,
40                "register",
41                kw_loc,
42            )),
43            Some((UnitKind::Entity | UnitKind::Pipeline(_), _)) => Ok(()),
44            None => Err(bug_no_item_context(at)),
45        }
46    }
47
48    fn allows_inst(&self, at: Loc<()>) -> Result<(), Diagnostic> {
49        match self.as_ref().map(|x| x.split_loc_ref()) {
50            // FIXME: Choose "entities" or "pipelines" depending on what we try to instantiate
51            Some((UnitKind::Function, kw_loc)) => Err(not_allowed_in_function(
52                "cannot instantiate entities and pipelines in functions",
53                at,
54                "inst",
55                kw_loc,
56            )),
57            Some((UnitKind::Entity | UnitKind::Pipeline(_), _)) => Ok(()),
58            None => Err(bug_no_item_context(at)),
59        }
60    }
61
62    fn allows_pipeline_ref(&self, at: Loc<()>) -> Result<(), Diagnostic> {
63        match self.as_ref().map(|x| x.split_loc_ref()) {
64            Some((UnitKind::Function, kw_loc)) => Err(stage_ref_in("function", at, kw_loc)),
65            Some((UnitKind::Entity, kw_loc)) => Err(stage_ref_in("entity", at, kw_loc)),
66            Some((UnitKind::Pipeline(_), _)) => Ok(()),
67            None => Err(bug_no_item_context(at)),
68        }
69    }
70}