yog_script_analyze/typeck/
commands.rs1use 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 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 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
57pub 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}