Fresh start
This commit is contained in:
parent
ef387fc051
commit
e4d211b075
3 changed files with 4 additions and 479 deletions
328
src/executor.rs
328
src/executor.rs
|
@ -1,328 +0,0 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use crate::{OpCode, LispValue};
|
|
||||||
|
|
||||||
pub struct LispState {
|
|
||||||
table: HashMap<String, LispValue>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_function<T: Into<String> + Clone>(table: &mut HashMap<String, LispValue>, name: T, func: fn(Vec<LispValue>) -> Vec<LispValue>) {
|
|
||||||
table.insert(name.clone().into(), LispValue::RustFunction(name.into(), func));
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LispState {
|
|
||||||
pub fn new() -> LispState {
|
|
||||||
let mut table = HashMap::new();
|
|
||||||
|
|
||||||
add_function(&mut table, "print", |x| {
|
|
||||||
let mut strings = Vec::new();
|
|
||||||
for val in x {
|
|
||||||
strings.push(val.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
let str = strings.join(" ");
|
|
||||||
println!("{}", str);
|
|
||||||
|
|
||||||
vec![LispValue::Nil]
|
|
||||||
});
|
|
||||||
|
|
||||||
add_function(&mut table, "concat", |x| {
|
|
||||||
let mut strings = Vec::new();
|
|
||||||
for val in x {
|
|
||||||
strings.push(val.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
let str = strings.concat();
|
|
||||||
vec![LispValue::String(str)]
|
|
||||||
});
|
|
||||||
|
|
||||||
add_function(&mut table, "add", |x| {
|
|
||||||
if x.len() < 1 {
|
|
||||||
return vec![LispValue::Nil]
|
|
||||||
} else if x.len() == 1 {
|
|
||||||
return vec![x[0].clone()];
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut t = "int";
|
|
||||||
for v in &x {
|
|
||||||
match v {
|
|
||||||
LispValue::Float(_) => t = "float",
|
|
||||||
LispValue::Integer(_) => (),
|
|
||||||
_ => return vec![LispValue::Nil]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match t {
|
|
||||||
"int" => {
|
|
||||||
let mut sum = 0;
|
|
||||||
for v in &x {
|
|
||||||
if let LispValue::Integer(n) = v {
|
|
||||||
sum += n;
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vec![LispValue::Integer(sum)];
|
|
||||||
},
|
|
||||||
"float" => {
|
|
||||||
let mut sum = 0.0 as f32;
|
|
||||||
for v in &x {
|
|
||||||
if let LispValue::Float(n) = v {
|
|
||||||
sum += n;
|
|
||||||
} else if let LispValue::Integer(n) = v{
|
|
||||||
sum += *n as f32;
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vec![LispValue::Float(sum)];
|
|
||||||
},
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add_function(&mut table, "sub", |x| {
|
|
||||||
if x.len() < 1 {
|
|
||||||
return vec![LispValue::Nil]
|
|
||||||
} else if x.len() == 1 {
|
|
||||||
return vec![x[0].clone()];
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut t = "int";
|
|
||||||
for v in &x {
|
|
||||||
match v {
|
|
||||||
LispValue::Float(_) => t = "float",
|
|
||||||
LispValue::Integer(_) => (),
|
|
||||||
_ => return vec![LispValue::Nil]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match t {
|
|
||||||
"int" => {
|
|
||||||
if let LispValue::Integer(n) = x[0] {
|
|
||||||
let mut sum = n;
|
|
||||||
for i in 1..x.len() {
|
|
||||||
if let LispValue::Integer(n) = &x[i] {
|
|
||||||
sum -= n;
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vec![LispValue::Integer(sum)];
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"float" => {
|
|
||||||
if let LispValue::Float(n) = x[0] {
|
|
||||||
let mut sum = n;
|
|
||||||
for i in 1..x.len() {
|
|
||||||
if let LispValue::Float(n) = &x[i] {
|
|
||||||
sum -= *n;
|
|
||||||
} else if let LispValue::Integer(n) = &x[i] {
|
|
||||||
sum -= *n as f32;
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vec![LispValue::Float(sum)];
|
|
||||||
} else if let LispValue::Integer(n) = x[0] {
|
|
||||||
let mut sum = n as f32;
|
|
||||||
for i in 1..x.len() {
|
|
||||||
if let LispValue::Float(n) = &x[i] {
|
|
||||||
sum -= *n;
|
|
||||||
} else if let LispValue::Integer(n) = &x[i] {
|
|
||||||
sum -= *n as f32;
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vec![LispValue::Float(sum)];
|
|
||||||
} {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add_function(&mut table, "mul", |x| {
|
|
||||||
if x.len() < 1 {
|
|
||||||
return vec![LispValue::Nil]
|
|
||||||
} else if x.len() == 1 {
|
|
||||||
return vec![x[0].clone()];
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut t = "int";
|
|
||||||
for v in &x {
|
|
||||||
match v {
|
|
||||||
LispValue::Float(_) => t = "float",
|
|
||||||
LispValue::Integer(_) => (),
|
|
||||||
_ => return vec![LispValue::Nil]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match t {
|
|
||||||
"int" => {
|
|
||||||
if let LispValue::Integer(n) = x[0] {
|
|
||||||
let mut sum = n;
|
|
||||||
for i in 1..x.len() {
|
|
||||||
if let LispValue::Integer(n) = &x[i] {
|
|
||||||
sum *= n;
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vec![LispValue::Integer(sum)];
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"float" => {
|
|
||||||
if let LispValue::Float(n) = x[0] {
|
|
||||||
let mut product = n;
|
|
||||||
for i in 1..x.len() {
|
|
||||||
if let LispValue::Float(n) = &x[i] {
|
|
||||||
product *= *n;
|
|
||||||
} else if let LispValue::Integer(n) = &x[i] {
|
|
||||||
product *= *n as f32;
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vec![LispValue::Float(product)];
|
|
||||||
} else if let LispValue::Integer(n) = x[0] {
|
|
||||||
let mut product = n as f32;
|
|
||||||
for i in 1..x.len() {
|
|
||||||
if let LispValue::Float(n) = &x[i] {
|
|
||||||
product *= *n;
|
|
||||||
} else if let LispValue::Integer(n) = &x[i] {
|
|
||||||
product *= *n as f32;
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vec![LispValue::Float(product)];
|
|
||||||
} {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add_function(&mut table, "div", |x| {
|
|
||||||
if x.len() < 1 {
|
|
||||||
return vec![LispValue::Nil]
|
|
||||||
} else if x.len() == 1 {
|
|
||||||
return vec![x[0].clone()];
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut t = "int";
|
|
||||||
for v in &x {
|
|
||||||
match v {
|
|
||||||
LispValue::Float(_) => t = "float",
|
|
||||||
LispValue::Integer(_) => (),
|
|
||||||
_ => return vec![LispValue::Nil]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match t {
|
|
||||||
"int" => {
|
|
||||||
if let LispValue::Integer(n) = x[0] {
|
|
||||||
let mut sum = n;
|
|
||||||
for i in 1..x.len() {
|
|
||||||
if let LispValue::Integer(n) = &x[i] {
|
|
||||||
sum /= n;
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vec![LispValue::Integer(sum)];
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"float" => {
|
|
||||||
if let LispValue::Float(n) = x[0] {
|
|
||||||
let mut product = n;
|
|
||||||
for i in 1..x.len() {
|
|
||||||
if let LispValue::Float(n) = &x[i] {
|
|
||||||
product /= *n;
|
|
||||||
} else if let LispValue::Integer(n) = &x[i] {
|
|
||||||
product /= *n as f32;
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vec![LispValue::Float(product)];
|
|
||||||
} else if let LispValue::Integer(n) = x[0] {
|
|
||||||
let mut product = n as f32;
|
|
||||||
for i in 1..x.len() {
|
|
||||||
if let LispValue::Float(n) = &x[i] {
|
|
||||||
product /= *n;
|
|
||||||
} else if let LispValue::Integer(n) = &x[i] {
|
|
||||||
product /= *n as f32;
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vec![LispValue::Float(product)];
|
|
||||||
} {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
LispState {
|
|
||||||
table
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_call(&self, opcode: &OpCode) -> Vec<LispValue> {
|
|
||||||
if let OpCode::Call(func, args) = opcode {
|
|
||||||
let f = self.table.get(func).unwrap();
|
|
||||||
|
|
||||||
let mut args: Vec<LispValue> = args.clone();
|
|
||||||
for i in 0..args.len() {
|
|
||||||
let arg = &args[i];
|
|
||||||
if let LispValue::Eval(OpCode::Exp(opcodes)) = arg {
|
|
||||||
if opcodes.len() < 1 {
|
|
||||||
args[i] = LispValue::Nil;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let call_opcode = opcodes.last().unwrap();
|
|
||||||
let mut res = self.do_call(call_opcode);
|
|
||||||
args.remove(i);
|
|
||||||
for j in 0..res.len() {
|
|
||||||
args.insert(i + j, res.remove(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let LispValue::RustFunction(_, f) = f {
|
|
||||||
return f(args.to_vec());
|
|
||||||
} else {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
panic!("Bad OpCode: expected OpCode::Call")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute(&self, instructions: Vec<OpCode>) {
|
|
||||||
for op in instructions {
|
|
||||||
match op {
|
|
||||||
OpCode::Call(func, args) => {
|
|
||||||
self.do_call(&OpCode::Call(func, args));
|
|
||||||
},
|
|
||||||
OpCode::Exp(ins) => {
|
|
||||||
self.execute(ins);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
151
src/parser.rs
151
src/parser.rs
|
@ -1,151 +0,0 @@
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
use crate::Token;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum LispValue {
|
|
||||||
Nil,
|
|
||||||
String(String),
|
|
||||||
Integer(i32),
|
|
||||||
Float(f32),
|
|
||||||
LispFunction(String, Vec<OpCode>),
|
|
||||||
RustFunction(String, fn(Vec<LispValue>) -> Vec<LispValue>),
|
|
||||||
Ref(String),
|
|
||||||
Eval(OpCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for LispValue {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
LispValue::Nil => write!(f, "nil"),
|
|
||||||
LispValue::String(str) => write!(f, "{}", str),
|
|
||||||
LispValue::LispFunction(name, _) => write!(f, "<'{}': Lisp Function>", name),
|
|
||||||
LispValue::RustFunction(name, _) => write!(f, "<'{}': Rust Function>", name),
|
|
||||||
LispValue::Integer(num) => write!(f, "{}", num),
|
|
||||||
LispValue::Float(num) => write!(f, "{}", num),
|
|
||||||
LispValue::Ref(name) => write!(f, "<'{}': Reference>", name),
|
|
||||||
_ => todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&str> for LispValue {
|
|
||||||
fn from(value: &str) -> Self {
|
|
||||||
LispValue::String(value.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<String> for LispValue {
|
|
||||||
fn from(value: String) -> Self {
|
|
||||||
LispValue::String(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<i32> for LispValue {
|
|
||||||
fn from(value: i32) -> Self {
|
|
||||||
LispValue::Integer(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum OpCode {
|
|
||||||
Call(String, Vec<LispValue>),
|
|
||||||
Exp(Vec<OpCode>)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Handle failure
|
|
||||||
fn read_exp(open_paren_idx: usize, tokens: &Vec<Token>) -> Option<(Vec<Token>, usize)> /* Option<tokens, close_paren_idx> */ {
|
|
||||||
let mut tkns = Vec::new();
|
|
||||||
let mut depth = 0;
|
|
||||||
|
|
||||||
for i in open_paren_idx..tokens.len() {
|
|
||||||
match &tokens[i] {
|
|
||||||
Token::OpenParen => {
|
|
||||||
if depth != 0 {
|
|
||||||
tkns.push(Token::OpenParen);
|
|
||||||
}
|
|
||||||
depth += 1;
|
|
||||||
}
|
|
||||||
Token::CloseParen => {
|
|
||||||
depth -= 1;
|
|
||||||
if depth == 0 {
|
|
||||||
return Some((tkns, i));
|
|
||||||
} else {
|
|
||||||
tkns.push(Token::CloseParen)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
token => {
|
|
||||||
tkns.push(token.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_exp(tokens: Vec<Token>) -> Vec<OpCode> {
|
|
||||||
let mut opcodes = Vec::new();
|
|
||||||
|
|
||||||
if tokens.len() < 1 {
|
|
||||||
return opcodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Token::Identifier(name) = &tokens[0] {
|
|
||||||
let mut args = Vec::new();
|
|
||||||
|
|
||||||
let mut i = 1;
|
|
||||||
while i < tokens.len() {
|
|
||||||
let tkn = &tokens[i];
|
|
||||||
match tkn {
|
|
||||||
Token::OpenParen => {
|
|
||||||
let (tkns, close_paren_idx) = read_exp(i, &tokens).unwrap();
|
|
||||||
args.push(LispValue::Eval(OpCode::Exp(parse_exp(tkns))));
|
|
||||||
i = close_paren_idx;
|
|
||||||
},
|
|
||||||
Token::Identifier(name) => {
|
|
||||||
args.push(LispValue::Ref(name.to_owned()));
|
|
||||||
},
|
|
||||||
Token::Integer(num) => {
|
|
||||||
args.push(LispValue::Integer(*num));
|
|
||||||
},
|
|
||||||
Token::Float(num) => {
|
|
||||||
args.push(LispValue::Float(*num));
|
|
||||||
},
|
|
||||||
Token::String(str) => {
|
|
||||||
args.push(LispValue::String(str.to_owned()));
|
|
||||||
},
|
|
||||||
Token::CloseParen => {
|
|
||||||
panic!("Unexpected closing parenthesis");
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
opcodes.push(OpCode::Call(name.to_owned(), args))
|
|
||||||
}
|
|
||||||
|
|
||||||
opcodes
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(tokens: Vec<Token>) -> Vec<OpCode> {
|
|
||||||
let mut opcodes = Vec::new();
|
|
||||||
|
|
||||||
let mut i = 0;
|
|
||||||
while i < tokens.len() {
|
|
||||||
match &tokens[i] {
|
|
||||||
Token::OpenParen => {
|
|
||||||
let (tkns, close_paren_idx) = read_exp(i, &tokens).unwrap();
|
|
||||||
opcodes.push(OpCode::Exp(parse_exp(tkns)));
|
|
||||||
i = close_paren_idx;
|
|
||||||
}
|
|
||||||
tkn => {
|
|
||||||
// TODO: Include more error data
|
|
||||||
panic!("Unexpected token {:?}", tkn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
opcodes
|
|
||||||
}
|
|
|
@ -4,6 +4,8 @@ use std::fmt;
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
OpenParen,
|
OpenParen,
|
||||||
CloseParen,
|
CloseParen,
|
||||||
|
Quote,
|
||||||
|
Unquote,
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
String(String),
|
String(String),
|
||||||
Integer(i32),
|
Integer(i32),
|
||||||
|
@ -164,6 +166,8 @@ impl Tokenizer {
|
||||||
self.reading_string = true;
|
self.reading_string = true;
|
||||||
self.storage.clear();
|
self.storage.clear();
|
||||||
},
|
},
|
||||||
|
'\'' => tokens.push(Token::Quote),
|
||||||
|
',' => tokens.push(Token::Unquote),
|
||||||
c => {
|
c => {
|
||||||
if c.is_alphabetic() {
|
if c.is_alphabetic() {
|
||||||
self.reading_identifier = true;
|
self.reading_identifier = true;
|
||||||
|
|
Reference in a new issue