ableos_userland/programs/aidl/src/main.rs

169 lines
5.5 KiB
Rust

#![feature(result_option_inspect)]
#![feature(box_patterns)]
#![feature(default_free_fn)]
#![allow(non_snake_case)]
use std::{fmt::Display, path::Path, process::exit};
use ast::IDLModule;
use codegen::generate;
use codespan_reporting::{
diagnostic::{Diagnostic, Label, Severity},
files::SimpleFile,
term::{
emit,
termcolor::{StandardStream, StandardStreamLock},
Config,
},
};
use lexer::{NumberSuffix, Token};
use parser::TokenIterator;
use crate::lexer::Spanned;
mod ast;
mod codegen;
mod lexer;
mod parser;
fn precheck<N: Display + Clone, S: AsRef<str>>(
writer: &mut StandardStreamLock<'_>,
config: &Config,
file: &SimpleFile<N, S>,
) {
let mut lexer = TokenIterator::new(file.source().as_ref());
let mut diagnostics = vec![];
let mut previous = lexer.peek().ok().map(|Spanned(a, b)| Spanned(a.clone(), b));
while let Ok(Spanned(token, span)) = lexer.next() {
let prev = Spanned(token.clone(), span.clone());
match token {
Token::Ident(lexer::Ident::Other(t)) if t == "Type" => {
diagnostics.push(
Diagnostic::error()
.with_labels(vec![Label::primary((), span.0)])
.with_message("`Type` is not supported anymore.")
.with_notes(vec!["use `Alias` instead of `Type`".into()]),
);
}
Token::Ident(lexer::Ident::Other(ident))
if lexer
.peek()
.is_ok_and(|Spanned(a, _)| matches!(a, Token::LeftCurly))
&& previous.is_some_and(|Spanned(ref a, _)| matches!(a, Token::Equals)) =>
{
diagnostics.push(
Diagnostic::error()
.with_message("Unknown expression")
.with_labels(vec![Label::primary((), span.0.clone())])
.with_notes(vec![
format!("add `Make` before the structure name to create a Make expression that will construct the `{ident}` structure"
),
]),
);
}
Token::Ident(lexer::Ident::Other(ident))
if NumberSuffix::ALL_SUFFIXES.contains(&ident.to_lowercase().as_str()) =>
{
diagnostics.push(
Diagnostic::warning()
.with_message("Potentially invalid use of an uppercased number type")
.with_labels(vec![Label::primary((), span.0)])
.with_notes(vec![
format!("Replace {ident} with {}", ident.to_lowercase()),
"Code generation might fail".into(),
]),
);
}
_ => {}
}
previous = Some(prev);
}
if !diagnostics.is_empty() {
let mut was_fatal = false;
for diagnostic in diagnostics {
if let Severity::Error | Severity::Bug = &diagnostic.severity {
was_fatal = true;
}
emit(writer, config, file, &diagnostic).unwrap();
}
if was_fatal {
exit(1);
}
}
}
fn main() {
let mut args = std::env::args();
args.next().unwrap();
let mut ast: Option<IDLModule> = None;
if let Some(file) = args.next() {
let path = Path::new(&file);
let codespan_file = codespan_reporting::files::SimpleFile::new(
&file,
std::fs::read_to_string(path).unwrap(),
);
let writer = StandardStream::stdout(codespan_reporting::term::termcolor::ColorChoice::Auto);
let config = Config {
tab_width: 2,
..Default::default()
};
precheck(&mut writer.lock(), &config, &codespan_file);
match parser::parse(codespan_file.source()) {
Ok(ast_) => {
println!("{:#?}", ast_);
ast = Some(ast_);
}
Err(e) => {
let msg = e.to_string();
let label = match e {
parser::ParserError::UnexpectedEOF => Label::primary(
(),
(codespan_file.source().len() - 1)..codespan_file.source().len(),
)
.with_message("Unexpected end of file here"),
parser::ParserError::Unexpected(expected, Spanned(got, span)) => {
Label::primary((), span.0)
.with_message(format!("Unexpected `{got}`, expected {expected}"))
}
parser::ParserError::PleaseStopParsingUse => unsafe {
std::hint::unreachable_unchecked()
},
};
let diagnostic = codespan_reporting::diagnostic::Diagnostic::error()
.with_message(msg)
.with_labels(vec![label]);
codespan_reporting::term::emit(
&mut writer.lock(),
&config,
&codespan_file,
&diagnostic,
)
.unwrap();
}
}
} else {
eprintln!("No file given. Aborting.");
}
let rust = generate(ast.unwrap());
println!("{}", rust);
}
#[macro_export]
macro_rules! unwrap_match {
($x:expr, $m:pat => $a:expr) => {
match $x {
$m => $a,
_ => unreachable!(),
}
};
}