2023-05-04 11:50:17 -05:00
|
|
|
#![feature(result_option_inspect)]
|
2023-05-06 10:57:45 -05:00
|
|
|
#![feature(box_patterns)]
|
|
|
|
#![feature(default_free_fn)]
|
2023-05-04 06:19:32 -05:00
|
|
|
#![allow(non_snake_case)]
|
2023-05-04 02:27:04 -05:00
|
|
|
|
2023-05-05 09:15:38 -05:00
|
|
|
use std::{fmt::Display, path::Path, process::exit};
|
2023-05-05 04:15:01 -05:00
|
|
|
|
2023-05-06 10:57:45 -05:00
|
|
|
use ast::IDLModule;
|
|
|
|
use codegen::generate;
|
2023-05-05 04:15:01 -05:00
|
|
|
use codespan_reporting::{
|
2023-05-05 09:15:38 -05:00
|
|
|
diagnostic::{Diagnostic, Label, Severity},
|
|
|
|
files::SimpleFile,
|
|
|
|
term::{
|
|
|
|
emit,
|
2023-05-06 10:57:45 -05:00
|
|
|
termcolor::{StandardStream, StandardStreamLock},
|
|
|
|
Config,
|
2023-05-05 09:15:38 -05:00
|
|
|
},
|
2023-05-05 04:15:01 -05:00
|
|
|
};
|
2023-05-05 09:15:38 -05:00
|
|
|
use lexer::{NumberSuffix, Token};
|
|
|
|
use parser::TokenIterator;
|
2023-05-05 04:15:01 -05:00
|
|
|
|
|
|
|
use crate::lexer::Spanned;
|
|
|
|
|
2023-05-04 06:19:32 -05:00
|
|
|
mod ast;
|
2023-05-06 10:57:45 -05:00
|
|
|
mod codegen;
|
2023-05-04 06:19:32 -05:00
|
|
|
mod lexer;
|
|
|
|
mod parser;
|
2023-05-04 02:27:04 -05:00
|
|
|
|
2023-05-05 09:15:38 -05:00
|
|
|
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)])
|
2023-05-06 10:57:45 -05:00
|
|
|
.with_notes(vec![
|
|
|
|
format!("Replace {ident} with {}", ident.to_lowercase()),
|
|
|
|
"Code generation might fail".into(),
|
|
|
|
]),
|
2023-05-05 09:15:38 -05:00
|
|
|
);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-04 02:27:04 -05:00
|
|
|
fn main() {
|
2023-05-05 04:15:01 -05:00
|
|
|
let mut args = std::env::args();
|
|
|
|
args.next().unwrap();
|
2023-05-06 10:57:45 -05:00
|
|
|
|
|
|
|
let mut ast: Option<IDLModule> = None;
|
|
|
|
|
2023-05-05 04:15:01 -05:00
|
|
|
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);
|
2023-05-05 09:15:38 -05:00
|
|
|
let config = Config {
|
|
|
|
tab_width: 2,
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
precheck(&mut writer.lock(), &config, &codespan_file);
|
|
|
|
|
2023-05-05 04:15:01 -05:00
|
|
|
match parser::parse(codespan_file.source()) {
|
2023-05-06 10:57:45 -05:00
|
|
|
Ok(ast_) => {
|
|
|
|
println!("{:#?}", ast_);
|
|
|
|
ast = Some(ast_);
|
|
|
|
}
|
2023-05-05 04:15:01 -05:00
|
|
|
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(),
|
2023-05-05 06:21:24 -05:00
|
|
|
)
|
|
|
|
.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()
|
|
|
|
},
|
2023-05-05 04:15:01 -05:00
|
|
|
};
|
|
|
|
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();
|
|
|
|
}
|
2023-05-04 08:51:31 -05:00
|
|
|
}
|
2023-05-05 06:21:24 -05:00
|
|
|
} else {
|
|
|
|
eprintln!("No file given. Aborting.");
|
2023-05-04 07:44:49 -05:00
|
|
|
}
|
2023-05-06 10:57:45 -05:00
|
|
|
|
|
|
|
let rust = generate(ast.unwrap());
|
|
|
|
println!("{}", rust);
|
2023-05-04 06:19:32 -05:00
|
|
|
}
|
2023-05-04 02:27:04 -05:00
|
|
|
|
2023-05-04 06:19:32 -05:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! unwrap_match {
|
|
|
|
($x:expr, $m:pat => $a:expr) => {
|
|
|
|
match $x {
|
|
|
|
$m => $a,
|
2023-05-04 08:51:31 -05:00
|
|
|
_ => unreachable!(),
|
2023-05-04 06:19:32 -05:00
|
|
|
}
|
|
|
|
};
|
2023-05-04 02:27:04 -05:00
|
|
|
}
|