Grand culling

Deleting a bunch of old code related to the old way the interpreter
worked
This commit is contained in:
greg 2019-03-14 00:51:33 -07:00
parent 7e899246e9
commit 1622a6ce44
13 changed files with 122 additions and 677 deletions

View File

@ -6,12 +6,10 @@ authors = ["greg <greg.shuflin@protonmail.com>"]
[dependencies] [dependencies]
schala-repl = { path = "schala-repl" } schala-repl = { path = "schala-repl" }
schala-repl-codegen = { path = "schala-repl-codegen" }
maaru-lang = { path = "maaru" } maaru-lang = { path = "maaru" }
rukka-lang = { path = "rukka" } rukka-lang = { path = "rukka" }
robo-lang = { path = "robo" } robo-lang = { path = "robo" }
schala-lang = { path = "schala-lang/language" } schala-lang = { path = "schala-lang/language" }
schala-lang-codegen = { path = "schala-lang/codegen" }
[build-dependencies] [build-dependencies]
includedir_codegen = "0.2.0" includedir_codegen = "0.2.0"

View File

@ -6,8 +6,6 @@ mod tokenizer;
mod parser; mod parser;
mod eval; mod eval;
use schala_repl::{ProgrammingLanguageInterface, EvalOptions, UnfinishedComputation, FinishedComputation, TraceArtifact};
#[derive(Debug)] #[derive(Debug)]
pub struct TokenError { pub struct TokenError {
pub msg: String, pub msg: String,
@ -33,6 +31,42 @@ impl<'a> Maaru<'a> {
} }
} }
/*
fn execute_pipeline(&mut self, input: &str, options: &EvalOptions) -> Result<String, String> {
let mut output = UnfinishedComputation::default();
let tokens = match tokenizer::tokenize(input) {
Ok(tokens) => {
if let Some(_) = options.debug_passes.get("tokens") {
output.add_artifact(TraceArtifact::new("tokens", format!("{:?}", tokens)));
}
tokens
},
Err(err) => {
return output.finish(Err(format!("Tokenization error: {:?}\n", err.msg)))
}
};
let ast = match parser::parse(&tokens, &[]) {
Ok(ast) => {
if let Some(_) = options.debug_passes.get("ast") {
output.add_artifact(TraceArtifact::new("ast", format!("{:?}", ast)));
}
ast
},
Err(err) => {
return output.finish(Err(format!("Parse error: {:?}\n", err.msg)))
}
};
let mut evaluation_output = String::new();
for s in self.evaluator.run(ast).iter() {
evaluation_output.push_str(s);
}
Ok(evaluation_output)
}
*/
/*
impl<'a> ProgrammingLanguageInterface for Maaru<'a> { impl<'a> ProgrammingLanguageInterface for Maaru<'a> {
fn get_language_name(&self) -> String { fn get_language_name(&self) -> String {
"Maaru".to_string() "Maaru".to_string()
@ -40,37 +74,5 @@ impl<'a> ProgrammingLanguageInterface for Maaru<'a> {
fn get_source_file_suffix(&self) -> String { fn get_source_file_suffix(&self) -> String {
format!("maaru") format!("maaru")
} }
fn execute_pipeline(&mut self, input: &str, options: &EvalOptions) -> FinishedComputation {
let mut output = UnfinishedComputation::default();
let tokens = match tokenizer::tokenize(input) {
Ok(tokens) => {
if let Some(_) = options.debug_passes.get("tokens") {
output.add_artifact(TraceArtifact::new("tokens", format!("{:?}", tokens)));
}
tokens
},
Err(err) => {
return output.finish(Err(format!("Tokenization error: {:?}\n", err.msg)))
}
};
let ast = match parser::parse(&tokens, &[]) {
Ok(ast) => {
if let Some(_) = options.debug_passes.get("ast") {
output.add_artifact(TraceArtifact::new("ast", format!("{:?}", ast)));
}
ast
},
Err(err) => {
return output.finish(Err(format!("Parse error: {:?}\n", err.msg)))
}
};
let mut evaluation_output = String::new();
for s in self.evaluator.run(ast).iter() {
evaluation_output.push_str(s);
}
output.finish(Ok(evaluation_output))
}
} }
*/

View File

@ -4,7 +4,7 @@ extern crate itertools;
extern crate schala_repl; extern crate schala_repl;
use itertools::Itertools; use itertools::Itertools;
use schala_repl::{ProgrammingLanguageInterface, EvalOptions, FinishedComputation, UnfinishedComputation}; use schala_repl::{ProgrammingLanguageInterface, EvalOptions};
pub struct Robo { pub struct Robo {
} }
@ -154,17 +154,5 @@ impl ProgrammingLanguageInterface for Robo {
fn get_source_file_suffix(&self) -> String { fn get_source_file_suffix(&self) -> String {
format!("robo") 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)))
}
} }

