2017-11-26 21:17:17 -08:00
|
|
|
use itertools::Itertools;
|
|
|
|
use schala_lib::{ProgrammingLanguageInterface, EvalOptions, ReplOutput};
|
2017-11-29 01:45:29 -08:00
|
|
|
use std::iter::Peekable;
|
2017-12-01 02:16:28 -08:00
|
|
|
use std::vec::IntoIter;
|
2017-11-29 01:45:29 -08:00
|
|
|
use std::str::Chars;
|
2017-12-04 02:44:09 -08:00
|
|
|
use std::fmt::Write;
|
2017-11-26 21:17:17 -08:00
|
|
|
|
2017-12-03 22:10:19 -08:00
|
|
|
pub struct EvaluatorState { }
|
|
|
|
|
|
|
|
pub struct Rukka {
|
|
|
|
state: EvaluatorState
|
|
|
|
}
|
2017-11-26 21:17:17 -08:00
|
|
|
|
|
|
|
impl Rukka {
|
2017-12-03 22:10:19 -08:00
|
|
|
pub fn new() -> Rukka { Rukka { state: EvaluatorState::new() } }
|
2017-11-26 21:17:17 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ProgrammingLanguageInterface for Rukka {
|
|
|
|
fn get_language_name(&self) -> String {
|
|
|
|
"Rukka".to_string()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_source_file_suffix(&self) -> String {
|
|
|
|
format!("rukka")
|
|
|
|
}
|
|
|
|
|
|
|
|
fn evaluate_in_repl(&mut self, input: &str, _eval_options: &EvalOptions) -> ReplOutput {
|
|
|
|
let mut output = ReplOutput::default();
|
2017-12-01 02:16:28 -08:00
|
|
|
let sexps = match read(input) {
|
|
|
|
Err(err) => {
|
|
|
|
output.add_output(format!("Error: {}", err));
|
|
|
|
return output;
|
|
|
|
},
|
|
|
|
Ok(sexps) => sexps
|
2017-11-29 01:45:29 -08:00
|
|
|
};
|
2017-12-01 02:16:28 -08:00
|
|
|
|
2017-12-01 02:36:52 -08:00
|
|
|
let output_str: String = sexps.into_iter().enumerate().map(|(i, sexp)| {
|
2017-12-03 22:10:19 -08:00
|
|
|
match self.state.eval(sexp) {
|
2017-12-03 17:11:17 -08:00
|
|
|
Ok(result) => format!("{}: {}", i, result.print()),
|
2017-12-01 02:36:52 -08:00
|
|
|
Err(err) => format!("{} Error: {}", i, err),
|
2017-12-01 02:16:28 -08:00
|
|
|
}
|
2017-12-01 02:36:52 -08:00
|
|
|
}).intersperse(format!("\n")).collect();
|
|
|
|
output.add_output(output_str);
|
2017-11-26 21:17:17 -08:00
|
|
|
output
|
|
|
|
}
|
|
|
|
}
|
2017-11-27 00:57:26 -08:00
|
|
|
|
2017-12-03 22:10:19 -08:00
|
|
|
impl EvaluatorState {
|
|
|
|
fn new() -> EvaluatorState { EvaluatorState { } }
|
|
|
|
fn eval(&mut self, expr: Sexp) -> Result<Sexp, String> {
|
2017-12-03 22:20:43 -08:00
|
|
|
use self::Sexp::*;
|
2017-12-03 22:10:19 -08:00
|
|
|
Ok(match expr {
|
2017-12-03 22:20:43 -08:00
|
|
|
SymbolAtom(sym) => unimplemented!(),
|
|
|
|
expr @ StringAtom(_) => expr,
|
|
|
|
expr @ NumberAtom(_) => expr,
|
2017-12-04 01:57:24 -08:00
|
|
|
List(items) => {
|
|
|
|
if items.len() == 0 {
|
2017-12-04 03:01:47 -08:00
|
|
|
return Ok(List(items))
|
2017-12-04 01:57:24 -08:00
|
|
|
}
|
|
|
|
let ref first = items[0];
|
|
|
|
match first {
|
|
|
|
&SymbolAtom(ref sym) => match &sym[..] {
|
|
|
|
"quote" => unimplemented!(),
|
|
|
|
_ => unimplemented!(),
|
|
|
|
},
|
|
|
|
_ => unimplemented!()
|
|
|
|
}
|
|
|
|
}
|
2017-12-03 22:10:19 -08:00
|
|
|
})
|
|
|
|
}
|
2017-11-28 03:37:16 -08:00
|
|
|
}
|
|
|
|
|
2017-12-01 02:16:28 -08:00
|
|
|
fn read(input: &str) -> Result<Vec<Sexp>, String> {
|
|
|
|
let mut chars: Peekable<Chars> = input.chars().peekable();
|
|
|
|
let mut tokens = tokenize(&mut chars).into_iter().peekable();
|
|
|
|
let mut sexps = Vec::new();
|
2017-12-01 02:39:17 -08:00
|
|
|
while let Some(_) = tokens.peek() {
|
2017-12-01 02:16:28 -08:00
|
|
|
sexps.push(parse(&mut tokens)?);
|
2017-11-29 02:08:30 -08:00
|
|
|
}
|
2017-12-01 02:16:28 -08:00
|
|
|
Ok(sexps)
|
2017-11-28 03:37:16 -08:00
|
|
|
}
|
2017-11-27 00:57:26 -08:00
|
|
|
|
2017-11-30 22:37:49 -08:00
|
|
|
#[derive(Debug)]
|
|
|
|
enum Token {
|
|
|
|
LParen,
|
|
|
|
RParen,
|
2017-12-03 06:04:53 -08:00
|
|
|
Quote,
|
2017-12-03 17:11:17 -08:00
|
|
|
Word(String),
|
|
|
|
StringLiteral(String),
|
2017-12-03 19:21:56 -08:00
|
|
|
NumLiteral(u64),
|
2017-11-30 22:37:49 -08:00
|
|
|
}
|
|
|
|
|
2017-12-01 02:39:17 -08:00
|
|
|
#[derive(Debug)]
|
|
|
|
enum Sexp {
|
2017-12-03 22:20:43 -08:00
|
|
|
SymbolAtom(String),
|
|
|
|
StringAtom(String),
|
|
|
|
NumberAtom(u64),
|
2017-12-01 02:39:17 -08:00
|
|
|
List(Vec<Sexp>),
|
|
|
|
}
|
|
|
|
|
2017-12-03 17:11:17 -08:00
|
|
|
impl Sexp {
|
|
|
|
fn print(&self) -> String {
|
2017-12-03 22:20:43 -08:00
|
|
|
use self::Sexp::*;
|
2017-12-03 17:11:17 -08:00
|
|
|
match self {
|
2017-12-03 22:20:43 -08:00
|
|
|
&SymbolAtom(ref sym) => format!("{}", sym),
|
|
|
|
&StringAtom(ref s) => format!("\"{}\"", s),
|
|
|
|
&NumberAtom(ref n) => format!("{}", n),
|
2017-12-04 02:44:09 -08:00
|
|
|
&List(ref sexprs) => {
|
|
|
|
let mut output = String::new();
|
2017-12-04 03:02:38 -08:00
|
|
|
write!(&mut output, "(").unwrap();
|
2017-12-04 02:44:09 -08:00
|
|
|
for sexpr in sexprs.iter() {
|
2017-12-04 03:02:38 -08:00
|
|
|
write!(&mut output, "{}", sexpr.print()).unwrap();
|
2017-12-04 02:44:09 -08:00
|
|
|
}
|
2017-12-04 03:02:38 -08:00
|
|
|
write!(&mut output, ")").unwrap();
|
2017-12-04 02:44:09 -08:00
|
|
|
output
|
|
|
|
}
|
2017-12-03 17:11:17 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-30 22:37:49 -08:00
|
|
|
fn tokenize(input: &mut Peekable<Chars>) -> Vec<Token> {
|
2017-12-01 02:16:28 -08:00
|
|
|
use self::Token::*;
|
2017-11-30 22:37:49 -08:00
|
|
|
let mut tokens = Vec::new();
|
|
|
|
loop {
|
2017-12-01 02:16:28 -08:00
|
|
|
match input.next() {
|
2017-11-30 22:37:49 -08:00
|
|
|
None => break,
|
|
|
|
Some('(') => tokens.push(LParen),
|
|
|
|
Some(')') => tokens.push(RParen),
|
2017-12-03 06:04:53 -08:00
|
|
|
Some('\'') => tokens.push(Quote),
|
2017-12-01 02:16:28 -08:00
|
|
|
Some(c) if c.is_whitespace() => continue,
|
2017-12-03 19:21:56 -08:00
|
|
|
Some(c) if c.is_numeric() => {
|
|
|
|
let tok: String = input.peeking_take_while(|next| next.is_numeric()).collect();
|
|
|
|
let n: u64 = format!("{}{}", c, tok).parse().unwrap();
|
|
|
|
tokens.push(NumLiteral(n));
|
|
|
|
},
|
2017-12-03 17:11:17 -08:00
|
|
|
Some('"') => {
|
2017-12-03 17:47:17 -08:00
|
|
|
let string: String = input.scan(false, |escape, cur_char| {
|
|
|
|
let seen_escape = *escape;
|
|
|
|
*escape = cur_char == '\\' && !seen_escape;
|
2017-12-04 02:00:00 -08:00
|
|
|
match (cur_char, seen_escape) {
|
|
|
|
('"', false) => None,
|
|
|
|
('\\', false) => Some(None),
|
|
|
|
(c, _) => Some(Some(c))
|
2017-12-03 17:11:17 -08:00
|
|
|
}
|
2017-12-03 17:47:17 -08:00
|
|
|
}).filter_map(|x| x).collect();
|
2017-12-03 17:11:17 -08:00
|
|
|
tokens.push(StringLiteral(string));
|
|
|
|
}
|
2017-12-01 02:58:09 -08:00
|
|
|
Some(c) => {
|
2017-12-01 02:36:52 -08:00
|
|
|
let sym: String = input.peeking_take_while(|next| {
|
|
|
|
match *next {
|
|
|
|
'(' | ')' => false,
|
|
|
|
c if c.is_whitespace() => false,
|
|
|
|
_ => true
|
2017-12-01 02:16:28 -08:00
|
|
|
}
|
2017-12-01 02:36:52 -08:00
|
|
|
}).collect();
|
2017-12-01 03:00:42 -08:00
|
|
|
tokens.push(Word(format!("{}{}", c, sym)));
|
2017-11-30 22:37:49 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-12-01 02:16:28 -08:00
|
|
|
tokens
|
2017-11-30 22:37:49 -08:00
|
|
|
}
|
|
|
|
|
2017-12-01 02:16:28 -08:00
|
|
|
fn parse(tokens: &mut Peekable<IntoIter<Token>>) -> Result<Sexp, String> {
|
|
|
|
use self::Token::*;
|
2017-12-03 22:20:43 -08:00
|
|
|
use self::Sexp::*;
|
2017-12-01 02:16:28 -08:00
|
|
|
match tokens.next() {
|
2017-12-03 22:20:43 -08:00
|
|
|
Some(Word(s)) => Ok(SymbolAtom(s)),
|
|
|
|
Some(StringLiteral(s)) => Ok(StringAtom(s)),
|
2017-12-01 02:16:28 -08:00
|
|
|
Some(LParen) => parse_sexp(tokens),
|
|
|
|
Some(RParen) => Err(format!("Unexpected ')'")),
|
2017-12-03 06:04:53 -08:00
|
|
|
Some(Quote) => {
|
2017-12-04 01:57:24 -08:00
|
|
|
let quoted = parse(tokens)?;
|
|
|
|
Ok(List(vec![SymbolAtom(format!("quote")), quoted]))
|
2017-12-03 06:04:53 -08:00
|
|
|
},
|
2017-12-03 22:20:43 -08:00
|
|
|
Some(NumLiteral(n)) => Ok(NumberAtom(n)),
|
2017-12-01 02:16:28 -08:00
|
|
|
None => Err(format!("Unexpected end of input")),
|
2017-11-29 02:08:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-01 02:16:28 -08:00
|
|
|
fn parse_sexp(tokens: &mut Peekable<IntoIter<Token>>) -> Result<Sexp, String> {
|
|
|
|
use self::Token::*;
|
2017-12-04 01:57:24 -08:00
|
|
|
use self::Sexp::*;
|
2017-12-01 02:16:28 -08:00
|
|
|
let mut vec = Vec::new();
|
2017-11-29 02:08:30 -08:00
|
|
|
loop {
|
2017-12-01 02:16:28 -08:00
|
|
|
match tokens.peek() {
|
|
|
|
None => return Err(format!("Unexpected end of input")),
|
|
|
|
Some(&RParen) => { tokens.next(); break},
|
|
|
|
_ => vec.push(parse(tokens)?),
|
2017-11-29 02:08:30 -08:00
|
|
|
}
|
|
|
|
}
|
2017-12-04 01:57:24 -08:00
|
|
|
Ok(List(vec))
|
2017-11-28 03:37:16 -08:00
|
|
|
}
|
|
|
|
|