Very weirdly organized, but it JITs!

This commit is contained in:
2023-03-24 10:28:32 -05:00
parent ff8412acca
commit 4aa3a9419a
14 changed files with 441 additions and 81 deletions

148
src/bin/ngri.rs Normal file
View File

@@ -0,0 +1,148 @@
use codespan_reporting::diagnostic::Diagnostic;
use codespan_reporting::files::SimpleFiles;
use codespan_reporting::term::{self, Config};
use ngr::ir::Program as IR;
use ngr::jit::{JITEngine, JITError};
use ngr::syntax::{Location, ParserError, Statement};
use pretty::termcolor::{ColorChoice, StandardStream, WriteColor};
use rustyline::error::ReadlineError;
use rustyline::DefaultEditor;
use std::collections::HashMap;
pub struct RunLoop<'a> {
file_database: SimpleFiles<&'a str, String>,
jitter: JITEngine,
variable_binding_sites: HashMap<String, Location>,
gensym_index: usize,
writer: &'a mut dyn WriteColor,
config: Config,
}
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, thiserror::Error)]
enum REPLError {
#[error("Error parsing statement: {0}")]
Parser(#[from] ParserError),
#[error("JIT error: {0}")]
JIT(#[from] JITError),
#[error(transparent)]
Reporting(#[from] codespan_reporting::files::Error),
}
impl From<REPLError> for Diagnostic<usize> {
fn from(value: REPLError) -> Self {
match value {
REPLError::Parser(err) => Diagnostic::from(&err),
REPLError::JIT(err) => Diagnostic::from(err),
REPLError::Reporting(err) => Diagnostic::bug().with_message(format!("{}", err)),
}
}
}
impl<'a> RunLoop<'a> {
pub fn new(writer: &'a mut dyn WriteColor, config: Config) -> Result<Self, JITError> {
Ok(RunLoop {
file_database: SimpleFiles::new(),
jitter: JITEngine::new()?,
variable_binding_sites: HashMap::new(),
gensym_index: 1,
writer,
config,
})
}
fn emit_diagnostic(
&mut self,
diagnostic: Diagnostic<usize>,
) -> Result<(), codespan_reporting::files::Error> {
term::emit(self.writer, &self.config, &self.file_database, &diagnostic)
}
fn process_input(&mut self, line_no: usize, command: String) {
if let Err(err) = self.process(line_no, command) {
if let Err(e) = self.emit_diagnostic(Diagnostic::from(err)) {
eprintln!(
"WOAH! System having trouble printing error messages. This is very bad. ({})",
e
);
}
}
}
fn process(&mut self, line_no: usize, command: String) -> Result<(), REPLError> {
let entry = self.file_database.add("entry", command);
let source = self
.file_database
.get(entry)
.expect("entry exists")
.source();
let syntax = Statement::parse(entry, source)?;
// if this is a variable binding, and we've never defined this variable before,
// we should tell cranelift about it. this is optimistic; if we fail to compile,
// then we won't use this definition until someone tries again.
if let Statement::Binding(_, ref name, _) = syntax {
if !self.variable_binding_sites.contains_key(name.as_str()) {
self.jitter.define_string(name.clone())?;
self.jitter.define_variable(name.clone())?;
}
};
let (mut errors, mut warnings) = syntax.validate(&mut self.variable_binding_sites);
let stop = !errors.is_empty();
let messages = errors
.drain(..)
.map(Into::into)
.chain(warnings.drain(..).map(Into::into));
for message in messages {
self.emit_diagnostic(message)?;
}
if stop {
return Ok(());
}
let ir = IR::from(syntax.simplify(&mut self.gensym_index));
let compiled = self.jitter.compile(line_no, ir)?;
compiled();
Ok(())
}
}
fn main() -> Result<(), JITError> {
let mut editor = DefaultEditor::new().expect("rustyline works");
let mut line_no = 0;
let mut writer = StandardStream::stdout(ColorChoice::Auto);
let config = codespan_reporting::term::Config::default();
let mut state = RunLoop::new(&mut writer, config)?;
println!("No Good Reason, the Interpreter!");
loop {
line_no += 1;
match editor.readline("> ") {
Ok(command) => match command.trim() {
"" => continue,
":quit" => break,
_ => state.process_input(line_no, command),
},
Err(ReadlineError::Io(e)) => {
eprintln!("IO error: {}", e);
break;
}
Err(ReadlineError::Eof) => break,
Err(ReadlineError::Interrupted) => break,
Err(ReadlineError::Errno(e)) => {
eprintln!("Unknown syscall error: {}", e);
break;
}
Err(ReadlineError::WindowResized) => continue,
Err(e) => {
eprintln!("Unknown internal error: {}", e);
break;
}
}
}
Ok(())
}