1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use std::path::PathBuf;

use derivative::Derivative;
use derive_more::{AsRef, Deref, Display, From, Into};
use fxhash::FxBuildHasher;
use indexmap::{IndexMap, IndexSet};
use smol_str::SmolStr;

pub type FxIndexMap<K, V> = IndexMap<K, V, FxBuildHasher>;
pub type FxIndexSet<T> = IndexSet<T, FxBuildHasher>;

#[derive(AsRef, Hash, From, Into, Clone, PartialEq, Eq, Derivative, Deref, Display)]
#[display(fmt = "{}", "_0.to_str().unwrap()")]
#[derivative(Debug = "transparent")]
pub struct SourceFilePath(PathBuf);

impl SourceFilePath {
  pub fn new(value: impl Into<PathBuf>) -> Self {
    Self(value.into())
  }

  pub fn read_contents(&self) -> Result<String, std::io::Error> {
    std::fs::read_to_string(self.as_path())
  }

  pub fn dir(&self) -> SourceFileDir {
    SourceFileDir(self.parent().unwrap().into())
  }

  pub fn file_prefix(&self) -> String {
    // file_prefix is only available in nightly
    let file_name = self.0.file_stem().unwrap().to_str().unwrap();
    let prefix = file_name.split('.').next().unwrap_or("");
    prefix.to_string()
  }
}

#[derive(AsRef, Hash, From, Into, Clone, PartialEq, Eq, Derivative, Deref, Display)]
#[display(fmt = "{}", "_0.to_str().unwrap()")]
#[derivative(Debug = "transparent")]
pub struct SourceFileDir(PathBuf);

impl SourceFileDir {
  pub fn new(value: impl Into<PathBuf>) -> Self {
    Self(value.into())
  }

  pub fn read_contents(&self) -> Result<String, std::io::Error> {
    std::fs::read_to_string(self.as_path())
  }
}

impl From<&SourceFilePath> for SourceFileDir {
  fn from(value: &SourceFilePath) -> Self {
    value.dir()
  }
}

/// Path used in the import statement
#[derive(AsRef, Hash, From, Into, Clone, PartialEq, Eq, Derivative, Deref, Display)]
#[display(fmt = "{}", "_0")]
#[derivative(Debug = "transparent")]
pub struct ImportedPath(SmolStr);

impl ImportedPath {
  pub fn new(value: impl Into<SmolStr>) -> Self {
    Self(value.into())
  }
}

#[derive(AsRef, Hash, From, Into, Clone, PartialEq, Eq, Derivative, Deref, Display)]
#[display(fmt = "{}", "_0")]
#[derivative(Debug = "transparent")]
pub struct SourceModuleName(SmolStr);

impl SourceModuleName {
  pub fn new(value: impl Into<SmolStr>) -> Self {
    Self(value.into())
  }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SourceLocation {
  /// 1-based line number.
  pub line_number: usize,
  /// 1-based column of the start of this span
  pub line_position: usize,
  /// 0-based Offset in code units (in bytes) of the start of the span.
  pub offset: usize,
  /// Length in code units (in bytes) of the span.
  pub length: usize,
}

impl From<&SourceLocation> for miette::SourceSpan {
  fn from(value: &SourceLocation) -> miette::SourceSpan {
    miette::SourceSpan::new(value.offset.into(), value.length)
  }
}