Skip to main content

yog_script_analyze/typeck/
commands.rs

1//! A `command "charge" { … }`: each method a way of running it (`/charge
2//! fill <target>`), taking who ran it (`Sender`) first, then arguments of
3//! the types the game parses (a number, a word or text, a player); what it
4//! `requires` refuses the others.
5
6use yog_ids::script_problem;
7use yog_script_ids::system::SENDER;
8
9use super::Checker;
10use super::model::Type;
11use crate::ast::{Decl, DeclKind, Method};
12
13impl Checker<'_, '_, '_> {
14    /// A command's ways of running, checked.
15    pub(super) fn command(&mut self, body: &[Decl]) {
16        for d in body {
17            match &d.kind {
18                DeclKind::Method(m) => {
19                    self.command_method(m);
20                    self.decl(d);
21                }
22                _ => self.report.error(
23                    script_problem::TYPE_MISMATCH,
24                    d.span,
25                    "a command holds the methods it's run by",
26                ),
27            }
28        }
29    }
30
31    /// Method `m` of a command: who ran it first, arguments the game parses.
32    fn command_method(&mut self, m: &Method) {
33        let mut params = m.params.iter();
34        let sender = params.next().map(|p| self.type_of(&p.ty));
35        if sender != Some(Type::own(SENDER.to_string())) {
36            self.report.error(
37                script_problem::TYPE_MISMATCH,
38                m.name.span,
39                format!("a command's method takes who ran it first: `{SENDER} source`"),
40            );
41        }
42        for p in params {
43            let t = self.type_of(&p.ty);
44            if command_arg(&t).is_none() {
45                self.report.error(
46                    script_problem::TYPE_MISMATCH,
47                    p.ty.span,
48                    format!(
49                        "a command's argument is a number, a `string` or a `Player`, not a `{t}`"
50                    ),
51                );
52            }
53        }
54    }
55}
56
57/// The game's argument type a command's parameter of type `t` is parsed as.
58pub fn command_arg(t: &Type) -> Option<&'static str> {
59    use yog_ids::command_arg::{FLOAT, INT, PLAYER, WORD};
60    match t {
61        Type::I32 => Some(INT),
62        Type::F32 | Type::F64 => Some(FLOAT),
63        Type::String => Some(WORD),
64        Type::Yog(name) if name == crate::yog::player() => Some(PLAYER),
65        _ => None,
66    }
67}