Basic functionality achieved

This commit is contained in:
Apache 2024-06-12 19:16:10 -05:00
parent aee4fbdc34
commit b51ace40df
Signed by: apache
GPG key ID: 6B10F3EAF14F4C77
5 changed files with 117 additions and 25 deletions

View file

@ -6,11 +6,15 @@ pub struct LispState {
table: HashMap<String, LispValue>, 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 { impl LispState {
pub fn new() -> LispState { pub fn new() -> LispState {
let mut table = HashMap::new(); let mut table = HashMap::new();
table.insert(String::from("print"), LispValue::RustFunction(String::from("print"), |x| { add_function(&mut table, "print", |x| {
let mut strings = Vec::new(); let mut strings = Vec::new();
for val in x { for val in x {
strings.push(val.to_string()); strings.push(val.to_string());
@ -19,24 +23,66 @@ impl LispState {
let str = strings.join(" "); let str = strings.join(" ");
println!("{}", str); println!("{}", str);
LispValue::Nil vec![LispValue::Nil]
})); });
add_function(&mut table, "add", |x| {
if x.len() != 2 {
return vec![LispValue::Nil]
}
if let (LispValue::Integer(lhs), LispValue::Integer(rhs)) = (&x[0], &x[1]) {
return vec![LispValue::Integer(lhs + rhs)];
} else if let (LispValue::String(lhs), LispValue::String(rhs)) = (&x[0], &x[1]) {
return vec![LispValue::String(lhs.to_owned() + rhs)];
} else {
return vec![LispValue::Nil];
}
});
LispState { LispState {
table 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>) { pub fn execute(&self, instructions: Vec<OpCode>) {
println!("{:?}", instructions);
for op in instructions { for op in instructions {
match op { match op {
OpCode::Call(func, args) => { OpCode::Call(func, args) => {
let f = self.table.get(&func).unwrap(); self.do_call(&OpCode::Call(func, args));
if let LispValue::RustFunction(_, f) = f {
f(args);
} else {
todo!();
}
}, },
OpCode::Exp(ins) => { OpCode::Exp(ins) => {
self.execute(ins); self.execute(ins);

View file

@ -17,7 +17,6 @@ fn main() {
Vec::new() Vec::new()
} }
}; };
println!("{:?}", tokens);
let instructions = parse(tokens); let instructions = parse(tokens);
let state = LispState::new(); let state = LispState::new();

View file

@ -2,12 +2,15 @@ use std::fmt;
use crate::Token; use crate::Token;
#[derive(Debug, Clone)]
pub enum LispValue { pub enum LispValue {
Nil, Nil,
String(String), String(String),
Integer(i32),
LispFunction(String, Vec<OpCode>), LispFunction(String, Vec<OpCode>),
RustFunction(String, fn(Vec<LispValue>) -> LispValue), RustFunction(String, fn(Vec<LispValue>) -> Vec<LispValue>),
Exp(OpCode) Ref(String),
Eval(OpCode)
} }
impl fmt::Display for LispValue { impl fmt::Display for LispValue {
@ -17,6 +20,8 @@ impl fmt::Display for LispValue {
LispValue::String(str) => write!(f, "{}", str), LispValue::String(str) => write!(f, "{}", str),
LispValue::LispFunction(name, _) => write!(f, "<'{}': Lisp Function>", name), LispValue::LispFunction(name, _) => write!(f, "<'{}': Lisp Function>", name),
LispValue::RustFunction(name, _) => write!(f, "<'{}': Rust Function>", name), LispValue::RustFunction(name, _) => write!(f, "<'{}': Rust Function>", name),
LispValue::Integer(num) => write!(f, "{}", num),
LispValue::Ref(name) => write!(f, "<'{}': Reference>", name),
_ => todo!() _ => todo!()
} }
} }
@ -34,6 +39,13 @@ impl From<String> for LispValue {
} }
} }
impl From<i32> for LispValue {
fn from(value: i32) -> Self {
LispValue::Integer(value)
}
}
#[derive(Debug, Clone)]
pub enum OpCode { pub enum OpCode {
Call(String, Vec<LispValue>), Call(String, Vec<LispValue>),
Exp(Vec<OpCode>) Exp(Vec<OpCode>)
@ -44,7 +56,7 @@ fn read_exp(open_paren_idx: usize, tokens: &Vec<Token>) -> Option<(Vec<Token>, u
let mut tkns = Vec::new(); let mut tkns = Vec::new();
let mut depth = 0; let mut depth = 0;
for i in open_paren_idx..tokens.len() - 1 { for i in open_paren_idx..tokens.len() {
match &tokens[i] { match &tokens[i] {
Token::OpenParen => { Token::OpenParen => {
if depth != 0 { if depth != 0 {
@ -56,6 +68,8 @@ fn read_exp(open_paren_idx: usize, tokens: &Vec<Token>) -> Option<(Vec<Token>, u
depth -= 1; depth -= 1;
if depth == 0 { if depth == 0 {
return Some((tkns, i)); return Some((tkns, i));
} else {
tkns.push(Token::CloseParen)
} }
} }
token => { token => {
@ -68,14 +82,50 @@ fn read_exp(open_paren_idx: usize, tokens: &Vec<Token>) -> Option<(Vec<Token>, u
} }
fn parse_exp(tokens: Vec<Token>) -> Vec<OpCode> { fn parse_exp(tokens: Vec<Token>) -> Vec<OpCode> {
todo!() 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::String(str) => {
args.push(LispValue::String(str.to_owned()));
}
Token::CloseParen => {
panic!("Unexpected closing parenthesis");
},
_ => todo!()
}
i += 1;
}
opcodes.push(OpCode::Call(name.to_owned(), args))
}
opcodes
} }
pub fn parse(tokens: Vec<Token>) -> Vec<OpCode> { pub fn parse(tokens: Vec<Token>) -> Vec<OpCode> {
let mut opcodes = Vec::new(); let mut opcodes = Vec::new();
let mut current_depth = 0;
let mut seeking = false;
let mut i = 0; let mut i = 0;
while i < tokens.len() { while i < tokens.len() {
@ -86,13 +136,13 @@ pub fn parse(tokens: Vec<Token>) -> Vec<OpCode> {
i = close_paren_idx; i = close_paren_idx;
} }
tkn => { tkn => {
// TODO: Include more error data
panic!("Unexpected token {:?}", tkn); panic!("Unexpected token {:?}", tkn);
} }
} }
i += 1; i += 1;
} }
// opcodes.push(OpCode::Call("print".to_string(), vec![ // opcodes.push(OpCode::Call("print".to_string(), vec![
// LispValue::from("Hello, World!") // LispValue::from("Hello, World!")
// ])); // ]));

View file

@ -1,10 +1,5 @@
; This is a comment ; This is a comment
(print "Hello, World") ; OpCode::Call("print", {"Hello, World"}) (print "Hello, World")
(print (add 1 2)) (print (add 1 2))
; OpCode::Call("print", {
; OpCode::Exp({
; OpCode::Call("add", 1, 2)
; })
; })

View file

@ -154,8 +154,10 @@ impl Tokenizer {
self.storage.push(c); self.storage.push(c);
continue; continue;
// Allow numbers to also start with _ for fun // Allow numbers to also start with _ for fun
// ______100_0__: 1,000 // ______100_0__: 1,000
// TODO: delete this when I expand identifiers to include more symbols // TODO: delete this when I expand identifiers to include more symbols
} else if c.is_numeric() || c == '_' { } else if c.is_numeric() || c == '_' {
self.reading_num = true; self.reading_num = true;