polar_core/
sources.rs

1use std::fmt::Write;
2use std::{fmt, sync::Arc};
3
4use serde::{Deserialize, Serialize};
5
6use crate::{formatting::source_lines, lexer::loc_to_pos};
7
8/// Parsed source context.
9#[derive(Clone)]
10pub struct Context {
11    pub source: Arc<Source>,
12    /// Start location within `source`.
13    pub left: usize,
14    /// End location within `source`.
15    pub right: usize,
16}
17
18impl fmt::Display for Context {
19    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
20        write!(f, "{}", self.source_position())?;
21        let lines = source_lines(&self.source, self.left, 0).replace('\n', "\n\t");
22        writeln!(f, ":\n\t{}", lines)?;
23        Ok(())
24    }
25}
26
27impl Context {
28    pub(crate) fn new(source: Arc<Source>, left: usize, right: usize) -> Self {
29        Self {
30            source,
31            left,
32            right,
33        }
34    }
35
36    pub(crate) fn source_position(&self) -> String {
37        let mut f = String::new();
38        let (row, column) = loc_to_pos(&self.source.src, self.left);
39        write!(f, " at line {}, column {}", row + 1, column + 1).unwrap();
40        if let Some(ref filename) = self.source.filename {
41            write!(f, " of file {}", filename).unwrap();
42        }
43        f
44    }
45}
46
47#[derive(Clone)]
48pub enum SourceInfo {
49    // From the parser
50    Parser(Context),
51
52    /// Created as a temporary variable
53    TemporaryVariable,
54
55    /// From an FFI call
56    Ffi,
57
58    /// Created for a test
59    Test,
60}
61
62impl fmt::Debug for SourceInfo {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        match self {
65            // Ignore inner `Context` when `Debug`-formatting `SourceInfo::Parser`.
66            Self::Parser(_) => f.write_str("SourceInfo::Parser"),
67            Self::TemporaryVariable => f.write_str("SourceInfo::TemporaryVariable"),
68            Self::Ffi => f.write_str("SourceInfo::Ffi"),
69            Self::Test => f.write_str("SourceInfo::Test"),
70        }
71    }
72}
73
74impl SourceInfo {
75    pub fn ffi() -> Self {
76        Self::Ffi
77    }
78
79    pub(crate) fn parser(source: Arc<Source>, left: usize, right: usize) -> Self {
80        Self::Parser(Context::new(source, left, right))
81    }
82}
83
84// TODO(gj): `Serialize` makes some `polar-wasm-api` tests easier to write. We could look into
85// https://serde.rs/remote-derive.html if we cared to preserve that while removing this impl.
86#[derive(PartialEq, Eq, Serialize, Deserialize)]
87pub struct Source {
88    pub filename: Option<String>,
89    pub src: String,
90}
91
92impl Source {
93    pub fn new<T: AsRef<str>>(src: T) -> Self {
94        Self {
95            filename: None,
96            src: src.as_ref().into(),
97        }
98    }
99
100    pub fn new_with_name<T: AsRef<str>, U: AsRef<str>>(filename: T, src: U) -> Self {
101        Self {
102            filename: Some(filename.as_ref().into()),
103            src: src.as_ref().into(),
104        }
105    }
106}