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 let name = QualifiedName::from_id(Identifier::no_ref(
11 &path
12 .as_ref()
13 .file_stem()
14 .expect("illegal file name")
15 .to_string_lossy(),
16 ));
17 Self::load_with_name(path, name)
18 }
19
20 pub fn load_with_name(
22 path: impl AsRef<std::path::Path> + std::fmt::Debug,
23 name: QualifiedName,
24 ) -> ParseResult<Rc<Self>> {
25 log::trace!("{load} file {path:?} [{name}]", load = crate::mark!(LOAD));
26
27 let mut file = match std::fs::File::open(&path) {
28 Ok(file) => file,
29 _ => return Err(ParseError::LoadSource(path.as_ref().into())),
30 };
31
32 let mut buf = String::new();
33 file.read_to_string(&mut buf)?;
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(name: &str, s: &str) -> ParseResult<Rc<Self>> {
52 log::trace!("{load} source from string", load = crate::mark!(LOAD));
53 let mut source_file: Self = Parser::parse_rule(crate::parser::Rule::source_file, s, 0)?;
54 source_file.set_name(QualifiedName::from_id(Identifier::no_ref(name)));
55 log::debug!("Successfully loaded source from string");
56 log::trace!("Syntax tree:\n{}", FormatTree(&source_file));
57 Ok(Rc::new(source_file))
58 }
59
60 fn calculate_hash(value: &str) -> u64 {
61 use std::hash::{Hash, Hasher};
62 let mut hasher = rustc_hash::FxHasher::default();
63 value.hash(&mut hasher);
64 hasher.finish()
65 }
66}
67
68impl Parse for SourceFile {
69 fn parse(mut pair: Pair) -> ParseResult<Self> {
70 let hash = Self::calculate_hash(pair.as_str());
72 pair.set_source_hash(hash);
73
74 Ok(SourceFile::new(
75 crate::find_rule!(pair, statement_list)?,
76 pair.as_span().as_str().to_string(),
77 hash,
78 ))
79 }
80}
81
82#[test]
83fn parse_source_file() {
84 let source_file = Parser::parse_rule::<SourceFile>(
85 Rule::source_file,
86 r#"use std::log::info;
87 part Foo(r: Scalar) {
88 info("Hello, world, {r}!");
89 }
90 Foo(20.0);
91 "#,
92 0,
93 )
94 .expect("test error");
95
96 assert_eq!(source_file.statements.len(), 3);
97}