microcad_lang/syntax/source_file/
mod.rs1use crate::{src_ref::*, syntax::*};
7
8#[derive(Clone, Default)]
10pub struct SourceFile {
11 pub doc: Option<DocBlock>,
13 pub name: QualifiedName,
15 pub statements: StatementList,
17 filename: Option<std::path::PathBuf>,
19 pub source: String,
21
22 pub hash: u64,
27}
28
29impl SourceFile {
30 pub fn new(
32 doc: Option<DocBlock>,
33 statements: StatementList,
34 source: String,
35 hash: u64,
36 ) -> Self {
37 Self {
38 doc,
39 statements,
40 source,
41 hash,
42 ..Default::default()
43 }
44 }
45 pub fn filename(&self) -> std::path::PathBuf {
47 self.filename
48 .clone()
49 .unwrap_or(std::path::PathBuf::from(crate::invalid_no_ansi!(SOURCE)))
50 }
51
52 pub fn set_filename(&mut self, path: impl AsRef<std::path::Path>) {
54 assert!(self.filename.is_none());
55 self.filename = Some(
56 path.as_ref()
57 .canonicalize()
58 .unwrap_or(path.as_ref().to_path_buf()),
59 )
60 }
61
62 pub fn filename_as_str(&self) -> &str {
64 self.filename
65 .as_ref()
66 .map(|f| f.to_str().expect("File name error {filename:?}"))
67 .unwrap_or(crate::invalid!(SOURCE))
68 }
69
70 pub fn id(&self) -> Identifier {
72 self.name.last().unwrap_or(&Identifier::none()).clone()
73 }
74
75 pub fn get_line(&self, line: usize) -> Option<&str> {
79 self.source.lines().nth(line)
80 }
81
82 pub fn get_code(&self, src_ref: &SrcRef) -> &str {
86 let range = &src_ref.as_ref().expect("source reference empty").range;
87 &self.source[range.start..range.end]
88 }
89
90 pub fn num_lines(&self) -> usize {
92 self.source.lines().count()
93 }
94
95 pub fn set_name(&mut self, name: QualifiedName) {
97 self.name = name
98 }
99}
100
101impl std::fmt::Display for SourceFile {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 self.statements.iter().try_for_each(|s| writeln!(f, "{s}"))
104 }
105}
106
107impl std::fmt::Debug for SourceFile {
108 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109 self.statements
110 .iter()
111 .try_for_each(|s| writeln!(f, "{s:?}"))
112 }
113}
114
115impl TreeDisplay for SourceFile {
116 fn tree_print(&self, f: &mut std::fmt::Formatter, mut depth: TreeState) -> std::fmt::Result {
117 writeln!(
118 f,
119 "{:depth$}SourceFile '{:?}' ({}):",
120 "",
121 self.id(),
122 self.filename_as_str()
123 )?;
124 depth.indent();
125 if let Some(doc) = &self.doc {
126 doc.tree_print(f, depth)?;
127 }
128 self.statements
129 .iter()
130 .try_for_each(|s| s.tree_print(f, depth))
131 }
132}
133
134impl SrcReferrer for SourceFile {
135 fn src_ref(&self) -> crate::src_ref::SrcRef {
136 SrcRef::new(0..self.num_lines(), 0, 0, self.hash)
137 }
138}
139
140impl Doc for SourceFile {
141 fn doc(&self) -> Option<DocBlock> {
142 self.doc.clone()
143 }
144}
145
146#[test]
147fn load_source_file_wrong_location() {
148 let source_file = SourceFile::load("I do not exist.µcad");
149 if let Err(err) = source_file {
150 log::info!("{err}");
151 } else {
153 panic!("Does file exist?");
154 }
155}