microcad_lang/parse/
source_file.rs1use crate::{parse::*, parser::*, rc::*, tree_display::*};
5use std::io::Read;
6
7impl SourceFile {
8 pub fn load(path: impl AsRef<std::path::Path> + std::fmt::Debug) -> ParseResult<Rc<Self>> {
10 Self::load_with_name(&path, Self::name_from_path(&path))
11 }
12
13 pub fn load_with_name(
15 path: impl AsRef<std::path::Path> + std::fmt::Debug,
16 name: QualifiedName,
17 ) -> ParseResult<Rc<Self>> {
18 log::trace!("{load} file {path:?} [{name}]", load = crate::mark!(LOAD));
19
20 let mut file = match std::fs::File::open(&path) {
21 Ok(file) => file,
22 _ => {
23 return Err(ParseError::LoadSource(Refer::new(
24 path.as_ref().into(),
25 name.src_ref(),
26 )))
27 }
28 };
29
30 let mut buf = String::new();
31 if let Err(err) = file.read_to_string(&mut buf) {
32 return Err(ParseError::IoError(Refer::new(err, name.src_ref())));
33 }
34
35 let mut source_file: Self = Parser::parse_rule(crate::parser::Rule::source_file, &buf, 0)?;
36 assert_ne!(source_file.hash, 0);
37 source_file.set_filename(path.as_ref());
38 source_file.name = name;
39 log::debug!(
40 "Successfully loaded external file {} to {}",
41 path.as_ref().to_string_lossy(),
42 source_file.name
43 );
44 log::trace!("Syntax tree:\n{}", FormatTree(&source_file));
45
46 Ok(Rc::new(source_file))
47 }
48
49 pub fn load_from_str(
52 name: Option<&str>,
53 path: impl AsRef<std::path::Path>,
54 source_str: &str,
55 ) -> ParseResult<Rc<Self>> {
56 log::trace!("{load} source from string", load = crate::mark!(LOAD));
57 let mut source_file: Self =
58 Parser::parse_rule(crate::parser::Rule::source_file, source_str, 0)?;
59 if let Some(name) = name {
60 source_file.set_name(QualifiedName::from_id(Identifier::no_ref(name)));
61 } else {
62 source_file.set_name(Self::name_from_path(&path));
63 };
64 source_file.set_filename(path);
65 log::debug!("Successfully loaded source from string");
66 log::trace!("Syntax tree:\n{}", FormatTree(&source_file));
67 Ok(Rc::new(source_file))
68 }
69
70 fn calculate_hash(value: &str) -> u64 {
71 use std::hash::{Hash, Hasher};
72 let mut hasher = rustc_hash::FxHasher::default();
73 value.hash(&mut hasher);
74 hasher.finish()
75 }
76
77 pub fn name_from_path(path: impl AsRef<std::path::Path>) -> QualifiedName {
79 QualifiedName::from_id(Identifier::no_ref(
80 &path
81 .as_ref()
82 .file_stem()
83 .expect("illegal file name")
84 .to_string_lossy(),
85 ))
86 }
87}
88
89impl Parse for SourceFile {
90 fn parse(mut pair: Pair) -> ParseResult<Self> {
91 let hash = Self::calculate_hash(pair.as_str());
93 pair.set_source_hash(hash);
94
95 Ok(SourceFile::new(
96 crate::find_rule_opt!(pair, doc_block),
97 crate::find_rule!(pair, statement_list)?,
98 pair.as_span().as_str().to_string(),
99 hash,
100 ))
101 }
102}
103
104#[test]
105fn parse_source_file() {
106 let source_file = Parser::parse_rule::<SourceFile>(
107 Rule::source_file,
108 r#"use std::log::info;
109 part Foo(r: Scalar) {
110 info("Hello, world, {r}!");
111 }
112 Foo(20.0);
113 "#,
114 0,
115 )
116 .expect("test error");
117
118 assert_eq!(source_file.statements.len(), 3);
119}