schala/src/language.rs

97 lines
2.7 KiB
Rust
Raw Normal View History

2017-01-21 14:34:17 -08:00
use std::fmt::Debug;
2017-01-21 01:49:45 -08:00
2017-01-23 19:51:27 -08:00
#[derive(Debug)]
2017-01-21 01:49:45 -08:00
pub struct TokenError {
pub msg: String,
}
2017-01-23 19:45:26 -08:00
impl TokenError {
pub fn new(msg: &str) -> TokenError {
TokenError { msg: msg.to_string() }
}
}
2017-01-23 19:51:27 -08:00
#[derive(Debug)]
2017-01-21 01:49:45 -08:00
pub struct ParseError {
pub msg: String,
}
2017-01-23 19:11:50 -08:00
pub struct LLVMCodeString(pub String);
pub trait ProgrammingLanguage {
2017-01-21 14:34:17 -08:00
type Token: Debug;
type AST: Debug;
type Evaluator: EvaluationMachine;
2017-01-21 01:49:45 -08:00
2017-02-02 01:04:15 -08:00
fn name() -> String;
2017-01-21 01:49:45 -08:00
fn tokenize(input: &str) -> Result<Vec<Self::Token>, TokenError>;
fn parse(input: Vec<Self::Token>) -> Result<Self::AST, ParseError>;
fn evaluate(ast: Self::AST, evaluator: &mut Self::Evaluator) -> Vec<String>;
2017-01-23 19:11:50 -08:00
fn compile(ast: Self::AST) -> LLVMCodeString;
2017-01-21 01:49:45 -08:00
}
pub trait EvaluationMachine {
fn set_option(&mut self, option: &str, value: bool) -> bool;
fn new() -> Self;
}
#[derive(Default)]
pub struct LanguageInterfaceOptions {
pub show_parse: bool,
pub show_tokens: bool,
pub show_llvm_ir: bool,
}
pub trait LanguageInterface {
fn evaluate_in_repl(&mut self, input: &str, options: LanguageInterfaceOptions) -> String;
2017-02-02 01:04:15 -08:00
fn get_language_name(&self) -> String;
2017-02-05 21:23:11 -08:00
fn set_option(&mut self, option: &str, value: bool) -> bool;
}
impl<PL, T, A, E> LanguageInterface for (PL, PL::Evaluator) where PL: ProgrammingLanguage<Token=T, AST=A, Evaluator=E>, T: Debug, A: Debug, E: EvaluationMachine {
2017-02-05 21:23:11 -08:00
fn set_option(&mut self, option: &str, value: bool) -> bool {
self.1.set_option(option, value)
}
2017-02-02 01:04:15 -08:00
fn get_language_name(&self) -> String {
PL::name()
}
fn evaluate_in_repl(&mut self, input: &str, options: LanguageInterfaceOptions) -> String {
let mut output = String::new();
let tokens = match PL::tokenize(input) {
Ok(tokens) => tokens,
Err(err) => {
output.push_str(&format!("Tokenization error: {}\n", err.msg));
return output;
}
};
if options.show_tokens {
output.push_str(&format!("Tokens: {:?}\n", tokens));
}
let ast = match PL::parse(tokens) {
Ok(ast) => ast,
Err(err) => {
output.push_str(&format!("Parse error: {:?}\n", err.msg));
return output;
}
};
if options.show_parse {
output.push_str(&format!("AST: {:?}\n", ast));
}
if options.show_llvm_ir {
let LLVMCodeString(s) = PL::compile(ast);
output.push_str(&s);
} else {
// for now only handle last output
let ref mut evaluator = self.1;
let mut full_output: Vec<String> = PL::evaluate(ast, evaluator);
output.push_str(&full_output.pop().unwrap_or("".to_string()));
}
output
}
}