1use core::fmt;
2use std::fs;
3use std::path::{PathBuf, Path};
4use std::io;
5use crate::utils::{self, ReadChars};
6
7use crate::lexer::LexerBuilder;
8use crate::parser::{Parser, ParserError};
9use crate::parser::stmt::StmtMeta;
10use crate::runtime::strings::StringInterner;
11
12type ReadFileChars = ReadChars<io::BufReader<fs::File>>;
13
14#[derive(Debug, Hash)]
15pub enum ModuleSource {
16 String(String),
17 File(PathBuf),
18}
19
20impl ModuleSource {
21 pub fn read_text(&self) -> io::Result<SourceText> {
23 match self {
24 Self::String(string) => Ok(SourceText::String(string.clone())),
25 Self::File(ref path) => Ok(SourceText::File(Self::read_source_file(path)?)),
26 }
27 }
28
29 fn read_source_file(path: &Path) -> io::Result<ReadFileChars> {
30 let file = fs::File::open(path)?;
31 let reader = io::BufReader::new(file);
32 Ok(ReadChars::new(reader))
33 }
34}
35
36impl fmt::Display for ModuleSource {
37 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
38 match self {
39 Self::File(path) => write!(fmt, "file \"{}\"", path.display()),
40 Self::String(string) => write!(fmt, "source text \"{}\"", utils::trim_str(string, 16)),
41 }
42 }
43}
44
45
46#[derive(Debug)]
47pub enum SourceText {
48 String(String),
49 File(ReadFileChars),
50}
51
52impl<S> From<S> for SourceText where S: ToString {
53 fn from(text: S) -> Self { SourceText::String(text.to_string()) }
54}
55
56
57
58pub struct ParseContext<'f, 's> {
62 lexer_factory: &'f LexerBuilder,
63 interner: &'s mut StringInterner,
64}
65
66impl<'f, 's> ParseContext<'f, 's> {
67 pub fn new(lexer_factory: &'f LexerBuilder, interner: &'s mut StringInterner) -> Self {
68 ParseContext {
69 lexer_factory,
70 interner,
71 }
72 }
73
74 pub fn parse_ast(&mut self, source: SourceText) -> Result<Vec<StmtMeta>, Vec<ParserError>> {
76
77 let output = self.collect_parser_output(source);
78
79 if output.iter().any(|r| r.is_err()) {
80 Err(output.into_iter().filter_map(|r| r.err()).collect())
81 } else {
82 Ok(output.into_iter().filter_map(|r| r.ok()).collect())
83 }
84 }
85
86 fn collect_parser_output(&mut self, source: SourceText) -> Vec<Result<StmtMeta, ParserError>> {
88 match source {
89 SourceText::String(text) => {
90 let mut chars = Vec::with_capacity(text.len());
91 chars.extend(text.chars().map(Ok));
92
93 let lexer = self.lexer_factory.build(chars.into_iter());
94 let parser = Parser::new(self.interner, lexer);
95 parser.collect()
96 }
97 SourceText::File(text) => {
98 let lexer = self.lexer_factory.build(text);
99 let parser = Parser::new(self.interner, lexer);
100 parser.collect()
101 },
102 }
103 }
104}