yog_script_analyze/typeck/
model.rs1use std::fmt;
5
6use super::builtin;
7
8#[derive(Debug, Clone, PartialEq)]
10pub enum Type {
11 I8,
12 I16,
13 I32,
14 I64,
15 U8,
16 U16,
17 U32,
18 U64,
19 F32,
20 F64,
21 Decimal,
22 Char,
23 Bool,
24 String,
25 Object,
27 Dynamic,
29 Void,
30 Null,
32 Text,
34 Unit(String),
36 Content(String),
38 Tag,
39 Own(String, Vec<Type>),
42 Param(String),
45 Static(String),
48 Game(String),
50 Yog(String),
53 Namespace(String),
55 List(Box<Type>),
56 Map(Box<Type>, Box<Type>),
57 Tuple(Vec<Type>),
58 Fn(Vec<Type>, Box<Type>),
60 Nullable(Box<Type>),
61 Unknown,
64}
65
66pub const TICKS: &str = "Ticks";
68pub const SECONDS: &str = "Seconds";
69pub const BLOCKS: &str = "Blocks";
70
71impl Type {
72 pub fn own(name: impl Into<String>) -> Type {
74 Type::Own(name.into(), Vec::new())
75 }
76
77 pub fn nullable(self) -> Type {
78 match self {
79 Type::Nullable(_) | Type::Null | Type::Unknown => self,
80 other => Type::Nullable(Box::new(other)),
81 }
82 }
83
84 pub fn non_null(&self) -> &Type {
86 match self {
87 Type::Nullable(t) => t,
88 t => t,
89 }
90 }
91
92 pub fn is_nullable(&self) -> bool {
93 matches!(self, Type::Nullable(_) | Type::Null)
94 }
95
96 pub fn known(&self) -> bool {
97 !matches!(self, Type::Unknown)
98 }
99
100 pub fn is_numeric(&self) -> bool {
101 builtin::is_number(self) || matches!(self, Type::Unit(_))
102 }
103
104 pub fn converts_to(&self, to: &Type) -> bool {
106 if self == to || !self.known() || !to.known() {
107 return true;
108 }
109 if matches!(self, Type::Dynamic) || matches!(to, Type::Dynamic | Type::Object) {
110 return true;
111 }
112 match (self, to) {
113 (Type::Null, Type::Nullable(_)) => true,
114 (Type::Nullable(a), Type::Nullable(b)) => a.converts_to(b),
115 (a, Type::Nullable(b)) => a.converts_to(b),
116 (Type::Unit(a), Type::Unit(b)) => a == SECONDS && b == TICKS,
117 (n, Type::Unit(_)) => builtin::is_number(n),
120 (Type::Unit(_), n) => builtin::widens(&Type::I32, n),
121 (Type::String, Type::Text) => true,
122 (Type::List(a), Type::List(b)) => a.converts_to(b),
123 (a, b) => builtin::widens(a, b),
124 }
125 }
126
127 pub fn wider(a: &Type, b: &Type) -> Type {
129 match (a, b) {
130 (Type::Unit(_), _) => a.clone(),
131 (_, Type::Unit(_)) => b.clone(),
132 _ if builtin::widens(a, b) => b.clone(),
133 _ => a.clone(),
134 }
135 }
136}
137
138impl fmt::Display for Type {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 match self {
141 Type::I8
142 | Type::I16
143 | Type::I32
144 | Type::I64
145 | Type::U8
146 | Type::U16
147 | Type::U32
148 | Type::U64
149 | Type::F32
150 | Type::F64
151 | Type::Decimal
152 | Type::Char
153 | Type::Bool
154 | Type::String
155 | Type::Object
156 | Type::Dynamic
157 | Type::Void => write!(f, "{}", builtin::word(self).unwrap_or_default()),
158 Type::Null => write!(f, "{}", crate::words::null::WORD.text),
159 Type::Text => write!(f, "Text"),
160 Type::Own(name, args) if !args.is_empty() => {
161 let args: Vec<_> = args.iter().map(ToString::to_string).collect();
162 write!(f, "{name}<{}>", args.join(", "))
163 }
164 Type::Unit(u)
165 | Type::Own(u, _)
166 | Type::Static(u)
167 | Type::Param(u)
168 | Type::Yog(u)
169 | Type::Namespace(u) => {
170 write!(f, "{u}")
171 }
172 Type::Content(kind) => write!(f, "@{kind}"),
173 Type::Tag => write!(f, "{}", yog_ids::kind::TAG),
174 Type::Game(name) => write!(f, "{}", crate::index::simple_name(name)),
175 Type::List(t) => write!(f, "List<{t}>"),
176 Type::Map(k, v) => write!(f, "Dictionary<{k}, {v}>"),
177 Type::Tuple(items) => {
178 let items: Vec<_> = items.iter().map(ToString::to_string).collect();
179 write!(f, "({})", items.join(", "))
180 }
181 Type::Fn(params, ret) => {
182 let mut all: Vec<String> = params.iter().map(ToString::to_string).collect();
183 let word = if **ret == Type::Void {
184 super::written::ACTION
185 } else {
186 all.push(ret.to_string());
187 super::written::FUNC
188 };
189 write!(f, "{word}<{}>", all.join(", "))
190 }
191 Type::Nullable(t) => write!(f, "{t}?"),
192 Type::Unknown => write!(f, "?"),
193 }
194 }
195}
196
197#[cfg(test)]
198mod tests;