schala/src/rukka_lang/mod.rs

376 lines
11 KiB
Rust
Raw Normal View History

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-07 20:28:09 -08:00
use std::collections::HashMap;
2017-12-07 20:28:09 -08:00
pub struct EvaluatorState {
2017-12-21 03:11:56 -08:00
binding_stack: Vec<HashMap<String, Sexp>>
2017-12-07 20:28:09 -08:00
}
2017-12-03 22:10:19 -08:00
2017-12-10 03:35:51 -08:00
impl EvaluatorState {
fn new() -> EvaluatorState {
2017-12-21 03:11:56 -08:00
use self::Sexp::*;
let mut default_map = HashMap::new();
default_map.insert(format!("+"), Builtin("+".to_string()));
default_map.insert(format!("-"), Builtin("-".to_string()));
default_map.insert(format!("*"), Builtin("*".to_string()));
default_map.insert(format!("/"), Builtin("/".to_string()));
default_map.insert(format!("%"), Builtin("%".to_string()));
2017-12-10 03:35:51 -08:00
EvaluatorState {
2017-12-21 03:11:56 -08:00
binding_stack: vec![default_map],
2017-12-10 03:35:51 -08:00
}
}
fn set_var(&mut self, var: String, value: Sexp) {
2017-12-21 03:11:56 -08:00
let binding = self.binding_stack.last_mut().unwrap();
binding.insert(var, value);
2017-12-10 03:35:51 -08:00
}
fn get_var(&self, var: &str) -> Option<&Sexp> {
2017-12-21 03:11:56 -08:00
for bindings in self.binding_stack.iter().rev() {
match bindings.get(var) {
Some(x) => return Some(x),
None => (),
}
}
None
2017-12-10 03:35:51 -08:00
}
}
pub struct Rukka {
2017-12-03 22:10:19 -08:00
state: EvaluatorState
}
impl Rukka {
2017-12-03 22:10:19 -08:00
pub fn new() -> Rukka { Rukka { state: EvaluatorState::new() } }
}
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);
output
}
}
2017-11-27 00:57:26 -08:00
2017-12-03 22:10:19 -08:00
impl EvaluatorState {
fn eval(&mut self, expr: Sexp) -> Result<Sexp, String> {
2017-12-03 22:20:43 -08:00
use self::Sexp::*;
2017-12-11 01:53:27 -08:00
println!("Evaling {:?}", expr);
2017-12-03 22:10:19 -08:00
Ok(match expr {
2017-12-20 22:56:24 -08:00
SymbolAtom(ref sym) => {
if is_builtin(sym) {
Builtin(sym.clone())
} else {
match self.get_var(sym) {
Some(ref sexp) => {
let q: &Sexp = sexp; //WTF? if I delete this line, the copy doesn't work??
q.clone() //TODO make this not involve a clone
},
None => return Err(format!("Variable {} not bound", sym)),
}
}
2017-12-09 19:08:01 -08:00
},
2017-12-20 22:56:24 -08:00
expr @ Builtin(_) => expr,
2017-12-11 01:53:27 -08:00
expr @ FnLiteral { .. } => expr,
2017-12-03 22:20:43 -08:00
expr @ StringAtom(_) => expr,
expr @ NumberAtom(_) => expr,
2017-12-07 19:51:34 -08:00
True => True,
False => False,
2017-12-10 19:01:44 -08:00
Cons(box operator, box operands) => match operator {
SymbolAtom(ref sym) if match &sym[..] {
"quote" | "eq?" | "cons" | "car" | "cdr" | "atom?" | "define" | "lambda" | "if" | "cond" => true, _ => false
} => self.eval_special_form(sym, operands)?,
_ => {
let evaled = self.eval(operator)?;
self.apply(evaled, operands)?
2017-12-04 01:57:24 -08:00
}
2017-12-04 03:23:55 -08:00
},
Nil => Nil,
2017-12-03 22:10:19 -08:00
})
}
2017-12-10 18:44:21 -08:00
fn eval_special_form(&mut self, form: &str, operands: Sexp) -> Result<Sexp, String> {
use self::Sexp::*;
Ok(match form {
2017-12-21 01:11:16 -08:00
"quote" => match operands {
Cons(box quoted, box Nil) => quoted,
_ => return Err(format!("Bad syntax in quote")),
},
2017-12-10 18:44:21 -08:00
"eq?" => match operands {
Cons(box lhs, box Cons(box rhs, _)) => {
match lhs == rhs {
true => True,
false => False,
}
},
_ => True,
},
"cons" => match operands {
Cons(box cadr, box Cons(box caddr, box Nil)) => {
let newl = self.eval(cadr)?;
let newr = self.eval(caddr)?;
Cons(Box::new(newl), Box::new(newr))
},
_ => return Err(format!("Bad arguments for cons")),
},
"car" => match operands {
Cons(box car, _) => car,
_ => return Err(format!("called car with a non-pair argument")),
},
"cdr" => match operands {
Cons(_, box cdr) => cdr,
_ => return Err(format!("called cdr with a non-pair argument")),
},
"atom?" => match operands {
Cons(_, _) => False,
_ => True,
},
"define" => match operands {
Cons(box SymbolAtom(sym), box Cons(box expr, box Nil)) => {
let evaluated = self.eval(expr)?;
self.set_var(sym, evaluated);
Nil
},
_ => return Err(format!("Bad assignment")),
}
"lambda" => match operands {
2017-12-12 02:56:10 -08:00
Cons(box mut paramlist, box Cons(box formalexp, box Nil)) => {
let mut formal_params = vec![];
{
2017-12-20 18:23:44 -08:00
let mut ptr = &paramlist;
loop {
match ptr {
&Cons(ref arg, ref rest) => {
if let SymbolAtom(ref sym) = **arg {
formal_params.push(sym.clone());
ptr = rest;
} else {
return Err(format!("Bad lambda format"));
}
},
_ => break,
}
}
2017-12-12 02:56:10 -08:00
}
FnLiteral {
formal_params,
body: Box::new(formalexp)
}
2017-12-10 18:44:21 -08:00
},
_ => return Err(format!("Bad lambda expression")),
},
"if" => match operands {
Cons(box test, box body) => {
let truth_value = test.truthy();
match (truth_value, body) {
(true, Cons(box consequent, _)) => consequent,
(false, Cons(_, box Cons(box alternative, _))) => alternative,
_ => return Err(format!("Bad if expression"))
}
},
_ => return Err(format!("Bad if expression"))
},
2017-12-11 01:55:08 -08:00
s => return Err(format!("Non-existent special form {}; this should never happen", s)),
2017-12-10 18:44:21 -08:00
})
}
2017-12-21 01:10:53 -08:00
fn apply(&mut self, function: Sexp, _operands: Sexp) -> Result<Sexp, String> {
use self::Sexp::*;
match function {
FnLiteral { formal_params, body } => {
Err(format!("unimplementd"))
},
Builtin(sym) => {
Err(format!("unimplementd"))
},
_ => return Err(format!("Bad type to apply")),
}
2017-12-10 18:44:21 -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-07 19:54:53 -08:00
//TODO make this notion of Eq more sophisticated
2017-12-09 19:08:01 -08:00
#[derive(Debug, PartialEq, Clone)]
2017-12-01 02:39:17 -08:00
enum Sexp {
2017-12-03 22:20:43 -08:00
SymbolAtom(String),
StringAtom(String),
NumberAtom(u64),
2017-12-07 19:51:34 -08:00
True,
False,
2017-12-04 03:23:55 -08:00
Cons(Box<Sexp>, Box<Sexp>),
2017-12-11 01:53:27 -08:00
Nil,
FnLiteral {
formal_params: Vec<String>,
body: Box<Sexp>
2017-12-20 22:56:24 -08:00
},
Builtin(String)
}
fn is_builtin(sym: &String) -> bool {
match &sym[..] {
"+" | "-" | "*" | "/" | "%" => true,
_ => false
2017-12-11 01:53:27 -08:00
}
2017-12-01 02:39:17 -08:00
}
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-07 19:51:34 -08:00
&True => format!("#t"),
&False => format!("#f"),
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 03:26:38 -08:00
&Cons(ref car, ref cdr) => format!("({} . {})", car.print(), cdr.print()),
2017-12-04 03:23:55 -08:00
&Nil => format!("()"),
2017-12-11 01:53:27 -08:00
&FnLiteral { ref formal_params, .. } => format!("<lambda {:?}>", formal_params),
2017-12-20 22:56:24 -08:00
&Builtin(ref sym) => format!("<builtin \"{}\">", sym),
2017-12-03 17:11:17 -08:00
}
}
2017-12-10 02:58:07 -08:00
fn truthy(&self) -> bool {
use self::Sexp::*;
match self {
&False => false,
_ => true
}
}
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-07 19:51:34 -08:00
Some(Word(ref s)) if s == "#f" => Ok(False),
Some(Word(ref s)) if s == "#t" => Ok(True),
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)?;
2017-12-21 01:11:16 -08:00
Ok(Cons(Box::new(SymbolAtom(format!("quote"))), Box::new(Cons(Box::new(quoted), Box::new(Nil)))))
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-04 03:23:55 -08:00
let mut cell = Nil;
{
let mut cell_ptr = &mut cell;
loop {
match tokens.peek() {
None => return Err(format!("Unexpected end of input")),
Some(&RParen) => {
tokens.next();
break;
},
_ => {
let current = parse(tokens)?;
let new_cdr = Cons(Box::new(current), Box::new(Nil));
match cell_ptr {
&mut Cons(_, ref mut cdr) => **cdr = new_cdr,
&mut Nil => *cell_ptr = new_cdr,
_ => unreachable!()
};
2017-12-07 11:22:59 -08:00
let old_ptr = cell_ptr;
let new_ptr: &mut Sexp = match old_ptr { &mut Cons(_, ref mut cdr) => cdr, _ => unreachable!() } as &mut Sexp;
cell_ptr = new_ptr;
}
2017-12-04 03:23:55 -08:00
}
2017-11-29 02:08:30 -08:00
}
}
2017-12-04 03:23:55 -08:00
Ok(cell)
2017-11-28 03:37:16 -08:00
}