schala/schala-repl/src/language.rs

197 lines
5.5 KiB
Rust
Raw Normal View History

use std::collections::HashMap;
2018-03-24 15:14:24 -07:00
use colored::*;
2018-03-24 13:20:10 -07:00
use std::fmt::Write;
2017-09-08 03:47:04 -07:00
2017-01-23 19:11:50 -08:00
pub struct LLVMCodeString(pub String);
2017-09-17 18:57:47 -07:00
#[derive(Debug, Default, Serialize, Deserialize)]
2017-08-30 19:09:22 -07:00
pub struct EvalOptions {
pub execution_method: ExecutionMethod,
2018-07-15 15:01:50 -07:00
pub debug_passes: HashMap<String, PassDebugOptionsDescriptor>,
2018-03-20 20:29:07 -07:00
}
2018-07-06 03:17:37 -07:00
#[derive(Debug, Hash, PartialEq)]
pub struct PassDescriptor {
pub name: String,
pub debug_options: Vec<String>
}
#[derive(Debug, Serialize, Deserialize)]
2018-07-15 15:01:50 -07:00
pub struct PassDebugOptionsDescriptor {
pub opts: Vec<String>,
}
2018-03-20 20:29:07 -07:00
#[derive(Debug, Serialize, Deserialize)]
pub enum ExecutionMethod {
Compile,
Interpret,
}
impl Default for ExecutionMethod {
fn default() -> ExecutionMethod {
ExecutionMethod::Interpret
}
}
#[derive(Debug, Default)]
pub struct UnfinishedComputation {
2018-05-13 18:28:10 -07:00
artifacts: Vec<(String, TraceArtifact)>,
pub cur_debug_options: Vec<String>,
}
#[derive(Debug)]
pub struct FinishedComputation {
2018-05-13 18:28:10 -07:00
artifacts: Vec<(String, TraceArtifact)>,
text_output: Result<String, String>,
}
impl UnfinishedComputation {
pub fn add_artifact(&mut self, artifact: TraceArtifact) {
2018-05-13 18:28:10 -07:00
self.artifacts.push((artifact.stage_name.clone(), artifact));
}
2018-04-29 04:00:41 -07:00
pub fn finish(self, text_output: Result<String, String>) -> FinishedComputation {
FinishedComputation {
artifacts: self.artifacts,
text_output
}
}
pub fn output(self, output: Result<String, String>) -> FinishedComputation {
FinishedComputation {
artifacts: self.artifacts,
text_output: output
}
}
}
2018-03-19 22:57:54 -07:00
impl FinishedComputation {
2018-03-20 20:29:07 -07:00
pub fn to_repl(&self) -> String {
2018-04-24 23:11:04 -07:00
let mut buf = String::new();
2018-05-11 02:33:19 -07:00
for (stage, artifact) in self.artifacts.iter() {
let color = artifact.text_color;
let stage = stage.color(color).bold();
let output = artifact.debug_output.color(color);
write!(&mut buf, "{}: {}\n", stage, output).unwrap();
2018-03-19 22:57:54 -07:00
}
2018-05-11 02:33:19 -07:00
2018-04-24 23:11:04 -07:00
match self.text_output {
Ok(ref output) => write!(&mut buf, "{}", output).unwrap(),
Err(ref err) => write!(&mut buf, "{} {}", "Error: ".red().bold(), err).unwrap(),
}
buf
2018-03-19 22:57:54 -07:00
}
2018-03-20 20:29:07 -07:00
pub fn to_noninteractive(&self) -> Option<String> {
match self.text_output {
2018-03-27 00:50:31 -07:00
Ok(_) => {
let mut buf = String::new();
2018-05-13 18:28:10 -07:00
for (stage, artifact) in self.artifacts.iter() {
let color = artifact.text_color;
let stage = stage.color(color).bold();
let output = artifact.debug_output.color(color);
write!(&mut buf, "{}: {}\n", stage, output).unwrap();
2018-03-27 00:50:31 -07:00
}
if buf == "" { None } else { Some(buf) }
},
2018-03-22 03:37:48 -07:00
Err(ref s) => Some(format!("{} {}", "Error: ".red().bold(), s))
2018-03-20 20:29:07 -07:00
}
}
2018-03-19 22:57:54 -07:00
}
2017-08-31 20:59:43 -07:00
#[derive(Debug)]
pub struct TraceArtifact {
stage_name: String,
debug_output: String,
2017-09-08 03:47:04 -07:00
text_color: &'static str,
2017-08-31 20:59:43 -07:00
}
impl TraceArtifact {
pub fn new(stage: &str, debug: String) -> TraceArtifact {
2017-09-16 14:29:22 -07:00
let color = match stage {
2017-10-08 22:17:29 -07:00
"parse_trace" | "ast" => "red",
2018-05-11 02:58:14 -07:00
"ast_reducing" => "red",
2017-09-16 14:29:22 -07:00
"tokens" => "green",
2017-10-01 00:48:08 -07:00
"type_check" => "magenta",
2017-09-16 14:29:22 -07:00
_ => "blue",
};
TraceArtifact { stage_name: stage.to_string(), debug_output: debug, text_color: color}
}
pub fn new_parse_trace(trace: Vec<String>) -> TraceArtifact {
2017-09-16 15:05:11 -07:00
let mut output = String::new();
for t in trace {
output.push_str(&t);
output.push_str("\n");
}
TraceArtifact { stage_name: "parse_trace".to_string(), debug_output: output, text_color: "red"}
2017-08-31 20:59:43 -07:00
}
}
2017-08-30 19:09:22 -07:00
pub trait ProgrammingLanguageInterface {
fn execute_pipeline(&mut self, _input: &str, _eval_options: &EvalOptions) -> FinishedComputation {
2018-05-13 18:28:10 -07:00
FinishedComputation { artifacts: vec![], text_output: Err(format!("Execution pipeline not done")) }
}
2017-08-30 19:09:22 -07:00
fn get_language_name(&self) -> String;
2017-10-02 23:07:05 -07:00
fn get_source_file_suffix(&self) -> String;
2018-07-06 03:17:37 -07:00
fn get_passes(&self) -> Vec<PassDescriptor> {
vec![]
}
2018-04-29 03:22:36 -07:00
fn handle_custom_interpreter_directives(&mut self, _commands: &Vec<&str>) -> Option<String> {
None
}
fn custom_interpreter_directives_help(&self) -> String {
format!(">> No custom interpreter directives specified <<")
}
2017-08-30 19:09:22 -07:00
}
2018-04-29 19:45:04 -07:00
/* a pass_chain function signature looks like:
* fn(&mut ProgrammingLanguageInterface, A, Option<&mut DebugHandler>) -> Result<B, String>
*
* TODO use some kind of failure-handling library to make this better
*/
#[macro_export]
macro_rules! pass_chain {
2018-04-29 22:17:10 -07:00
($state:expr, $options:expr; $($pass:path), *) => {
2018-04-29 20:54:45 -07:00
|text_input| {
let mut comp = UnfinishedComputation::default();
2018-04-29 22:17:10 -07:00
pass_chain_helper! { ($state, comp, $options); text_input $(, $pass)* }
2018-04-29 20:54:45 -07:00
}
};
}
#[macro_export]
macro_rules! pass_chain_helper {
2018-04-29 22:17:10 -07:00
(($state:expr, $comp:expr, $options:expr); $input:expr, $pass:path $(, $rest:path)*) => {
2018-04-29 00:55:39 -07:00
{
2018-07-15 15:01:50 -07:00
use schala_repl::PassDebugOptionsDescriptor;
2018-04-29 00:55:39 -07:00
let pass_name = stringify!($pass);
let output = {
let ref debug_map = $options.debug_passes;
let debug_handle = match debug_map.get(pass_name) {
Some(PassDebugOptionsDescriptor { opts }) => {
let ptr = &mut $comp;
ptr.cur_debug_options = opts.clone();
Some(ptr)
}
_ => None
};
2018-05-01 18:22:52 -07:00
$pass($state, $input, debug_handle)
};
2018-04-29 00:55:39 -07:00
match output {
2018-04-29 22:17:10 -07:00
Ok(result) => pass_chain_helper! { ($state, $comp, $options); result $(, $rest)* },
2018-04-29 00:55:39 -07:00
Err(err) => {
2018-04-29 20:58:08 -07:00
$comp.output(Err(format!("Pass {} failed with {:?}", pass_name, err)))
2018-04-29 00:55:39 -07:00
}
}
}
};
// Done
2018-04-29 22:17:10 -07:00
(($state:expr, $comp:expr, $options:expr); $final_output:expr) => {
2018-04-29 00:55:39 -07:00
{
2018-04-29 20:58:08 -07:00
let final_output: FinishedComputation = $comp.finish(Ok($final_output));
2018-04-29 00:55:39 -07:00
final_output
}
};
}