rune/workspace/
build.rs
1use core::fmt;
2
3use crate::alloc;
4use crate::ast::Span;
5use crate::workspace::manifest::{Loader, Manifest};
6use crate::workspace::{Diagnostics, FileSourceLoader, SourceLoader, WorkspaceError};
7use crate::Sources;
8
9#[derive(Debug)]
11pub struct BuildError {
12 kind: BuildErrorKind,
13}
14
15impl BuildError {
16 pub(crate) const DEFAULT: Self = Self {
17 kind: BuildErrorKind::Default,
18 };
19}
20
21#[derive(Debug)]
22enum BuildErrorKind {
23 Default,
24 Alloc(alloc::Error),
25}
26
27impl From<alloc::Error> for BuildError {
28 fn from(error: alloc::Error) -> Self {
29 Self {
30 kind: BuildErrorKind::Alloc(error),
31 }
32 }
33}
34
35impl fmt::Display for BuildError {
36 #[inline]
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 match &self.kind {
39 BuildErrorKind::Default => {
40 write!(f, "Failed to load workspace (see diagnostics for details)")
41 }
42 BuildErrorKind::Alloc(error) => error.fmt(f),
43 }
44 }
45}
46
47impl core::error::Error for BuildError {}
48
49pub fn prepare(sources: &mut Sources) -> Build<'_> {
51 Build {
52 sources,
53 diagnostics: None,
54 source_loader: None,
55 }
56}
57
58pub struct Build<'a> {
60 sources: &'a mut Sources,
61 diagnostics: Option<&'a mut Diagnostics>,
62 source_loader: Option<&'a mut dyn SourceLoader>,
63}
64
65impl<'a> Build<'a> {
66 pub fn with_diagnostics(self, diagnostics: &'a mut Diagnostics) -> Self {
68 Self {
69 diagnostics: Some(diagnostics),
70 ..self
71 }
72 }
73
74 pub fn with_source_loader(self, source_loader: &'a mut dyn SourceLoader) -> Self {
78 Self {
79 source_loader: Some(source_loader),
80 ..self
81 }
82 }
83
84 pub fn build(self) -> Result<Manifest, BuildError> {
86 let mut diagnostics;
87
88 let diagnostics = match self.diagnostics {
89 Some(diagnostics) => diagnostics,
90 None => {
91 diagnostics = Diagnostics::new();
92 &mut diagnostics
93 }
94 };
95
96 let mut source_loader;
97
98 let source_loader = match self.source_loader {
99 Some(source_loader) => source_loader,
100 None => {
101 source_loader = FileSourceLoader::new();
102 &mut source_loader
103 }
104 };
105
106 let mut manifest = Manifest::default();
107
108 for id in self.sources.source_ids() {
109 let mut loader =
110 Loader::new(id, self.sources, diagnostics, source_loader, &mut manifest);
111
112 if let Err(error) = loader.load_manifest() {
113 diagnostics.fatal(id, WorkspaceError::new(Span::empty(), error))?;
114 }
115 }
116
117 if diagnostics.has_errors() {
118 return Err(BuildError::DEFAULT);
119 }
120
121 Ok(manifest)
122 }
123}