View File

@ -4,7 +4,7 @@ extern crate itertools;
extern crate schala_repl; extern crate schala_repl;
use itertools::Itertools; use itertools::Itertools;
use schala_repl::{ProgrammingLanguageInterface, EvalOptions, UnfinishedComputation, FinishedComputation}; use schala_repl::{ProgrammingLanguageInterface, EvalOptions};
use std::iter::Peekable; use std::iter::Peekable;
use std::vec::IntoIter; use std::vec::IntoIter;
use std::str::Chars; use std::str::Chars;
@ -72,24 +72,6 @@ impl ProgrammingLanguageInterface for Rukka {
fn get_source_file_suffix(&self) -> String { fn get_source_file_suffix(&self) -> String {
format!("rukka") 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 { impl EvaluatorState {

View File

@ -15,4 +15,3 @@ ena = "0.11.0"
schala-lang-codegen = { path = "../codegen" } schala-lang-codegen = { path = "../codegen" }
schala-repl = { path = "../../schala-repl" } schala-repl = { path = "../../schala-repl" }
schala-repl-codegen = { path = "../../schala-repl-codegen" }

View File

@ -14,8 +14,6 @@ extern crate lazy_static;
extern crate maplit; extern crate maplit;
extern crate schala_repl; extern crate schala_repl;
#[macro_use] #[macro_use]
extern crate schala_repl_codegen;
#[macro_use]
extern crate schala_lang_codegen; extern crate schala_lang_codegen;
extern crate ena; extern crate ena;

View File

@ -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

View File

@ -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
}

View File

@ -1,24 +1,10 @@
use std::collections::HashMap; use std::collections::HashMap;
use colored::*; use colored::*;
use std::fmt::Write;
use std::time; use std::time;
#[derive(Debug, Default, Serialize, Deserialize)] #[derive(Debug, Default, Serialize, Deserialize)]
pub struct EvalOptions { pub struct EvalOptions {
pub execution_method: ExecutionMethod, 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)] #[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 { 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_language_name(&self) -> String;
fn get_source_file_suffix(&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 { fn run_computation(&mut self, _request: ComputationRequest) -> ComputationResponse {
ComputationResponse { ComputationResponse {
@ -185,7 +31,7 @@ pub trait ProgrammingLanguageInterface {
} }
fn repl_request(&self, repl_request: String) -> String { 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>, total_duration: Option<time::Duration>,
stage_durations: Option<Vec<(String, 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
}
}
}
*/

View File

@ -25,99 +25,35 @@ mod repl;
mod language; mod language;
mod webapp; mod webapp;
pub use language::{ProgrammingLanguageInterface, EvalOptions,
ExecutionMethod, ComputationRequest, ComputationResponse, GlobalOutputStats};
include!(concat!(env!("OUT_DIR"), "/static.rs")); include!(concat!(env!("OUT_DIR"), "/static.rs"));
const VERSION_STRING: &'static str = "0.1.0"; const VERSION_STRING: &'static str = "0.1.0";
pub fn start_repl(langs: Vec<Box<dyn ProgrammingLanguageInterface>>) { 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); println!("{:?}", e);
exit(1); exit(1);
}); });
if command_line_options.opt_present("help") { if options.opt_present("help") {
println!("{}", program_options().usage("Schala metainterpreter")); println!("{}", command_line_options().usage("Schala metainterpreter"));
exit(0); exit(0);
} }
let mut repl = repl::NewRepl::new(langs); match options.free[..] {
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); let mut repl = repl::NewRepl::new(langs);
repl.run(); repl.run_repl();
} }
[_, ref filename, _..] => { [_, ref filename, _..] => {
run_noninteractive(filename, langs);
run_noninteractive(filename, languages, options, debug_passes);
} }
}; };
} }
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 path = Path::new(filename);
let ext = path.extension().and_then(|e| e.to_str()).unwrap_or_else(|| { let ext = path.extension().and_then(|e| e.to_str()).unwrap_or_else(|| {
println!("Source file lacks extension"); 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 source_file = File::open(path).unwrap();
let mut buffer = String::new(); let mut buffer = String::new();
source_file.read_to_string(&mut buffer).unwrap(); source_file.read_to_string(&mut buffer).unwrap();
for pass in debug_passes.into_iter() { println!("NON-INTERACTIVE OUTPUT DOESN'T WORK YET");
if let Some(_) = language.get_passes().iter().find(|desc| desc.name == pass) { panic!();
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));
}
}
} }
fn program_options() -> getopts::Options {
fn command_line_options() -> getopts::Options {
let mut options = getopts::Options::new(); 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", options.optflag("h",
"help", "help",
"Show help text"); "Show help text");
options.optflag("w", options.optflag("w",
"webapp", "webapp",
"Start up web interpreter"); "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 options
} }

