bend/fun/check/
set_entrypoint.rs

1use crate::{
2  diagnostics::WarningType,
3  fun::{Book, Ctx, Definition, Name},
4  ENTRY_POINT, HVM1_ENTRY_POINT,
5};
6
7#[derive(Debug, Clone)]
8pub enum EntryErr {
9  NotFound(Name),
10  Multiple(Vec<Name>),
11  MultipleRules,
12}
13
14impl Ctx<'_> {
15  pub fn set_entrypoint(&mut self) {
16    let mut entrypoint = None;
17
18    let (custom, main, hvm1_main) = self.book.get_possible_entry_points();
19    match (custom, main, hvm1_main) {
20      (Some(entry), None, None) | (None, Some(entry), None) | (None, None, Some(entry)) => {
21        match validate_entry_point(entry) {
22          Ok(name) => entrypoint = Some(name),
23          Err(err) => self.info.add_book_error(err),
24        }
25      }
26
27      (Some(a), Some(b), None) | (None, Some(a), Some(b)) | (Some(a), None, Some(b)) => {
28        self.info.add_book_error(EntryErr::Multiple(vec![a.name.clone(), b.name.clone()]));
29
30        match validate_entry_point(a) {
31          Ok(name) => entrypoint = Some(name),
32          Err(err) => self.info.add_book_error(err),
33        }
34      }
35
36      (Some(a), Some(b), Some(c)) => {
37        self.info.add_book_error(EntryErr::Multiple(vec![a.name.clone(), b.name.clone(), c.name.clone()]));
38
39        match validate_entry_point(a) {
40          Ok(name) => entrypoint = Some(name),
41          Err(err) => self.info.add_book_error(err),
42        }
43      }
44
45      (None, None, None) => {
46        let entrypoint = self.book.entrypoint.clone().unwrap_or(Name::new(ENTRY_POINT));
47        self.info.add_book_warning(EntryErr::NotFound(entrypoint), WarningType::MissingMain)
48      }
49    }
50
51    self.book.entrypoint = entrypoint;
52  }
53}
54
55fn validate_entry_point(entry: &Definition) -> Result<Name, EntryErr> {
56  if entry.rules.len() > 1 {
57    Err(EntryErr::MultipleRules)
58  } else {
59    Ok(entry.name.clone())
60  }
61}
62
63impl Book {
64  fn get_possible_entry_points(&self) -> (Option<&Definition>, Option<&Definition>, Option<&Definition>) {
65    let custom = self.entrypoint.as_ref().and_then(|e| self.defs.get(e));
66    let main = self.defs.get(&Name::new(ENTRY_POINT));
67    let hvm1_main = self.defs.get(&Name::new(HVM1_ENTRY_POINT));
68    (custom, main, hvm1_main)
69  }
70}
71
72impl std::fmt::Display for EntryErr {
73  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74    match self {
75      EntryErr::NotFound(name) => write!(f, "File has no '{name}' definition."),
76      EntryErr::Multiple(fnd) if fnd.len() == 2 => {
77        write!(f, "File has both '{}' and '{}' definitions.", fnd[0], fnd[1])
78      }
79      EntryErr::Multiple(fnd) => {
80        write!(f, "File has '{}', '{}' and '{}' definitions.", fnd[0], fnd[1], fnd[2])
81      }
82      EntryErr::MultipleRules => write!(f, "Main definition can't have more than one rule."),
83    }
84  }
85}