diff --git a/src/language.rs b/src/language.rs index 6e0844c..b7ceb2f 100644 --- a/src/language.rs +++ b/src/language.rs @@ -21,6 +21,7 @@ pub struct EvalOptions { pub debug_tokens: bool, pub debug_parse: bool, pub debug_type: bool, + pub show_llvm_ir: bool, pub trace_evaluation: bool, } @@ -77,7 +78,7 @@ impl TraceArtifact { } pub trait ProgrammingLanguageInterface { - fn evaluate_in_repl(&mut self, input: &str, eval_options: EvalOptions) -> ReplOutput; + fn evaluate_in_repl(&mut self, input: &str, eval_options: &EvalOptions) -> ReplOutput; fn get_language_name(&self) -> String; fn compile(&mut self, _input: &str) -> LLVMCodeString { LLVMCodeString("".to_string()) diff --git a/src/maaru_lang/mod.rs b/src/maaru_lang/mod.rs index 77389d7..178f0ae 100644 --- a/src/maaru_lang/mod.rs +++ b/src/maaru_lang/mod.rs @@ -24,7 +24,7 @@ impl<'a> ProgrammingLanguageInterface for Maaru<'a> { "Maaru".to_string() } - fn evaluate_in_repl(&mut self, input: &str, options: EvalOptions) -> ReplOutput { + fn evaluate_in_repl(&mut self, input: &str, options: &EvalOptions) -> ReplOutput { let mut output = ReplOutput::default(); let tokens = match tokenizer::tokenize(input) { diff --git a/src/main.rs b/src/main.rs index 59bbabe..44ba4c2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,107 +22,74 @@ mod virtual_machine; use virtual_machine::{run_vm, run_assembler}; fn main() { - let languages: Vec> = - vec![ - Box::new(schala_lang::Schala::new()), - Box::new(maaru_lang::Maaru::new()), - Box::new(robo_lang::Robo::new()), - ]; + let languages: Vec> = + vec![ + Box::new(schala_lang::Schala::new()), + Box::new(maaru_lang::Maaru::new()), + Box::new(robo_lang::Robo::new()), + ]; - let option_matches = - match program_options().parse(std::env::args()) { - Ok(o) => o, - Err(e) => { - println!("{:?}", e); - std::process::exit(1); - } - }; - if option_matches.opt_present("list-languages") { - for lang in languages { - println!("{}", lang.get_language_name()); - } + let option_matches = + match program_options().parse(std::env::args()) { + Ok(o) => o, + Err(e) => { + println!("{:?}", e); std::process::exit(1); - } - - if option_matches.opt_present("h") { - println!("{}", program_options().usage("Schala metainterpreter")); - std::process::exit(0); - } - - if option_matches.opt_present("m") { - let file_name = option_matches.free.get(1); - run_vm(file_name); - std::process::exit(0); - } - - if option_matches.opt_present("a") { - let file_name = option_matches.free.get(1); - run_assembler(file_name); - std::process::exit(0); - } - - let language_names: Vec = languages.iter().map(|lang| {lang.get_language_name()}).collect(); - let initial_index: usize = - option_matches.opt_str("l") - .and_then(|lang| { language_names.iter().position(|x| { *x == lang }) }) - .unwrap_or(0); - - let mut options = EvalOptions::default(); - let show_llvm_ir = option_matches.opt_present("v"); - options.trace_evaluation = option_matches.opt_present("t"); - - let compile = !option_matches.opt_present("i"); - - match option_matches.free[..] { - [] | [_] => { - let mut repl = Repl::new(languages, initial_index); - repl.show_llvm_ir = show_llvm_ir; - repl.run(); - } - [_, ref filename, _..] => { - let mut language = maaru_lang::Maaru::new(); - run_noninteractive(filename, &mut language, options, compile); - } + } }; + if option_matches.opt_present("list-languages") { + for lang in languages { + println!("{}", lang.get_language_name()); + } + std::process::exit(1); + } + + if option_matches.opt_present("h") { + println!("{}", program_options().usage("Schala metainterpreter")); + std::process::exit(0); + } + + if option_matches.opt_present("m") { + let file_name = option_matches.free.get(1); + run_vm(file_name); + std::process::exit(0); + } + + if option_matches.opt_present("a") { + let file_name = option_matches.free.get(1); + run_assembler(file_name); + std::process::exit(0); + } + + let language_names: Vec = languages.iter().map(|lang| {lang.get_language_name()}).collect(); + let initial_index: usize = + option_matches.opt_str("l") + .and_then(|lang| { language_names.iter().position(|x| { *x == lang }) }) + .unwrap_or(0); + + let mut options = EvalOptions::default(); + options.trace_evaluation = option_matches.opt_present("t"); + + let compile = !option_matches.opt_present("i"); + + match option_matches.free[..] { + [] | [_] => { + let mut repl = Repl::new(languages, initial_index); + repl.options.show_llvm_ir = option_matches.opt_present("v"); + repl.run(); + } + [_, ref filename, _..] => { + let mut language = maaru_lang::Maaru::new(); + run_noninteractive(filename, &mut language, options, compile); + } + }; } -fn program_options() -> getopts::Options { - let mut options = getopts::Options::new(); - options.optflag("i", - "interpret", - "Interpret source file instead of compiling"); - options.optflag("t", - "trace-evaluation", - "Print out trace of evaluation"); - options.optflag("v", - "llvm-in-repl", - "Show LLVM IR in REPL"); - 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("m", - "virtual-machine", - "Start up a virtual machine instead of an interpreter"); - options.optflag("a", - "assembler", - "Assemble file into bytecode"); - options -} - -fn run_noninteractive(filename: &str, language: &mut T, _options: EvalOptions, compile: bool) { +fn run_noninteractive(filename: &str, language: &mut T, options: EvalOptions, compile: bool) { let mut source_file = File::open(&Path::new(filename)).unwrap(); let mut buffer = String::new(); source_file.read_to_string(&mut buffer).unwrap(); - let options = EvalOptions::default(); - if compile { if !language.can_compile() { panic!("Trying to compile a non-compileable language"); @@ -131,162 +98,149 @@ fn run_noninteractive(filename: &str, language: compilation_sequence(llvm_bytecode, filename); } } else { - let interpretor_output = language.evaluate_in_repl(&buffer, options); + let interpretor_output = language.evaluate_in_repl(&buffer, &options); interpretor_output.print_to_screen(); } } type LineReader = linefeed::Reader; struct Repl { - pub show_tokens: bool, - pub show_parse: bool, - pub show_llvm_ir: bool, - languages: Vec>, - current_language_index: usize, - interpreter_directive_sigil: char, - reader: LineReader, + options: EvalOptions, + languages: Vec>, + current_language_index: usize, + interpreter_directive_sigil: char, + reader: LineReader, } impl Repl { - fn new(languages: Vec>, initial_index: usize) -> Repl { - let mut reader: linefeed::Reader<_> = linefeed::Reader::new("Metainterpreter").unwrap(); - reader.set_prompt(">> "); - let i = if initial_index < languages.len() { initial_index } else { 0 }; - Repl { - show_tokens: false, - show_parse: false, - show_llvm_ir: false, - languages: languages, - current_language_index: i, - interpreter_directive_sigil: '.', - reader: reader, - } + fn new(languages: Vec>, initial_index: usize) -> Repl { + let mut reader: linefeed::Reader<_> = linefeed::Reader::new("Metainterpreter").unwrap(); + reader.set_prompt(">> "); + let i = if initial_index < languages.len() { initial_index } else { 0 }; + Repl { + options: EvalOptions::default(), + languages: languages, + current_language_index: i, + interpreter_directive_sigil: '.', + reader: reader, } - fn run(&mut self) { - use linefeed::ReadResult::*; - println!("MetaInterpreter v 0.05"); - println!("Using language: {}", self.languages[self.current_language_index].get_language_name()); - loop { - match self.reader.read_line() { - Err(e) => { - println!("Terminal read error: {}", e); - }, - Ok(Eof) => { - break; - } - Ok(Input(ref input)) => { - self.reader.add_history(input.clone()); - if self.handle_interpreter_directive(input) { - continue; - } - let output = self.input_handler(input); - println!("=> {}", output); - } - _ => (), + } + fn run(&mut self) { + use linefeed::ReadResult::*; + println!("MetaInterpreter v 0.05"); + println!("Using language: {}", self.languages[self.current_language_index].get_language_name()); + loop { + match self.reader.read_line() { + Err(e) => { + println!("Terminal read error: {}", e); + }, + Ok(Eof) => { + break; + } + Ok(Input(ref input)) => { + self.reader.add_history(input.clone()); + if self.handle_interpreter_directive(input) { + continue; + } + let output = self.input_handler(input); + println!("=> {}", output); + } + _ => (), + } + } + println!("Exiting..."); + } + + fn input_handler(&mut self, input: &str) -> String { + let ref mut language = self.languages[self.current_language_index]; + let interpretor_output = language.evaluate_in_repl(input, &self.options); + interpretor_output.to_string() + } + + fn handle_interpreter_directive(&mut self, input: &str) -> bool { + match input.chars().nth(0) { + Some(ch) if ch == self.interpreter_directive_sigil => (), + _ => return false + } + + let mut iter = input.chars(); + iter.next(); + let trimmed_sigil: &str = iter.as_str(); + + let commands: Vec<&str> = trimmed_sigil + .split_whitespace() + .collect(); + + let cmd: &str = match commands.get(0).clone() { + None => return true, + Some(s) => s + }; + + match cmd { + "exit" | "quit" => process::exit(0), + "history" => { + for item in self.reader.history() { + println!("{}", item); + } + }, + "lang" => { + match commands.get(1) { + Some(&"show") => { + for (i, lang) in self.languages.iter().enumerate() { + if i == self.current_language_index { + println!("* {}", lang.get_language_name()); + } else { + println!("{}", lang.get_language_name()); + } } + }, + Some(&"next") => { + self.current_language_index = (self.current_language_index + 1) % self.languages.len(); + println!("Switching to {}", self.languages[self.current_language_index].get_language_name()); + } + Some(&"prev") | Some(&"previous") => { + self.current_language_index = if self.current_language_index == 0 { self.languages.len() - 1 } else { self.current_language_index - 1 }; + println!("Switching to {}", self.languages[self.current_language_index].get_language_name()); + }, + Some(e) => println!("Bad `lang` argument: {}", e), + None => println!("`lang` - valid arguments `show`, `next`, `prev`|`previous`"), } - println!("Exiting..."); - } - - fn input_handler(&mut self, input: &str) -> String { - let ref mut language = self.languages[self.current_language_index]; - - let options = language::EvalOptions::default(); - /* - options.show_tokens = self.show_tokens; - options.show_parse = self.show_parse; - options.show_llvm_ir = self.show_llvm_ir; - */ - - - let interpretor_output = language.evaluate_in_repl(input, options); - interpretor_output.to_string() - } - - fn handle_interpreter_directive(&mut self, input: &str) -> bool { - match input.chars().nth(0) { - Some(ch) if ch == self.interpreter_directive_sigil => (), - _ => return false - } - - let mut iter = input.chars(); - iter.next(); - let trimmed_sigil: &str = iter.as_str(); - - let commands: Vec<&str> = trimmed_sigil - .split_whitespace() - .collect(); - - let cmd: &str = match commands.get(0).clone() { - None => return true, - Some(s) => s + }, + "set" => { + let show = match commands.get(1) { + Some(&"show") => true, + Some(&"hide") => false, + Some(e) => { + println!("Bad `set` argument: {}", e); + return true; + } + None => { + println!("`set` - valid arguments `show {{option}}`, `hide {{option}}`"); + return true; + } }; - - match cmd { - "exit" | "quit" => process::exit(0), - "history" => { - for item in self.reader.history() { - println!("{}", item); - } - }, - "lang" => { - match commands.get(1) { - Some(&"show") => { - for (i, lang) in self.languages.iter().enumerate() { - if i == self.current_language_index { - println!("* {}", lang.get_language_name()); - } else { - println!("{}", lang.get_language_name()); - } - } - }, - Some(&"next") => { - self.current_language_index = (self.current_language_index + 1) % self.languages.len(); - println!("Switching to {}", self.languages[self.current_language_index].get_language_name()); - } - Some(&"prev") | Some(&"previous") => { - self.current_language_index = if self.current_language_index == 0 { self.languages.len() - 1 } else { self.current_language_index - 1 }; - println!("Switching to {}", self.languages[self.current_language_index].get_language_name()); - }, - Some(e) => println!("Bad `lang` argument: {}", e), - None => println!("`lang` - valid arguments `show`, `next`, `prev`|`previous`"), - } - }, - "set" => { - let show = match commands.get(1) { - Some(&"show") => true, - Some(&"hide") => false, - Some(e) => { - println!("Bad `set` argument: {}", e); - return true; - } - None => { - println!("`set` - valid arguments `show {{option}}`, `hide {{option}}`"); - return true; - } - }; - match commands.get(2) { - Some(&"tokens") => self.show_tokens = show, - Some(&"parse") => self.show_parse = show, - Some(&"eval") => { - //let ref mut language = self.languages[self.current_language_index]; - //language.set_option("trace_evaluation", show); - }, - Some(&"llvm") => self.show_llvm_ir = show, - Some(e) => { - println!("Bad `show`/`hide` argument: {}", e); - return true; - } - None => { - println!("`show`/`hide` requires an argument"); - return true; - } - } - }, - e => println!("Unknown command: {}", e) + match commands.get(2) { + Some(&"tokens") => self.options.debug_tokens = show, + Some(&"parse") => self.options.debug_parse = show, + Some(&"eval") => { + //let ref mut language = self.languages[self.current_language_index]; + //language.set_option("trace_evaluation", show); + }, + Some(&"llvm") => self.options.show_llvm_ir = show, + Some(e) => { + println!("Bad `show`/`hide` argument: {}", e); + return true; + } + None => { + println!("`show`/`hide` requires an argument"); + return true; + } } - return true; + }, + e => println!("Unknown command: {}", e) } + return true; + } } pub fn compilation_sequence(llvm_code: LLVMCodeString, sourcefile: &str) { @@ -335,3 +289,33 @@ pub fn compilation_sequence(llvm_code: LLVMCodeString, sourcefile: &str) { } } +fn program_options() -> getopts::Options { + let mut options = getopts::Options::new(); + options.optflag("i", + "interpret", + "Interpret source file instead of compiling"); + options.optflag("t", + "trace-evaluation", + "Print out trace of evaluation"); + options.optflag("v", + "llvm-in-repl", + "Show LLVM IR in REPL"); + 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("m", + "virtual-machine", + "Start up a virtual machine instead of an interpreter"); + options.optflag("a", + "assembler", + "Assemble file into bytecode"); + options +} + diff --git a/src/robo_lang/mod.rs b/src/robo_lang/mod.rs index 41ba80c..736990c 100644 --- a/src/robo_lang/mod.rs +++ b/src/robo_lang/mod.rs @@ -137,7 +137,7 @@ impl ProgrammingLanguageInterface for Robo { "Robo".to_string() } - fn evaluate_in_repl(&mut self, input: &str, _eval_options: EvalOptions) -> ReplOutput { + fn evaluate_in_repl(&mut self, input: &str, _eval_options: &EvalOptions) -> ReplOutput { let mut output = ReplOutput::default(); let tokens = match tokenize(input) { Ok(tokens) => tokens, diff --git a/src/schala_lang/mod.rs b/src/schala_lang/mod.rs index 4a564b0..9334f5c 100644 --- a/src/schala_lang/mod.rs +++ b/src/schala_lang/mod.rs @@ -16,7 +16,7 @@ impl ProgrammingLanguageInterface for Schala { "Schala".to_string() } - fn evaluate_in_repl(&mut self, input: &str, options: EvalOptions) -> ReplOutput { + fn evaluate_in_repl(&mut self, input: &str, options: &EvalOptions) -> ReplOutput { let mut output = ReplOutput::default(); let tokens = match parsing::tokenize(input) { Ok(tokens) => {