1use std::{
2 fmt::{self, Debug, Display},
3 ops::Range,
4};
5
6use codespan_reporting::{
7 diagnostic::{Diagnostic, Label},
8 files::{Files, SimpleFile},
9 term,
10};
11use proc_macro2::{LineColumn, Span};
12
13mod c_lang;
14mod codegen;
15mod typecheck;
16
17pub struct Session {
19 files: SimpleFile<String, String>,
20}
21
22impl Session {
23 pub fn new(file_name: String, source: String) -> Self {
25 Self {
26 files: SimpleFile::new(file_name, source),
27 }
28 }
29
30 #[cfg(feature = "dev")]
31 pub fn debug(&self) -> Result<String, Box<dyn std::error::Error>> {
32 Ok(format!("{:#?}", syn::parse_file(&self.files.source())?))
33 }
34
35 pub fn compile(&self) -> Result<impl Display, SessionError> {
37 let syn_file = syn::parse_file(self.files.source()).map_err(|e| {
38 let error = CompilationError {
39 msg: format!("{}", e),
40 span: e.span(),
41 };
42
43 SessionError {
44 errors: vec![error],
45 syntax: true,
46 files: &self.files,
47 }
48 })?;
49
50 let type_info = typecheck::check(&syn_file).map_err(|e| SessionError {
51 errors: e.errors,
52 files: &self.files,
53 syntax: false,
54 })?;
55
56 match codegen::transform(&syn_file, type_info) {
57 Ok(program) => Ok(program),
58 Err(e) => Err(SessionError {
59 errors: e.errors,
60 syntax: false,
61 files: &self.files,
62 }),
63 }
64 }
65}
66
67pub struct SessionError<'a> {
69 pub syntax: bool,
71
72 pub errors: Vec<CompilationError>,
74
75 files: &'a SimpleFile<String, String>,
77}
78
79impl<'a> SessionError<'a> {
80 pub fn report(self) -> ! {
82 let mut writer =
83 term::termcolor::StandardStream::stderr(term::termcolor::ColorChoice::Auto);
84
85 self.report_to_writer(&mut writer);
86
87 std::process::exit(1);
88 }
89
90 pub fn into_ansi(mut self) -> Vec<(String, Span)> {
91 let errors = {
92 let mut errors = vec![];
93
94 std::mem::swap(&mut errors, &mut self.errors);
95
96 errors
97 };
98
99 errors
100 .into_iter()
101 .map(|error| (error.span, self.map_err(error)))
102 .map(|(span, diagnostic)| {
103 let mut buffer = term::termcolor::Buffer::ansi();
104
105 term::emit(
106 &mut buffer,
107 &term::Config::default(),
108 self.files,
109 &diagnostic,
110 )
111 .unwrap();
112
113 (String::from_utf8(buffer.into_inner()).unwrap(), span)
114 })
115 .collect()
116 }
117
118 fn report_to_writer(
119 mut self,
120 writer: &mut dyn codespan_reporting::term::termcolor::WriteColor,
121 ) {
122 let n_of_errors = self.errors.len();
123
124 let errors = {
125 let mut errors = vec![];
126
127 std::mem::swap(&mut errors, &mut self.errors);
128
129 errors
130 };
131
132 for diagnostic in errors.into_iter().map(|err| self.map_err(err)) {
133 term::emit(writer, &term::Config::default(), self.files, &diagnostic).unwrap()
134 }
135
136 write!(writer, "Compilation failed due to {} errors", n_of_errors).unwrap();
137 }
138
139 fn map_err(&self, error: CompilationError) -> Diagnostic<()> {
140 Diagnostic::error()
141 .with_message(error.msg)
142 .with_labels(vec![Label::primary((), self.span_to_range(error.span))])
143 }
144
145 fn span_to_range(&self, span: Span) -> Range<usize> {
146 self.linecolumn_to_index(span.start())..self.linecolumn_to_index(span.end())
147 }
148
149 fn linecolumn_to_index(&self, linecol: LineColumn) -> usize {
150 let range = self.files.line_range((), linecol.line - 1).unwrap();
151
152 range.start + linecol.column
153 }
154}
155
156impl<'a> Display for SessionError<'a> {
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 std::writeln!(f, "Failed due to {} errors", self.errors.len())
159 }
160}
161
162impl<'a> Debug for SessionError<'a> {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 Display::fmt(self, f)
165 }
166}
167
168impl<'a> std::error::Error for SessionError<'a> {}
169
170#[derive(Debug)]
172pub struct CompilationError {
173 pub span: Span,
174 pub msg: String,
175}
176
177#[derive(Debug)]
178struct CompilationErrors {
179 errors: Vec<CompilationError>,
180}
181
182impl Display for CompilationErrors {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 for error in &self.errors {
185 writeln!(f, "Error: {} ({:?})", error.msg, error.span)?;
186 }
187
188 Ok(())
189 }
190}
191
192impl std::error::Error for CompilationErrors {}