Skip to main content

yog_script_analyze/typeck/
content.rs

1//! A content declaration (`block Lamp { … }`) is its file's behaviour:
2//! what the block is — its strength, light, model, name — is in its file
3//! (`content/**/lamp.yblock`), the one place it's said; the declaration
4//! holds only fields, constructors and handlers, bound to that file by id.
5
6use yog_ids::{Format, script_problem};
7
8use super::Checker;
9use crate::ast::{Decl, DeclKind, Name};
10
11/// The path of content declaration `name`'s id (`Lamp`: `lamp`), in its
12/// mod's namespace: the file it binds to is `lamp.yblock`.
13pub fn content_path(name: &str) -> String {
14    yog_codegen::snake(name)
15}
16
17impl Checker<'_, '_, '_> {
18    /// Content declaration `name` of kind `word` (`body` its members):
19    /// no properties, and its file there when the mod's files are known.
20    pub(super) fn content_decl(&mut self, word: &str, name: &Name, body: &[Decl]) {
21        // A recipe's declaration is the recipe (`.yrecipe`'s other spelling).
22        if word == yog_ids::kind::RECIPE {
23            return;
24        }
25        let Some(format) = Format::ALL.iter().find(|f| f.noun() == word) else {
26            return;
27        };
28        let file = format.file(&content_path(&name.text));
29        for d in body {
30            if let DeclKind::Prop(p) = &d.kind {
31                self.expr(&p.value);
32                self.report.error(
33                    script_problem::CONTENT_PROPERTY,
34                    p.name.span,
35                    format!(
36                        "`{}` is said in `{file}`: a `{word}` declaration holds only its behaviour",
37                        p.name.text
38                    ),
39                );
40            }
41        }
42        let Some(content) = &self.content else {
43            return;
44        };
45        let path = content_path(&name.text);
46        let found = content
47            .iter()
48            .any(|(kind, id)| kind == word && yog_ids::split(id).1 == path);
49        if !found {
50            self.report.error(
51                script_problem::NO_CONTENT_FILE,
52                name.span,
53                format!(
54                    "no `{file}` under `{}/`: `{word} {}` is its behaviour",
55                    yog_ids::project::CONTENT,
56                    name.text
57                ),
58            );
59        }
60    }
61}