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 _ => return Err(ParseError::LoadSource(path.as_ref().into())),
23 };
24
25 let mut buf = String::new();
26 file.read_to_string(&mut buf)?;
27
28 let mut source_file: Self = Parser::parse_rule(crate::parser::Rule::source_file, &buf, 0)?;
29 assert_ne!(source_file.hash, 0);
30 source_file.set_filename(path.as_ref());
31 source_file.name = name;
32 log::debug!(
33 "Successfully loaded external file {} to {}",
34 path.as_ref().to_string_lossy(),
35 source_file.name
36 );
37 log::trace!("Syntax tree:\n{}", FormatTree(&source_file));
38
39 Ok(Rc::new(source_file))
40 }
41
42 pub fn load_from_str(
45 name: &str,
46 path: impl AsRef<std::path::Path>,
47 source_str: &str,
48 ) -> ParseResult<Rc<Self>> {
49 log::trace!("{load} source from string", load = crate::mark!(LOAD));
50 let mut source_file: Self =
51 Parser::parse_rule(crate::parser::Rule::source_file, source_str, 0)?;
52 source_file.set_name(QualifiedName::from_id(Identifier::no_ref(name)));
53 source_file.set_filename(path);
54 log::debug!("Successfully loaded source from string");
55 log::trace!("Syntax tree:\n{}", FormatTree(&source_file));
56 Ok(Rc::new(source_file))
57 }
58
59 fn calculate_hash(value: &str) -> u64 {
60 use std::hash::{Hash, Hasher};
61 let mut hasher = rustc_hash::FxHasher::default();
62 value.hash(&mut hasher);
63 hasher.finish()
64 }
65
66 fn name_from_path(path: impl AsRef<std::path::Path>) -> QualifiedName {
68 QualifiedName::from_id(Identifier::no_ref(
69 &path
70 .as_ref()
71 .file_stem()
72 .expect("illegal file name")
73 .to_string_lossy(),
74 ))
75 }
76}
77
78impl Parse for SourceFile {
79 fn parse(mut pair: Pair) -> ParseResult<Self> {
80 let hash = Self::calculate_hash(pair.as_str());
82 pair.set_source_hash(hash);
83
84 Ok(SourceFile::new(
85 crate::find_rule_opt!(pair, doc_block),
86 crate::find_rule!(pair, statement_list)?,
87 pair.as_span().as_str().to_string(),
88 hash,
89 ))
90 }
91}
92
93#[test]
94fn parse_source_file() {
95 let source_file = Parser::parse_rule::<SourceFile>(
96 Rule::source_file,
97 r#"use std::log::info;
98 part Foo(r: Scalar) {
99 info("Hello, world, {r}!");
100 }
101 Foo(20.0);
102 "#,
103 0,
104 )
105 .expect("test error");
106
107 assert_eq!(source_file.statements.len(), 3);
108}