compose_library/
world.rs

1use crate::Library;
2use crate::diag::FileResult;
3use compose_codespan_reporting::files::Files;
4use compose_syntax::{FileId, Source, Span};
5use std::io::{Read, Write};
6use std::ops::Range;
7
8pub trait World {
9    /// The entrypoint file of the program to execute
10    fn entry_point(&self) -> FileId;
11
12    fn source(&self, file_id: FileId) -> FileResult<Source>;
13
14    fn library(&self) -> &Library;
15
16    fn write(&self, f: &dyn Fn(&mut dyn Write) -> std::io::Result<()>) -> std::io::Result<()>;
17    fn read(&self, f: &dyn Fn(&mut dyn Read) -> std::io::Result<()>) -> std::io::Result<()>;
18
19    fn name(&self, id: FileId) -> String {
20        id.path().0.display().to_string()
21    }
22
23    fn related_source(&self, span: Span) -> Option<Source> {
24        self.source(span.id()?).ok()
25    }
26}
27
28pub struct SyntaxContext<'a> {
29    pub world: &'a dyn World,
30}
31
32
33impl<'a> Files<'a> for &dyn World {
34    type FileId = FileId;
35    type Name = String;
36    type Source = Source;
37
38    fn name(&'a self, id: Self::FileId) -> Result<Self::Name, compose_codespan_reporting::files::Error> {
39        Ok(World::name(*self, id))
40    }
41
42    fn source(
43        &'a self,
44        id: Self::FileId,
45    ) -> Result<Self::Source, compose_codespan_reporting::files::Error> {
46        World::source(*self, id).map_err(|_| compose_codespan_reporting::files::Error::FileMissing)
47    }
48
49    fn line_index(
50        &'a self,
51        id: Self::FileId,
52        byte_index: usize,
53    ) -> Result<usize, compose_codespan_reporting::files::Error> {
54        let source = Files::source(self, id)?;
55        Ok(source
56            .line_starts()
57            .binary_search(&byte_index)
58            .unwrap_or_else(|next_line| next_line - 1))
59    }
60
61    fn line_range(
62        &'a self,
63        id: Self::FileId,
64        line_index: usize,
65    ) -> Result<Range<usize>, compose_codespan_reporting::files::Error> {
66        let source = Files::source(self, id)?;
67        let start = source.line_starts().get(line_index).copied().ok_or(
68            compose_codespan_reporting::files::Error::LineTooLarge {
69                given: line_index,
70                max: source.line_starts().len(),
71            },
72        )?;
73
74        let end = source
75            .line_starts()
76            .get(line_index + 1)
77            .copied()
78            .unwrap_or(source.text().len());
79
80        Ok(start..end)
81    }
82}