Grand culling
Deleting a bunch of old code related to the old way the interpreter worked
This commit is contained in:
parent
7e899246e9
commit
1622a6ce44
@ -6,12 +6,10 @@ authors = ["greg <greg.shuflin@protonmail.com>"]
|
||||
[dependencies]
|
||||
|
||||
schala-repl = { path = "schala-repl" }
|
||||
schala-repl-codegen = { path = "schala-repl-codegen" }
|
||||
maaru-lang = { path = "maaru" }
|
||||
rukka-lang = { path = "rukka" }
|
||||
robo-lang = { path = "robo" }
|
||||
schala-lang = { path = "schala-lang/language" }
|
||||
schala-lang-codegen = { path = "schala-lang/codegen" }
|
||||
|
||||
[build-dependencies]
|
||||
includedir_codegen = "0.2.0"
|
||||
|
@ -6,8 +6,6 @@ mod tokenizer;
|
||||
mod parser;
|
||||
mod eval;
|
||||
|
||||
use schala_repl::{ProgrammingLanguageInterface, EvalOptions, UnfinishedComputation, FinishedComputation, TraceArtifact};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TokenError {
|
||||
pub msg: String,
|
||||
@ -33,15 +31,8 @@ impl<'a> Maaru<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ProgrammingLanguageInterface for Maaru<'a> {
|
||||
fn get_language_name(&self) -> String {
|
||||
"Maaru".to_string()
|
||||
}
|
||||
fn get_source_file_suffix(&self) -> String {
|
||||
format!("maaru")
|
||||
}
|
||||
|
||||
fn execute_pipeline(&mut self, input: &str, options: &EvalOptions) -> FinishedComputation {
|
||||
/*
|
||||
fn execute_pipeline(&mut self, input: &str, options: &EvalOptions) -> Result<String, String> {
|
||||
let mut output = UnfinishedComputation::default();
|
||||
|
||||
let tokens = match tokenizer::tokenize(input) {
|
||||
@ -71,6 +62,17 @@ impl<'a> ProgrammingLanguageInterface for Maaru<'a> {
|
||||
for s in self.evaluator.run(ast).iter() {
|
||||
evaluation_output.push_str(s);
|
||||
}
|
||||
output.finish(Ok(evaluation_output))
|
||||
Ok(evaluation_output)
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
impl<'a> ProgrammingLanguageInterface for Maaru<'a> {
|
||||
fn get_language_name(&self) -> String {
|
||||
"Maaru".to_string()
|
||||
}
|
||||
fn get_source_file_suffix(&self) -> String {
|
||||
format!("maaru")
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -4,7 +4,7 @@ extern crate itertools;
|
||||
extern crate schala_repl;
|
||||
|
||||
use itertools::Itertools;
|
||||
use schala_repl::{ProgrammingLanguageInterface, EvalOptions, FinishedComputation, UnfinishedComputation};
|
||||
use schala_repl::{ProgrammingLanguageInterface, EvalOptions};
|
||||
|
||||
pub struct Robo {
|
||||
}
|
||||
@ -154,17 +154,5 @@ impl ProgrammingLanguageInterface for Robo {
|
||||
fn get_source_file_suffix(&self) -> String {
|
||||
format!("robo")
|
||||
}
|
||||
|
||||
fn execute_pipeline(&mut self, input: &str, _eval_options: &EvalOptions) -> FinishedComputation {
|
||||
let output = UnfinishedComputation::default();
|
||||
let tokens = match tokenize(input) {
|
||||
Ok(tokens) => tokens,
|
||||
Err(e) => {
|
||||
return output.finish(Err(format!("Tokenize error: {:?}", e)));
|
||||
}
|
||||
};
|
||||
|
||||
output.finish(Ok(format!("{:?}", tokens)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ extern crate itertools;
|
||||
extern crate schala_repl;
|
||||
|
||||
use itertools::Itertools;
|
||||
use schala_repl::{ProgrammingLanguageInterface, EvalOptions, UnfinishedComputation, FinishedComputation};
|
||||
use schala_repl::{ProgrammingLanguageInterface, EvalOptions};
|
||||
use std::iter::Peekable;
|
||||
use std::vec::IntoIter;
|
||||
use std::str::Chars;
|
||||
@ -72,24 +72,6 @@ impl ProgrammingLanguageInterface for Rukka {
|
||||
fn get_source_file_suffix(&self) -> String {
|
||||
format!("rukka")
|
||||
}
|
||||
|
||||
fn execute_pipeline(&mut self, input: &str, _eval_options: &EvalOptions) -> FinishedComputation {
|
||||
let output = UnfinishedComputation::default();
|
||||
let sexps = match read(input) {
|
||||
Err(err) => {
|
||||
return output.finish(Err(format!("Error: {}", err)));
|
||||
},
|
||||
Ok(sexps) => sexps
|
||||
};
|
||||
|
||||
let output_str: String = sexps.into_iter().enumerate().map(|(i, sexp)| {
|
||||
match self.state.eval(sexp) {
|
||||
Ok(result) => format!("{}: {}", i, result.print()),
|
||||
Err(err) => format!("{} Error: {}", i, err),
|
||||
}
|
||||
}).intersperse(format!("\n")).collect();
|
||||
output.finish(Ok(output_str))
|
||||
}
|
||||
}
|
||||
|
||||
impl EvaluatorState {
|
||||
|
@ -15,4 +15,3 @@ ena = "0.11.0"
|
||||
|
||||
schala-lang-codegen = { path = "../codegen" }
|
||||
schala-repl = { path = "../../schala-repl" }
|
||||
schala-repl-codegen = { path = "../../schala-repl-codegen" }
|
||||
|
@ -14,8 +14,6 @@ extern crate lazy_static;
|
||||
extern crate maplit;
|
||||
extern crate schala_repl;
|
||||
#[macro_use]
|
||||
extern crate schala_repl_codegen;
|
||||
#[macro_use]
|
||||
extern crate schala_lang_codegen;
|
||||
extern crate ena;
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
[package]
|
||||
name = "schala-repl-codegen"
|
||||
version = "0.1.0"
|
||||
authors = ["greg <greg.shuflin@protonmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
syn = { version = "0.15.6", features = ["full", "extra-traits"] }
|
||||
quote = "0.6.8"
|
||||
proc-macro2 = "0.4.19"
|
||||
schala-repl = { path = "../schala-repl" }
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
@ -1,199 +0,0 @@
|
||||
#![feature(trace_macros)]
|
||||
#![recursion_limit="128"]
|
||||
extern crate proc_macro;
|
||||
extern crate proc_macro2;
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
extern crate syn;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use syn::{Ident, Attribute, DeriveInput};
|
||||
|
||||
fn find_attr_by_name<'a>(name: &str, attrs: &'a Vec<Attribute>) -> Option<&'a Attribute> {
|
||||
attrs.iter().find(|attr| {
|
||||
let first = attr.path.segments.first();
|
||||
let seg: Option<&&syn::PathSegment> = first.as_ref().map(|x| x.value());
|
||||
seg.map(|seg| seg.ident.to_string() == name).unwrap_or(false)
|
||||
})
|
||||
}
|
||||
|
||||
fn extract_attribute_arg_by_name(name: &str, attrs: &Vec<Attribute>) -> Option<String> {
|
||||
use syn::{Meta, Lit, MetaNameValue};
|
||||
find_attr_by_name(name, attrs)
|
||||
.and_then(|attr| {
|
||||
match attr.interpret_meta() {
|
||||
Some(Meta::NameValue(MetaNameValue { lit: Lit::Str(litstr), .. })) => Some(litstr.value()),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn extract_attribute_list(name: &str, attrs: &Vec<Attribute>) -> Option<Vec<(Ident, Option<Vec<Ident>>)>> {
|
||||
use syn::{Meta, MetaList, NestedMeta};
|
||||
find_attr_by_name(name, attrs)
|
||||
.and_then(|attr| {
|
||||
match attr.interpret_meta() {
|
||||
Some(Meta::List(MetaList { nested, .. })) => {
|
||||
Some(nested.iter().map(|nested_meta| match nested_meta {
|
||||
&NestedMeta::Meta(Meta::Word(ref ident)) => (ident.clone(), None),
|
||||
&NestedMeta::Meta(Meta::List(MetaList { ref ident, nested: ref nested2, .. })) => {
|
||||
let own_args = nested2.iter().map(|nested_meta2| match nested_meta2 {
|
||||
&NestedMeta::Meta(Meta::Word(ref ident)) => ident.clone(),
|
||||
_ => panic!("Bad format for doubly-nested attribute list")
|
||||
}).collect();
|
||||
(ident.clone(), Some(own_args))
|
||||
},
|
||||
_ => panic!("Bad format for nested list")
|
||||
}).collect())
|
||||
},
|
||||
_ => panic!("{} must be a comma-delimited list surrounded by parens", name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_attribute_identifier(attr_name: &str, attrs: &Vec<Attribute>) -> Option<proc_macro2::Ident> {
|
||||
find_attr_by_name(attr_name, attrs).and_then(|attr| {
|
||||
let tts = attr.tts.clone().into_iter().collect::<Vec<_>>();
|
||||
|
||||
if tts.len() == 2 {
|
||||
let ref after_equals: proc_macro2::TokenTree = tts[1];
|
||||
match after_equals {
|
||||
proc_macro2::TokenTree::Ident(ident) => Some(ident.clone()),
|
||||
_ => None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/* a pass_chain function signature with input A and output B looks like:
|
||||
* fn(A, &mut ProgrammingLanguageInterface, Option<&mut DebugHandler>) -> Result<B, String>
|
||||
*
|
||||
* TODO use some kind of failure-handling library to make this better
|
||||
*/
|
||||
fn generate_pass_chain(idents: Vec<Ident>) -> proc_macro2::TokenStream {
|
||||
let final_return = quote! {
|
||||
{
|
||||
let final_output: FinishedComputation = unfinished_computation.finish(Ok(input_to_next_stage));
|
||||
final_output
|
||||
}
|
||||
};
|
||||
|
||||
let nested_passes = idents.iter()
|
||||
.rev()
|
||||
.fold(final_return, |later_fragment, pass_name| {
|
||||
quote! {
|
||||
{
|
||||
let pass_name = stringify!(#pass_name);
|
||||
let (output, duration) = {
|
||||
let ref debug_map = eval_options.debug_passes;
|
||||
let debug_handle = match debug_map.get(pass_name) {
|
||||
Some(PassDebugOptionsDescriptor { opts }) => {
|
||||
let ptr = &mut unfinished_computation;
|
||||
ptr.cur_debug_options = opts.clone();
|
||||
Some(ptr)
|
||||
}
|
||||
_ => None
|
||||
};
|
||||
let start = time::Instant::now();
|
||||
let pass_output = #pass_name(input_to_next_stage, self, debug_handle);
|
||||
let elapsed = start.elapsed();
|
||||
(pass_output, elapsed)
|
||||
};
|
||||
if eval_options.debug_timing {
|
||||
unfinished_computation.durations.push(duration);
|
||||
}
|
||||
match output {
|
||||
Ok(input_to_next_stage) => #later_fragment,
|
||||
//TODO this error type needs to be guaranteed to provide a useable string
|
||||
Err(err) => return unfinished_computation.output(Err(format!("Pass {} failed:\n{}", pass_name, err))),
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
{
|
||||
use std::time;
|
||||
use schala_repl::PassDebugOptionsDescriptor;
|
||||
|
||||
let eval_options = options;
|
||||
let input_to_next_stage = input;
|
||||
let mut unfinished_computation = UnfinishedComputation::default();
|
||||
#nested_passes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_derive(ProgrammingLanguageInterface,
|
||||
attributes(LanguageName, SourceFileExtension, PipelineSteps, DocMethod, HandleCustomInterpreterDirectives))]
|
||||
pub fn derive_programming_language_interface(input: TokenStream) -> TokenStream {
|
||||
let ast: DeriveInput = syn::parse(input).unwrap();
|
||||
let name = &ast.ident;
|
||||
let attrs = &ast.attrs;
|
||||
|
||||
let language_name: String = extract_attribute_arg_by_name("LanguageName", attrs).expect("LanguageName is required");
|
||||
let file_ext = extract_attribute_arg_by_name("SourceFileExtension", attrs).expect("SourceFileExtension is required");
|
||||
let passes = extract_attribute_list("PipelineSteps", attrs).expect("PipelineSteps are required");
|
||||
let pass_idents = passes.iter().map(|x| x.0.clone());
|
||||
|
||||
let get_doc_impl = match get_attribute_identifier("DocMethod", attrs) {
|
||||
None => quote! { },
|
||||
Some(method_name) => quote! {
|
||||
fn get_doc(&self, commands: &Vec<&str>) -> Option<String> {
|
||||
self.#method_name(commands)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let handle_custom_interpreter_directives_impl = match get_attribute_identifier("HandleCustomInterpreterDirectives", attrs) {
|
||||
None => quote! { },
|
||||
Some(method_name) => quote! {
|
||||
fn handle_custom_interpreter_directives(&mut self, commands: &Vec<&str>) -> Option<String> {
|
||||
//println!("If #method_name is &self not &mut self, this runs forever");
|
||||
self.#method_name(commands)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let pass_descriptors = passes.iter().map(|pass| {
|
||||
let name = pass.0.to_string();
|
||||
let opts: Vec<String> = match &pass.1 {
|
||||
None => vec![],
|
||||
Some(opts) => opts.iter().map(|o| o.to_string()).collect(),
|
||||
};
|
||||
|
||||
quote! {
|
||||
PassDescriptor {
|
||||
name: #name.to_string(),
|
||||
debug_options: vec![#(format!(#opts)),*]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let pass_chain = generate_pass_chain(pass_idents.collect());
|
||||
|
||||
let tokens = quote! {
|
||||
use schala_repl::PassDescriptor;
|
||||
impl ProgrammingLanguageInterface for #name {
|
||||
fn get_language_name(&self) -> String {
|
||||
#language_name.to_string()
|
||||
}
|
||||
fn get_source_file_suffix(&self) -> String {
|
||||
#file_ext.to_string()
|
||||
}
|
||||
fn execute_pipeline(&mut self, input: &str, options: &EvalOptions) -> FinishedComputation {
|
||||
#pass_chain
|
||||
}
|
||||
fn get_passes(&self) -> Vec<PassDescriptor> {
|
||||
vec![ #(#pass_descriptors),* ]
|
||||
}
|
||||
#get_doc_impl
|
||||
#handle_custom_interpreter_directives_impl
|
||||
}
|
||||
};
|
||||
|
||||
let output: TokenStream = tokens.into();
|
||||
output
|
||||
}
|
@ -1,24 +1,10 @@
|
||||
use std::collections::HashMap;
|
||||
use colored::*;
|
||||
use std::fmt::Write;
|
||||
use std::time;
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct EvalOptions {
|
||||
pub execution_method: ExecutionMethod,
|
||||
pub debug_passes: HashMap<String, PassDebugOptionsDescriptor>,
|
||||
pub debug_timing: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, PartialEq)]
|
||||
pub struct PassDescriptor {
|
||||
pub name: String,
|
||||
pub debug_options: Vec<String>
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct PassDebugOptionsDescriptor {
|
||||
pub opts: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@ -32,149 +18,9 @@ impl Default for ExecutionMethod {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct UnfinishedComputation {
|
||||
artifacts: Vec<(String, TraceArtifact)>,
|
||||
pub durations: Vec<time::Duration>,
|
||||
pub cur_debug_options: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FinishedComputation {
|
||||
artifacts: Vec<(String, TraceArtifact)>,
|
||||
durations: Vec<time::Duration>,
|
||||
text_output: Result<String, String>,
|
||||
}
|
||||
|
||||
impl UnfinishedComputation {
|
||||
pub fn add_artifact(&mut self, artifact: TraceArtifact) {
|
||||
self.artifacts.push((artifact.stage_name.clone(), artifact));
|
||||
}
|
||||
pub fn finish(self, text_output: Result<String, String>) -> FinishedComputation {
|
||||
FinishedComputation {
|
||||
artifacts: self.artifacts,
|
||||
text_output,
|
||||
durations: self.durations,
|
||||
}
|
||||
}
|
||||
pub fn output(self, output: Result<String, String>) -> FinishedComputation {
|
||||
FinishedComputation {
|
||||
artifacts: self.artifacts,
|
||||
text_output: output,
|
||||
durations: self.durations,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FinishedComputation {
|
||||
|
||||
fn get_timing(&self) -> Option<String> {
|
||||
if self.durations.len() != 0 {
|
||||
let mut buf = String::new();
|
||||
write!(&mut buf, "Timing: ").unwrap();
|
||||
for duration in self.durations.iter() {
|
||||
let timing = (duration.as_secs() as f64) + (duration.subsec_nanos() as f64 * 1e-9);
|
||||
write!(&mut buf, "{}s, ", timing).unwrap()
|
||||
}
|
||||
write!(&mut buf, "\n").unwrap();
|
||||
Some(buf)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_repl(&self) -> String {
|
||||
let mut buf = String::new();
|
||||
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();
|
||||
}
|
||||
|
||||
match self.get_timing() {
|
||||
Some(timing) => write!(&mut buf, "{}", timing).unwrap(),
|
||||
None => ()
|
||||
}
|
||||
|
||||
match self.text_output {
|
||||
Ok(ref output) => write!(&mut buf, "{}", output).unwrap(),
|
||||
Err(ref err) => write!(&mut buf, "{} {}", "Error: ".red().bold(), err).unwrap(),
|
||||
}
|
||||
buf
|
||||
}
|
||||
pub fn to_noninteractive(&self) -> Option<String> {
|
||||
match self.text_output {
|
||||
Ok(_) => {
|
||||
let mut buf = String::new();
|
||||
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();
|
||||
}
|
||||
if buf == "" { None } else { Some(buf) }
|
||||
},
|
||||
Err(ref s) => Some(format!("{} {}", "Error: ".red().bold(), s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TraceArtifact {
|
||||
stage_name: String,
|
||||
debug_output: String,
|
||||
text_color: &'static str,
|
||||
}
|
||||
|
||||
impl TraceArtifact {
|
||||
pub fn new(stage: &str, debug: String) -> TraceArtifact {
|
||||
let color = match stage {
|
||||
"parse_trace" | "ast" => "red",
|
||||
"ast_reducing" => "red",
|
||||
"tokens" => "green",
|
||||
"type_check" => "magenta",
|
||||
_ => "blue",
|
||||
};
|
||||
TraceArtifact { stage_name: stage.to_string(), debug_output: debug, text_color: color}
|
||||
}
|
||||
|
||||
pub fn new_parse_trace(trace: Vec<String>) -> TraceArtifact {
|
||||
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"}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ProgrammingLanguageInterface {
|
||||
fn execute_pipeline(&mut self, _input: &str, _eval_options: &EvalOptions) -> FinishedComputation {
|
||||
FinishedComputation { artifacts: vec![], text_output: Err(format!("Execution pipeline not done")), durations: vec![] }
|
||||
}
|
||||
|
||||
fn get_language_name(&self) -> String;
|
||||
fn get_source_file_suffix(&self) -> String;
|
||||
fn get_passes(&self) -> Vec<PassDescriptor> {
|
||||
vec![]
|
||||
}
|
||||
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 <<")
|
||||
}
|
||||
fn get_doc(&self, _commands: &Vec<&str>) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
/* ------- */
|
||||
// new trait methods
|
||||
//
|
||||
//
|
||||
|
||||
fn run_computation(&mut self, _request: ComputationRequest) -> ComputationResponse {
|
||||
ComputationResponse {
|
||||
@ -185,7 +31,7 @@ pub trait ProgrammingLanguageInterface {
|
||||
}
|
||||
|
||||
fn repl_request(&self, repl_request: String) -> String {
|
||||
format!("Repl request not implemented")
|
||||
format!(">> No custom interpreter directives or help info specified <<")
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,3 +62,22 @@ pub struct GlobalOutputStats {
|
||||
total_duration: Option<time::Duration>,
|
||||
stage_durations: Option<Vec<(String, time::Duration)>>
|
||||
}
|
||||
|
||||
/*
|
||||
impl GlobalOutputStats {
|
||||
fn get_timing(&self) -> Option<String> {
|
||||
if self.durations.len() != 0 {
|
||||
let mut buf = String::new();
|
||||
write!(&mut buf, "Timing: ").unwrap();
|
||||
for duration in self.durations.iter() {
|
||||
let timing = (duration.as_secs() as f64) + (duration.subsec_nanos() as f64 * 1e-9);
|
||||
write!(&mut buf, "{}s, ", timing).unwrap()
|
||||
}
|
||||
write!(&mut buf, "\n").unwrap();
|
||||
Some(buf)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -25,99 +25,35 @@ mod repl;
|
||||
mod language;
|
||||
mod webapp;
|
||||
|
||||
pub use language::{ProgrammingLanguageInterface, EvalOptions,
|
||||
ExecutionMethod, ComputationRequest, ComputationResponse, GlobalOutputStats};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/static.rs"));
|
||||
const VERSION_STRING: &'static str = "0.1.0";
|
||||
|
||||
pub fn start_repl(langs: Vec<Box<dyn ProgrammingLanguageInterface>>) {
|
||||
let command_line_options = command_line_options().parse(std::env::args()).unwrap_or_else(|e| {
|
||||
let options = command_line_options().parse(std::env::args()).unwrap_or_else(|e| {
|
||||
println!("{:?}", e);
|
||||
exit(1);
|
||||
});
|
||||
|
||||
if command_line_options.opt_present("help") {
|
||||
println!("{}", program_options().usage("Schala metainterpreter"));
|
||||
if options.opt_present("help") {
|
||||
println!("{}", command_line_options().usage("Schala metainterpreter"));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
match options.free[..] {
|
||||
[] | [_] => {
|
||||
let mut repl = repl::NewRepl::new(langs);
|
||||
repl.run_repl();
|
||||
}
|
||||
|
||||
fn command_line_options() -> getopts::Options {
|
||||
let mut options = getopts::Options::new();
|
||||
options.optflag("h",
|
||||
"help",
|
||||
"Show help text");
|
||||
options.optflag("w",
|
||||
"webapp",
|
||||
"Start up web interpreter");
|
||||
options
|
||||
}
|
||||
|
||||
/* --------------------------- */
|
||||
|
||||
pub use language::{ProgrammingLanguageInterface, EvalOptions,
|
||||
ExecutionMethod, TraceArtifact, FinishedComputation, UnfinishedComputation, PassDebugOptionsDescriptor, PassDescriptor, ComputationRequest, ComputationResponse, GlobalOutputStats};
|
||||
|
||||
pub type PLIGenerator = Box<Fn() -> Box<ProgrammingLanguageInterface> + Send + Sync>;
|
||||
|
||||
pub fn repl_main(generators: Vec<PLIGenerator>) {
|
||||
let languages: Vec<Box<ProgrammingLanguageInterface>> = generators.iter().map(|x| x()).collect();
|
||||
|
||||
let option_matches = program_options().parse(std::env::args()).unwrap_or_else(|e| {
|
||||
println!("{:?}", e);
|
||||
exit(1);
|
||||
});
|
||||
|
||||
if option_matches.opt_present("list-languages") {
|
||||
for lang in languages {
|
||||
println!("{}", lang.get_language_name());
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if option_matches.opt_present("help") {
|
||||
println!("{}", program_options().usage("Schala metainterpreter"));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if option_matches.opt_present("webapp") {
|
||||
webapp::web_main(generators);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
let mut options = EvalOptions::default();
|
||||
let debug_passes = if let Some(opts) = option_matches.opt_str("debug") {
|
||||
let output: Vec<String> = opts.split_terminator(",").map(|s| s.to_string()).collect();
|
||||
output
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let language_names: Vec<String> = languages.iter().map(|lang| {lang.get_language_name()}).collect();
|
||||
let initial_index: usize =
|
||||
option_matches.opt_str("lang")
|
||||
.and_then(|lang| { language_names.iter().position(|x| { x.to_lowercase() == lang.to_lowercase() }) })
|
||||
.unwrap_or(0);
|
||||
|
||||
options.execution_method = match option_matches.opt_str("eval-style") {
|
||||
Some(ref s) if s == "compile" => ExecutionMethod::Compile,
|
||||
_ => ExecutionMethod::Interpret,
|
||||
};
|
||||
|
||||
match option_matches.free[..] {
|
||||
[] | [_] => {
|
||||
let mut repl = repl::Repl::new(languages, initial_index);
|
||||
repl.run();
|
||||
}
|
||||
[_, ref filename, _..] => {
|
||||
|
||||
run_noninteractive(filename, languages, options, debug_passes);
|
||||
run_noninteractive(filename, langs);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn run_noninteractive(filename: &str, languages: Vec<Box<ProgrammingLanguageInterface>>, mut options: EvalOptions, debug_passes: Vec<String>) {
|
||||
fn run_noninteractive(filename: &str, languages: Vec<Box<ProgrammingLanguageInterface>>) {
|
||||
let path = Path::new(filename);
|
||||
let ext = path.extension().and_then(|e| e.to_str()).unwrap_or_else(|| {
|
||||
println!("Source file lacks extension");
|
||||
@ -131,53 +67,20 @@ fn run_noninteractive(filename: &str, languages: Vec<Box<ProgrammingLanguageInte
|
||||
|
||||
let mut source_file = File::open(path).unwrap();
|
||||
let mut buffer = String::new();
|
||||
|
||||
source_file.read_to_string(&mut buffer).unwrap();
|
||||
|
||||
for pass in debug_passes.into_iter() {
|
||||
if let Some(_) = language.get_passes().iter().find(|desc| desc.name == pass) {
|
||||
options.debug_passes.insert(pass, PassDebugOptionsDescriptor { opts: vec![] });
|
||||
}
|
||||
}
|
||||
|
||||
match options.execution_method {
|
||||
ExecutionMethod::Compile => {
|
||||
/*
|
||||
let llvm_bytecode = language.compile(&buffer);
|
||||
compilation_sequence(llvm_bytecode, filename);
|
||||
*/
|
||||
panic!("Not ready to go yet");
|
||||
},
|
||||
ExecutionMethod::Interpret => {
|
||||
let output = language.execute_pipeline(&buffer, &options);
|
||||
output.to_noninteractive().map(|text| println!("{}", text));
|
||||
}
|
||||
}
|
||||
println!("NON-INTERACTIVE OUTPUT DOESN'T WORK YET");
|
||||
panic!();
|
||||
}
|
||||
|
||||
fn program_options() -> getopts::Options {
|
||||
|
||||
fn command_line_options() -> getopts::Options {
|
||||
let mut options = getopts::Options::new();
|
||||
options.optopt("s",
|
||||
"eval-style",
|
||||
"Specify whether to compile (if supported) or interpret the language. If not specified, the default is language-specific",
|
||||
"[compile|interpret]"
|
||||
);
|
||||
options.optflag("",
|
||||
"list-languages",
|
||||
"Show a list of all supported languages");
|
||||
options.optopt("l",
|
||||
"lang",
|
||||
"Start up REPL in a language",
|
||||
"LANGUAGE");
|
||||
options.optflag("h",
|
||||
"help",
|
||||
"Show help text");
|
||||
options.optflag("w",
|
||||
"webapp",
|
||||
"Start up web interpreter");
|
||||
options.optopt("d",
|
||||
"debug",
|
||||
"Debug a stage (l = tokenizer, a = AST, r = parse trace, s = symbol table)",
|
||||
"[l|a|r|s]");
|
||||
options
|
||||
}
|
||||
|
@ -5,8 +5,7 @@ use std::sync::Arc;
|
||||
|
||||
use colored::*;
|
||||
use itertools::Itertools;
|
||||
use crate::language::{ProgrammingLanguageInterface, EvalOptions,
|
||||
PassDebugOptionsDescriptor, ComputationRequest, ComputationResponse};
|
||||
use crate::language::{ProgrammingLanguageInterface, EvalOptions, ComputationRequest, ComputationResponse};
|
||||
mod command_tree;
|
||||
use self::command_tree::CommandTree;
|
||||
|
||||
@ -91,10 +90,6 @@ impl NewRepl {
|
||||
*/
|
||||
}
|
||||
|
||||
fn get_directives(&self) -> CommandTree {
|
||||
CommandTree::Top(vec![])
|
||||
}
|
||||
|
||||
fn handle_interpreter_directive(&mut self, input: &str) -> Option<String> {
|
||||
Some(format!("you typed {}, which is unsupported", input))
|
||||
}
|
||||
@ -120,122 +115,11 @@ impl NewRepl {
|
||||
Err(e) => format!("{} {}", "Error".red(), e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* --------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
pub struct Repl {
|
||||
options: EvalOptions,
|
||||
languages: Vec<Box<ProgrammingLanguageInterface>>,
|
||||
current_language_index: usize,
|
||||
interpreter_directive_sigil: char,
|
||||
line_reader: ::linefeed::interface::Interface<::linefeed::terminal::DefaultTerminal>,
|
||||
}
|
||||
|
||||
impl Repl {
|
||||
pub fn new(languages: Vec<Box<ProgrammingLanguageInterface>>, initial_index: usize) -> Repl {
|
||||
use linefeed::Interface;
|
||||
let current_language_index = if initial_index < languages.len() { initial_index } else { 0 };
|
||||
|
||||
let line_reader = Interface::new("schala-repl").unwrap();
|
||||
|
||||
Repl {
|
||||
options: Repl::get_options(),
|
||||
languages,
|
||||
current_language_index,
|
||||
interpreter_directive_sigil: ':',
|
||||
line_reader
|
||||
}
|
||||
}
|
||||
|
||||
fn get_cur_language(&self) -> &ProgrammingLanguageInterface {
|
||||
self.languages[self.current_language_index].as_ref()
|
||||
}
|
||||
|
||||
fn get_options() -> EvalOptions {
|
||||
File::open(OPTIONS_SAVE_FILE)
|
||||
.and_then(|mut file| {
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)?;
|
||||
Ok(contents)
|
||||
})
|
||||
.and_then(|contents| {
|
||||
let options: EvalOptions = ::serde_json::from_str(&contents)?;
|
||||
Ok(options)
|
||||
}).unwrap_or(EvalOptions::default())
|
||||
}
|
||||
|
||||
fn save_options(&self) {
|
||||
let ref options = self.options;
|
||||
let read = File::create(OPTIONS_SAVE_FILE)
|
||||
.and_then(|mut file| {
|
||||
let buf = ::serde_json::to_string(options).unwrap();
|
||||
file.write_all(buf.as_bytes())
|
||||
});
|
||||
|
||||
if let Err(err) = read {
|
||||
println!("Error saving {} file {}", OPTIONS_SAVE_FILE, err);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
use linefeed::ReadResult;
|
||||
|
||||
println!("Schala MetaInterpreter version {}", crate::VERSION_STRING);
|
||||
println!("Type {}help for help with the REPL", self.interpreter_directive_sigil);
|
||||
|
||||
self.line_reader.load_history(HISTORY_SAVE_FILE).unwrap_or(());
|
||||
|
||||
loop {
|
||||
let language_name = self.get_cur_language().get_language_name();
|
||||
let directives = self.get_directives();
|
||||
let tab_complete_handler = TabCompleteHandler::new(self.interpreter_directive_sigil, directives);
|
||||
self.line_reader.set_completer(Arc::new(tab_complete_handler));
|
||||
|
||||
let prompt_str = format!("{} >> ", language_name);
|
||||
self.line_reader.set_prompt(&prompt_str).unwrap();
|
||||
|
||||
match self.line_reader.read_line() {
|
||||
Err(e) => {
|
||||
println!("Terminal read error: {}", e);
|
||||
},
|
||||
Ok(ReadResult::Eof) => break,
|
||||
Ok(ReadResult::Signal(_)) => break,
|
||||
Ok(ReadResult::Input(ref input)) => {
|
||||
self.line_reader.add_history_unique(input.to_string());
|
||||
let output = match input.chars().nth(0) {
|
||||
Some(ch) if ch == self.interpreter_directive_sigil => self.handle_interpreter_directive(input),
|
||||
_ => Some(self.input_handler(input)),
|
||||
};
|
||||
if let Some(o) = output {
|
||||
println!("=> {}", o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.line_reader.save_history(HISTORY_SAVE_FILE).unwrap_or(());
|
||||
self.save_options();
|
||||
println!("Exiting...");
|
||||
}
|
||||
|
||||
fn input_handler(&mut self, input: &str) -> String {
|
||||
let ref mut language = self.languages[self.current_language_index];
|
||||
let interpreter_output = language.execute_pipeline(input, &self.options);
|
||||
interpreter_output.to_repl()
|
||||
}
|
||||
|
||||
fn get_directives(&self) -> CommandTree {
|
||||
let passes_directives = vec![];
|
||||
/*
|
||||
let ref passes = self.get_cur_language().get_passes();
|
||||
|
||||
let passes_directives: Vec<CommandTree> = passes.iter()
|
||||
.map(|pass_descriptor| {
|
||||
let name = &pass_descriptor.name;
|
||||
@ -252,6 +136,7 @@ impl Repl {
|
||||
}
|
||||
}
|
||||
}).collect();
|
||||
*/
|
||||
|
||||
CommandTree::Top(vec![
|
||||
CommandTree::term("exit", Some("exit the REPL")),
|
||||
@ -280,7 +165,41 @@ impl Repl {
|
||||
CommandTree::term("doc", Some("Get language-specific help for an item")),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------- */
|
||||
|
||||
|
||||
/*
|
||||
fn get_options() -> EvalOptions {
|
||||
File::open(OPTIONS_SAVE_FILE)
|
||||
.and_then(|mut file| {
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)?;
|
||||
Ok(contents)
|
||||
})
|
||||
.and_then(|contents| {
|
||||
let options: EvalOptions = ::serde_json::from_str(&contents)?;
|
||||
Ok(options)
|
||||
}).unwrap_or(EvalOptions::default())
|
||||
}
|
||||
|
||||
fn save_options(&self) {
|
||||
let ref options = self.options;
|
||||
let read = File::create(OPTIONS_SAVE_FILE)
|
||||
.and_then(|mut file| {
|
||||
let buf = ::serde_json::to_string(options).unwrap();
|
||||
file.write_all(buf.as_bytes())
|
||||
});
|
||||
|
||||
if let Err(err) = read {
|
||||
println!("Error saving {} file {}", OPTIONS_SAVE_FILE, err);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
fn handle_interpreter_directive(&mut self, input: &str) -> Option<String> {
|
||||
let mut iter = input.chars();
|
||||
iter.next();
|
||||
@ -364,6 +283,8 @@ impl Repl {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
fn handle_debug(&mut self, commands: Vec<&str>) -> Option<String> {
|
||||
let passes = self.get_cur_language().get_passes();
|
||||
match commands.get(1) {
|
||||
@ -410,7 +331,7 @@ impl Repl {
|
||||
_ => Some(format!("Unknown debug command"))
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
struct TabCompleteHandler {
|
||||
sigil: char,
|
||||
|
@ -5,7 +5,6 @@ use rocket::http::ContentType;
|
||||
use rocket_contrib::json::Json;
|
||||
use crate::language::{ProgrammingLanguageInterface, EvalOptions};
|
||||
use crate::WEBFILES;
|
||||
use crate::PLIGenerator;
|
||||
|
||||
#[get("/")]
|
||||
fn index() -> Content<String> {
|
||||
@ -31,14 +30,16 @@ struct Output {
|
||||
text: String,
|
||||
}
|
||||
|
||||
/*
|
||||
#[post("/input", format = "application/json", data = "<input>")]
|
||||
fn interpreter_input(input: Json<Input>, generators: State<Vec<PLIGenerator>>) -> Json<Output> {
|
||||
let schala_gen = generators.get(0).unwrap();
|
||||
let mut schala: Box<ProgrammingLanguageInterface> = schala_gen();
|
||||
let code_output = schala.execute_pipeline(&input.source, &EvalOptions::default());
|
||||
//let code_output = schala.execute_pipeline(&input.source, &EvalOptions::default());
|
||||
let code_output = format!("NOTDONE");
|
||||
Json(Output { text: code_output.to_repl() })
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn web_main(language_generators: Vec<PLIGenerator>) {
|
||||
rocket::ignite().manage(language_generators).mount("/", routes![index, js_bundle, interpreter_input]).launch();
|
||||
pub fn web_main(/*language_generators: Vec<PLIGenerator>*/) {
|
||||
rocket::ignite()/*.manage(language_generators)*/.mount("/", routes![index, js_bundle, /*interpreter_input*/]).launch();
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ extern crate maaru_lang;
|
||||
extern crate rukka_lang;
|
||||
extern crate robo_lang;
|
||||
extern crate schala_lang;
|
||||
use schala_repl::{PLIGenerator, ProgrammingLanguageInterface, repl_main, start_repl};
|
||||
use schala_repl::{ProgrammingLanguageInterface, start_repl};
|
||||
|
||||
extern { }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user