1use crate::Abi;
2use std::collections::{HashMap, HashSet};
3use std::rc::Rc;
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
6pub struct Id(String);
7
8impl Id {
9 pub fn new<S: AsRef<str>>(s: S) -> Self {
10 Id(s.as_ref().to_string())
11 }
12 pub fn as_str(&self) -> &str {
13 self.0.as_str()
14 }
15}
16
17impl AsRef<str> for Id {
18 fn as_ref(&self) -> &str {
19 self.0.as_ref()
20 }
21}
22
23impl PartialEq<&str> for Id {
24 fn eq(&self, rhs: &&str) -> bool {
25 PartialEq::eq(self.as_ref(), *rhs)
26 }
27}
28
29impl PartialEq<Id> for &str {
30 fn eq(&self, rhs: &Id) -> bool {
31 PartialEq::eq(*self, rhs.as_ref())
32 }
33}
34
35impl From<&str> for Id {
36 fn from(s: &str) -> Self {
37 Self::new(s)
38 }
39}
40
41#[derive(Debug, Clone)]
42pub struct Module {
43 name: Id,
44 module_id: ModuleId,
45 types: Vec<Rc<NamedType>>,
46 type_map: HashMap<Id, Rc<NamedType>>,
47
48 resources: Vec<Rc<Resource>>,
49 resource_map: HashMap<Id, Rc<Resource>>,
50
51 funcs: Vec<Rc<Function>>,
52 func_map: HashMap<Id, Rc<Function>>,
53
54 constants: Vec<Constant>,
55}
56
57#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
58pub struct ModuleId(pub(crate) Rc<std::path::PathBuf>);
59
60impl Module {
61 pub(crate) fn new(name: Id, module_id: ModuleId) -> Module {
62 Module {
63 name,
64 module_id,
65 types: Default::default(),
66 type_map: Default::default(),
67 resources: Default::default(),
68 resource_map: Default::default(),
69 funcs: Default::default(),
70 func_map: Default::default(),
71 constants: Default::default(),
72 }
73 }
74
75 pub fn name(&self) -> &Id {
76 &self.name
77 }
78
79 pub fn module_id(&self) -> &ModuleId {
80 &self.module_id
81 }
82
83 pub(crate) fn push_type(&mut self, ty: Rc<NamedType>) {
84 assert!(self.type_map.insert(ty.name.clone(), ty.clone()).is_none());
85 self.types.push(ty);
86 }
87
88 pub(crate) fn push_resource(&mut self, r: Rc<Resource>) {
89 assert!(self
90 .resource_map
91 .insert(r.name.clone(), r.clone())
92 .is_none());
93 self.resources.push(r);
94 }
95
96 pub(crate) fn push_func(&mut self, func: Rc<Function>) {
97 assert!(self
98 .func_map
99 .insert(func.name.clone(), func.clone())
100 .is_none());
101 self.funcs.push(func);
102 }
103
104 pub(crate) fn push_constant(&mut self, constant: Constant) {
105 self.constants.push(constant);
106 }
107
108 pub fn typename(&self, name: &Id) -> Option<Rc<NamedType>> {
109 self.type_map.get(name).cloned()
110 }
111
112 pub fn typenames<'a>(&'a self) -> impl Iterator<Item = &'a Rc<NamedType>> + 'a {
113 self.types.iter()
114 }
115
116 pub fn resource(&self, name: &Id) -> Option<Rc<Resource>> {
117 self.resource_map.get(name).cloned()
118 }
119
120 pub fn resources<'a>(&'a self) -> impl Iterator<Item = &'a Rc<Resource>> + 'a {
121 self.resources.iter()
122 }
123
124 pub fn error_types<'a>(&'a self) -> impl Iterator<Item = TypeRef> + 'a {
127 let errors: HashSet<TypeRef> = self
128 .funcs()
129 .filter_map(|f| {
130 if f.results.len() == 1 {
131 Some(f.results[0].tref.type_().clone())
132 } else {
133 None
134 }
135 })
136 .filter_map(|t| match &*t {
137 Type::Variant(v) => {
138 let (_ok, err) = v.as_expected()?;
139 Some(err?.clone())
140 }
141 _ => None,
142 })
143 .collect::<HashSet<TypeRef>>();
144 errors.into_iter()
145 }
146
147 pub fn func(&self, name: &Id) -> Option<Rc<Function>> {
148 self.func_map.get(&name).cloned()
149 }
150
151 pub fn funcs<'a>(&'a self) -> impl Iterator<Item = Rc<Function>> + 'a {
152 self.funcs.iter().cloned()
153 }
154
155 pub fn constants<'a>(&'a self) -> impl Iterator<Item = &'a Constant> + 'a {
156 self.constants.iter()
157 }
158}
159
160#[derive(Debug, Clone, PartialEq, Eq, Hash)]
161pub enum TypeRef {
162 Name(Rc<NamedType>),
163 Value(Rc<Type>),
164}
165
166impl TypeRef {
167 pub fn type_(&self) -> &Rc<Type> {
168 match self {
169 TypeRef::Name(named) => named.type_(),
170 TypeRef::Value(v) => v,
171 }
172 }
173
174 pub fn name(&self) -> Option<&NamedType> {
175 match self {
176 TypeRef::Name(n) => Some(n),
177 TypeRef::Value(_) => None,
178 }
179 }
180
181 pub fn named(&self) -> bool {
182 match self {
183 TypeRef::Name(_) => true,
184 TypeRef::Value(_) => false,
185 }
186 }
187
188 pub fn type_equal(&self, other: &TypeRef) -> bool {
189 self.type_().type_equal(other.type_())
190 }
191}
192
193#[derive(Debug, Clone, PartialEq, Eq, Hash)]
194pub struct NamedType {
195 pub name: Id,
196 pub module: ModuleId,
197 pub tref: TypeRef,
198 pub docs: String,
199}
200
201impl NamedType {
202 pub fn type_(&self) -> &Rc<Type> {
203 self.tref.type_()
204 }
205}
206
207#[derive(Debug, Clone, PartialEq, Eq, Hash)]
213pub enum Type {
214 Record(RecordDatatype),
216 Variant(Variant),
218 Handle(HandleDatatype),
222 List(TypeRef),
226 Pointer(TypeRef),
229 ConstPointer(TypeRef),
232 Buffer(Buffer),
234 Builtin(BuiltinType),
236}
237
238impl Type {
239 pub fn kind(&self) -> &'static str {
241 use Type::*;
242 match self {
243 Record(_) => "record",
244 Variant(_) => "variant",
245 Handle(_) => "handle",
246 List(_) => "list",
247 Pointer(_) => "pointer",
248 ConstPointer(_) => "constpointer",
249 Buffer(_) => "buffer",
250 Builtin(_) => "builtin",
251 }
252 }
253
254 pub fn all_bits_valid(&self) -> bool {
260 match self {
261 Type::Record(r) => r.members.iter().all(|t| t.tref.type_().all_bits_valid()),
262
263 Type::Builtin(BuiltinType::Char)
264 | Type::Variant(_)
265 | Type::Handle(_)
266 | Type::Buffer(_)
267 | Type::List(_) => false,
268
269 Type::Builtin(BuiltinType::U8 { .. })
270 | Type::Builtin(BuiltinType::S8)
271 | Type::Builtin(BuiltinType::U16)
272 | Type::Builtin(BuiltinType::S16)
273 | Type::Builtin(BuiltinType::U32 { .. })
274 | Type::Builtin(BuiltinType::S32)
275 | Type::Builtin(BuiltinType::U64)
276 | Type::Builtin(BuiltinType::S64)
277 | Type::Builtin(BuiltinType::F32)
278 | Type::Builtin(BuiltinType::F64)
279 | Type::Pointer(_)
280 | Type::ConstPointer(_) => true,
281 }
282 }
283
284 pub fn type_equal(&self, other: &Type) -> bool {
285 match self {
286 Type::Record(a) => match other {
287 Type::Record(b) => a.type_equal(b),
288 _ => false,
289 },
290 Type::Variant(a) => match other {
291 Type::Variant(b) => a.type_equal(b),
292 _ => false,
293 },
294 Type::Handle(a) => match other {
295 Type::Handle(b) => a.type_equal(b),
296 _ => false,
297 },
298 Type::List(a) => match other {
299 Type::List(b) => a.type_equal(b),
300 _ => false,
301 },
302 Type::Pointer(a) => match other {
303 Type::Pointer(b) => a.type_equal(b),
304 _ => false,
305 },
306 Type::ConstPointer(a) => match other {
307 Type::ConstPointer(b) => a.type_equal(b),
308 _ => false,
309 },
310 Type::Builtin(a) => match other {
311 Type::Builtin(b) => a == b,
312 _ => false,
313 },
314 Type::Buffer(a) => match other {
315 Type::Buffer(b) => a.type_equal(b),
316 _ => false,
317 },
318 }
319 }
320}
321
322#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
323pub enum BuiltinType {
324 Char,
328 U8 {
330 lang_c_char: bool,
339 },
340 U16,
342 U32 {
344 lang_ptr_size: bool,
353 },
354 U64,
356 S8,
358 S16,
360 S32,
362 S64,
364 F32,
366 F64,
368}
369
370#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
371pub enum IntRepr {
372 U8,
373 U16,
374 U32,
375 U64,
376}
377
378impl IntRepr {
379 pub fn to_builtin(&self) -> BuiltinType {
380 match self {
381 IntRepr::U8 => BuiltinType::U8 { lang_c_char: false },
382 IntRepr::U16 => BuiltinType::U16,
383 IntRepr::U32 => BuiltinType::U32 {
384 lang_ptr_size: false,
385 },
386 IntRepr::U64 => BuiltinType::U64,
387 }
388 }
389}
390
391#[derive(Debug, Clone, PartialEq, Eq, Hash)]
397pub struct RecordDatatype {
398 pub kind: RecordKind,
404
405 pub members: Vec<RecordMember>,
407}
408
409#[derive(Debug, Clone, PartialEq, Eq, Hash)]
411pub enum RecordKind {
412 Tuple,
415 Bitflags(IntRepr),
418 Other,
420}
421
422#[derive(Debug, Clone, PartialEq, Eq, Hash)]
423pub struct RecordMember {
424 pub name: Id,
425 pub tref: TypeRef,
426 pub docs: String,
427}
428
429impl RecordDatatype {
430 pub fn is_tuple(&self) -> bool {
431 match self.kind {
432 RecordKind::Tuple => true,
433 _ => false,
434 }
435 }
436
437 pub fn bitflags_repr(&self) -> Option<IntRepr> {
438 match self.kind {
439 RecordKind::Bitflags(i) => Some(i),
440 _ => None,
441 }
442 }
443
444 pub fn type_equal(&self, other: &RecordDatatype) -> bool {
445 self.members.len() == other.members.len()
450 && self
451 .members
452 .iter()
453 .zip(&other.members)
454 .all(|(a, b)| a.type_equal(b))
455 }
456}
457
458impl RecordMember {
459 pub fn type_equal(&self, other: &RecordMember) -> bool {
460 self.name == other.name && self.tref.type_equal(&other.tref)
461 }
462}
463
464impl RecordKind {
465 pub fn infer(members: &[RecordMember]) -> RecordKind {
466 if members.len() == 0 {
467 return RecordKind::Other;
468 }
469
470 if members.iter().all(|t| is_bool(&t.tref)) {
472 match members.len() {
473 n if n <= 8 => return RecordKind::Bitflags(IntRepr::U8),
474 n if n <= 16 => return RecordKind::Bitflags(IntRepr::U16),
475 n if n <= 32 => return RecordKind::Bitflags(IntRepr::U32),
476 n if n <= 64 => return RecordKind::Bitflags(IntRepr::U64),
477 _ => {}
478 }
479 }
480
481 if members
483 .iter()
484 .enumerate()
485 .all(|(i, m)| m.name.as_str().parse().ok() == Some(i))
486 {
487 return RecordKind::Tuple;
488 }
489
490 return RecordKind::Other;
491
492 fn is_bool(t: &TypeRef) -> bool {
493 match &**t.type_() {
494 Type::Variant(v) => v.is_bool(),
495 _ => false,
496 }
497 }
498 }
499}
500
501#[derive(Debug, Clone, PartialEq, Eq, Hash)]
513pub struct Variant {
514 pub tag_repr: IntRepr,
517 pub cases: Vec<Case>,
519}
520
521impl Variant {
522 pub fn infer_repr(cases: usize) -> IntRepr {
523 match cases {
524 n if n < u8::max_value() as usize => IntRepr::U8,
525 n if n < u16::max_value() as usize => IntRepr::U16,
526 n if n < u32::max_value() as usize => IntRepr::U32,
527 n if n < u64::max_value() as usize => IntRepr::U64,
528 _ => panic!("too many cases to fit in a repr"),
529 }
530 }
531
532 pub fn as_option(&self) -> Option<&TypeRef> {
543 if self.cases.len() != 2 {
544 return None;
545 }
546 if self.cases[0].name != "none" || self.cases[0].tref.is_some() {
547 return None;
548 }
549 if self.cases[1].name != "some" {
550 return None;
551 }
552 self.cases[1].tref.as_ref()
553 }
554
555 pub fn as_expected(&self) -> Option<(Option<&TypeRef>, Option<&TypeRef>)> {
566 if self.cases.len() != 2 {
567 return None;
568 }
569 if self.cases[0].name != "ok" {
570 return None;
571 }
572 if self.cases[1].name != "err" {
573 return None;
574 }
575 Some((self.cases[0].tref.as_ref(), self.cases[1].tref.as_ref()))
576 }
577
578 pub fn is_bool(&self) -> bool {
587 self.cases.len() == 2
588 && self.cases[0].name == "false"
589 && self.cases[1].name == "true"
590 && self.cases[0].tref.is_none()
591 && self.cases[1].tref.is_none()
592 }
593
594 pub fn is_enum(&self) -> bool {
597 self.cases.iter().all(|c| c.tref.is_none())
598 }
599
600 pub fn type_equal(&self, other: &Variant) -> bool {
601 self.tag_repr == other.tag_repr
604 && self.cases.len() == other.cases.len()
605 && self
606 .cases
607 .iter()
608 .zip(&other.cases)
609 .all(|(a, b)| a.type_equal(b))
610 }
611}
612
613#[derive(Debug, Clone, PartialEq, Eq, Hash)]
615pub struct Case {
616 pub name: Id,
618 pub tref: Option<TypeRef>,
621 pub docs: String,
623}
624
625impl Case {
626 pub fn type_equal(&self, other: &Case) -> bool {
627 self.name == other.name
628 && match (&self.tref, &other.tref) {
629 (Some(a), Some(b)) => a.type_equal(b),
630 (None, None) => true,
631 _ => false,
632 }
633 }
634}
635
636#[derive(Debug, Clone, PartialEq, Eq, Hash)]
637pub struct Resource {
638 pub name: Id,
641 pub resource_id: ResourceId,
643 pub docs: String,
645}
646
647#[derive(Debug, Clone, PartialEq, Eq, Hash)]
653pub struct ResourceId {
654 pub name: Id,
655 pub module_id: ModuleId,
656}
657
658#[derive(Debug, Clone, PartialEq, Eq, Hash)]
659pub struct HandleDatatype {
660 pub resource_id: ResourceId,
663}
664
665impl HandleDatatype {
666 pub fn type_equal(&self, other: &HandleDatatype) -> bool {
667 self.resource_id == other.resource_id
668 }
669}
670
671#[derive(Debug, Clone, PartialEq, Eq, Hash)]
672pub struct Function {
673 pub abi: Abi,
674 pub name: Id,
675 pub params: Vec<Param>,
676 pub results: Vec<Param>,
677 pub noreturn: bool,
678 pub docs: String,
679}
680
681#[derive(Debug, Clone, PartialEq, Eq, Hash)]
682pub struct Param {
683 pub name: Id,
684 pub tref: TypeRef,
685 pub docs: String,
686}
687
688#[derive(Debug, Clone, PartialEq, Eq, Hash)]
689pub struct Constant {
690 pub ty: Id,
691 pub name: Id,
692 pub value: u64,
693 pub docs: String,
694}
695
696#[derive(Debug, Clone, PartialEq, Eq, Hash)]
697pub struct Buffer {
698 pub out: bool,
701
702 pub tref: TypeRef,
704}
705
706impl Buffer {
707 pub fn type_equal(&self, other: &Buffer) -> bool {
708 self.out == other.out && self.tref.type_equal(&other.tref)
709 }
710}