bend-lang 0.2.38

A high-level, massively parallel programming language
Documentation
use crate::{
  diagnostics::WarningType,
  fun::{Book, Ctx, Definition, Name},
  ENTRY_POINT, HVM1_ENTRY_POINT,
};

#[derive(Debug, Clone)]
pub enum EntryErr {
  NotFound(Name),
  Multiple(Vec<Name>),
  MultipleRules,
}

impl Ctx<'_> {
  pub fn set_entrypoint(&mut self) {
    let mut entrypoint = None;

    let (custom, main, hvm1_main) = self.book.get_possible_entry_points();
    match (custom, main, hvm1_main) {
      (Some(entry), None, None) | (None, Some(entry), None) | (None, None, Some(entry)) => {
        match validate_entry_point(entry) {
          Ok(name) => entrypoint = Some(name),
          Err(err) => self.info.add_book_error(err),
        }
      }

      (Some(a), Some(b), None) | (None, Some(a), Some(b)) | (Some(a), None, Some(b)) => {
        self.info.add_book_error(EntryErr::Multiple(vec![a.name.clone(), b.name.clone()]));

        match validate_entry_point(a) {
          Ok(name) => entrypoint = Some(name),
          Err(err) => self.info.add_book_error(err),
        }
      }

      (Some(a), Some(b), Some(c)) => {
        self.info.add_book_error(EntryErr::Multiple(vec![a.name.clone(), b.name.clone(), c.name.clone()]));

        match validate_entry_point(a) {
          Ok(name) => entrypoint = Some(name),
          Err(err) => self.info.add_book_error(err),
        }
      }

      (None, None, None) => {
        let entrypoint = self.book.entrypoint.clone().unwrap_or(Name::new(ENTRY_POINT));
        self.info.add_book_warning(EntryErr::NotFound(entrypoint), WarningType::MissingMain)
      }
    }

    self.book.entrypoint = entrypoint;
  }
}

fn validate_entry_point(entry: &Definition) -> Result<Name, EntryErr> {
  if entry.rules.len() > 1 {
    Err(EntryErr::MultipleRules)
  } else {
    Ok(entry.name.clone())
  }
}

impl Book {
  fn get_possible_entry_points(&self) -> (Option<&Definition>, Option<&Definition>, Option<&Definition>) {
    let custom = self.entrypoint.as_ref().and_then(|e| self.defs.get(e));
    let main = self.defs.get(&Name::new(ENTRY_POINT));
    let hvm1_main = self.defs.get(&Name::new(HVM1_ENTRY_POINT));
    (custom, main, hvm1_main)
  }
}

impl std::fmt::Display for EntryErr {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    match self {
      EntryErr::NotFound(name) => write!(f, "File has no '{name}' definition."),
      EntryErr::Multiple(fnd) if fnd.len() == 2 => {
        write!(f, "File has both '{}' and '{}' definitions.", fnd[0], fnd[1])
      }
      EntryErr::Multiple(fnd) => {
        write!(f, "File has '{}', '{}' and '{}' definitions.", fnd[0], fnd[1], fnd[2])
      }
      EntryErr::MultipleRules => write!(f, "Main definition can't have more than one rule."),
    }
  }
}