View File

@ -5,8 +5,7 @@ use std::sync::Arc;
use colored::*; use colored::*;
use itertools::Itertools; use itertools::Itertools;
use crate::language::{ProgrammingLanguageInterface, EvalOptions, use crate::language::{ProgrammingLanguageInterface, EvalOptions, ComputationRequest, ComputationResponse};
PassDebugOptionsDescriptor, ComputationRequest, ComputationResponse};
mod command_tree; mod command_tree;
use self::command_tree::CommandTree; 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> { fn handle_interpreter_directive(&mut self, input: &str) -> Option<String> {
Some(format!("you typed {}, which is unsupported", input)) Some(format!("you typed {}, which is unsupported", input))
} }
@ -120,122 +115,11 @@ impl NewRepl {
Err(e) => format!("{} {}", "Error".red(), e) 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 { fn get_directives(&self) -> CommandTree {
let passes_directives = vec![];
/*
let ref passes = self.get_cur_language().get_passes(); let ref passes = self.get_cur_language().get_passes();
let passes_directives: Vec<CommandTree> = passes.iter() let passes_directives: Vec<CommandTree> = passes.iter()
.map(|pass_descriptor| { .map(|pass_descriptor| {
let name = &pass_descriptor.name; let name = &pass_descriptor.name;
@ -252,6 +136,7 @@ impl Repl {
} }
} }
}).collect(); }).collect();
*/
CommandTree::Top(vec![ CommandTree::Top(vec![
CommandTree::term("exit", Some("exit the REPL")), CommandTree::term("exit", Some("exit the REPL")),
@ -280,7 +165,41 @@ impl Repl {
CommandTree::term("doc", Some("Get language-specific help for an item")), 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> { fn handle_interpreter_directive(&mut self, input: &str) -> Option<String> {
let mut iter = input.chars(); let mut iter = input.chars();
iter.next(); iter.next();
@ -364,6 +283,8 @@ impl Repl {
} }
} }
} }
*/
/*
fn handle_debug(&mut self, commands: Vec<&str>) -> Option<String> { fn handle_debug(&mut self, commands: Vec<&str>) -> Option<String> {
let passes = self.get_cur_language().get_passes(); let passes = self.get_cur_language().get_passes();
match commands.get(1) { match commands.get(1) {
@ -410,7 +331,7 @@ impl Repl {
_ => Some(format!("Unknown debug command")) _ => Some(format!("Unknown debug command"))
} }
} }
} */
struct TabCompleteHandler { struct TabCompleteHandler {
sigil: char, sigil: char,

View File

@ -5,7 +5,6 @@ use rocket::http::ContentType;
use rocket_contrib::json::Json; use rocket_contrib::json::Json;
use crate::language::{ProgrammingLanguageInterface, EvalOptions}; use crate::language::{ProgrammingLanguageInterface, EvalOptions};
use crate::WEBFILES; use crate::WEBFILES;
use crate::PLIGenerator;
#[get("/")] #[get("/")]
fn index() -> Content<String> { fn index() -> Content<String> {
@ -31,14 +30,16 @@ struct Output {
text: String, text: String,
} }
/*
#[post("/input", format = "application/json", data = "<input>")] #[post("/input", format = "application/json", data = "<input>")]
fn interpreter_input(input: Json<Input>, generators: State<Vec<PLIGenerator>>) -> Json<Output> { 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 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() }) Json(Output { text: code_output.to_repl() })
} }
*/
pub fn web_main(language_generators: Vec<PLIGenerator>) { pub fn web_main(/*language_generators: Vec<PLIGenerator>*/) {
rocket::ignite().manage(language_generators).mount("/", routes![index, js_bundle, interpreter_input]).launch(); rocket::ignite()/*.manage(language_generators)*/.mount("/", routes![index, js_bundle, /*interpreter_input*/]).launch();
} }

View File

@ -4,7 +4,7 @@ extern crate maaru_lang;
extern crate rukka_lang; extern crate rukka_lang;
extern crate robo_lang; extern crate robo_lang;
extern crate schala_lang; extern crate schala_lang;
use schala_repl::{PLIGenerator, ProgrammingLanguageInterface, repl_main, start_repl}; use schala_repl::{ProgrammingLanguageInterface, start_repl};
extern { } extern { }