Compare commits
4 commits
f572fec5ae
...
9507ff65a3
Author | SHA256 | Date | |
---|---|---|---|
9507ff65a3 | |||
bf3e784b42 | |||
b67ac42cee | |||
66e7ab5b21 |
5 changed files with 192 additions and 102 deletions
140
src/executor.rs
140
src/executor.rs
|
@ -1,6 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, fmt};
|
||||
|
||||
use crate::{OpCode, LispValue};
|
||||
use crate::PreLispValue;
|
||||
|
||||
pub struct LispState {
|
||||
table: HashMap<String, LispValue>,
|
||||
|
@ -10,6 +10,54 @@ fn add_function<T: Into<String> + Clone>(table: &mut HashMap<String, LispValue>,
|
|||
table.insert(name.clone().into(), LispValue::RustFunction(name.into(), func));
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum LispValue {
|
||||
Nil,
|
||||
String(String),
|
||||
Integer(i32),
|
||||
Float(f32),
|
||||
List(Vec<LispValue>, bool),
|
||||
LispFunction(String, Vec<LispValue>),
|
||||
RustFunction(String, fn(Vec<LispValue>) -> Vec<LispValue>),
|
||||
}
|
||||
|
||||
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),
|
||||
val => {
|
||||
write!(f, "{}", format!("{:?}", val))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
impl From<f32> for LispValue {
|
||||
fn from(value: f32) -> Self {
|
||||
LispValue::Float(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl LispState {
|
||||
pub fn new() -> LispState {
|
||||
let mut table = HashMap::new();
|
||||
|
@ -281,47 +329,73 @@ impl LispState {
|
|||
}
|
||||
}
|
||||
|
||||
fn do_call(&self, opcode: &OpCode) -> Vec<LispValue> {
|
||||
if let OpCode::Call(func, args) = opcode {
|
||||
let f = self.table.get(func).unwrap();
|
||||
fn handle_prevalues(&self, input: Vec<PreLispValue>) -> Vec<LispValue> {
|
||||
let mut out = Vec::new();
|
||||
|
||||
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;
|
||||
}
|
||||
for v in input {
|
||||
out.push(match v {
|
||||
PreLispValue::Nil => LispValue::Nil,
|
||||
PreLispValue::String(str) => LispValue::String(str),
|
||||
PreLispValue::Integer(num) => LispValue::Integer(num),
|
||||
PreLispValue::Float(num) => LispValue::Float(num),
|
||||
PreLispValue::List(list, quoted) => {
|
||||
LispValue::List(Self::handle_prevalues(self, list), quoted)
|
||||
},
|
||||
PreLispValue::LispFunction(name, instructions) => {
|
||||
LispValue::LispFunction(name, Self::handle_prevalues(self, instructions))
|
||||
},
|
||||
PreLispValue::Var(name) => {
|
||||
self.table.get(&name).unwrap_or(&LispValue::Nil).to_owned()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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));
|
||||
out
|
||||
}
|
||||
|
||||
fn eval_list(list: &Vec<LispValue>, quoted: bool) -> (Vec<LispValue>, bool) {
|
||||
if list.len() < 1 {
|
||||
return (vec![LispValue::List(Vec::new(), quoted)], false);
|
||||
}
|
||||
|
||||
let list = &mut list.clone();
|
||||
|
||||
for i in 0..list.len() {
|
||||
if let LispValue::List(elements, quoted) = &list[i] {
|
||||
let (elems, astuple) = Self::eval_list(elements, *quoted);
|
||||
if astuple {
|
||||
list[i] = elems.get(0).unwrap_or(&LispValue::Nil).to_owned();
|
||||
for j in 1..elems.len() {
|
||||
list.insert(i, elems[j].to_owned());
|
||||
}
|
||||
} else {
|
||||
list[i] = LispValue::List(elems, *quoted);
|
||||
}
|
||||
}
|
||||
if let LispValue::RustFunction(_, f) = f {
|
||||
return f(args.to_vec());
|
||||
} else {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
if quoted {
|
||||
return (list.to_vec(), false);
|
||||
}
|
||||
|
||||
if let LispValue::RustFunction(_name, f) = &list[0] {
|
||||
(f(list[1..].to_vec()), true)
|
||||
} else if let LispValue::LispFunction(_name, ins) = &list[0] {
|
||||
(Self::call_lisp_func(&list[0], list[1..].to_vec()), true)
|
||||
} else {
|
||||
panic!("Bad OpCode: expected OpCode::Call")
|
||||
(list.to_vec(), false)
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
fn call_lisp_func(f: &LispValue, args: Vec<LispValue>) -> Vec<LispValue> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn execute(&self, instructions: Vec<PreLispValue>) {
|
||||
let instructions = Self::handle_prevalues(self, instructions);
|
||||
for val in instructions {
|
||||
if let LispValue::List(elements, quoted) = val {
|
||||
Self::eval_list(&elements, quoted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use executor::*;
|
|||
|
||||
fn main() {
|
||||
let source = std::fs::read_to_string("src/test.lisp").unwrap();
|
||||
|
||||
let mut tokenizer = Tokenizer::new(source);
|
||||
let tokens = match tokenizer.tokenize() {
|
||||
Ok(tokens) => tokens,
|
||||
|
|
131
src/parser.rs
131
src/parser.rs
|
@ -3,54 +3,53 @@ use std::fmt;
|
|||
use crate::Token;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum LispValue {
|
||||
pub enum PreLispValue {
|
||||
Nil,
|
||||
String(String),
|
||||
Var(String),
|
||||
Integer(i32),
|
||||
Float(f32),
|
||||
LispFunction(String, Vec<OpCode>),
|
||||
RustFunction(String, fn(Vec<LispValue>) -> Vec<LispValue>),
|
||||
Ref(String),
|
||||
Eval(OpCode)
|
||||
List(Vec<PreLispValue>, bool), // Values, Quoted
|
||||
LispFunction(String, Vec<PreLispValue>),
|
||||
}
|
||||
|
||||
impl fmt::Display for LispValue {
|
||||
impl fmt::Display for PreLispValue {
|
||||
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),
|
||||
PreLispValue::Nil => write!(f, "nil"),
|
||||
PreLispValue::String(str) => write!(f, "{}", str),
|
||||
PreLispValue::LispFunction(name, _) => write!(f, "<'{}': Lisp Function>", name),
|
||||
PreLispValue::Integer(num) => write!(f, "{}", num),
|
||||
PreLispValue::Float(num) => write!(f, "{}", num),
|
||||
_ => todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for LispValue {
|
||||
impl From<&str> for PreLispValue {
|
||||
fn from(value: &str) -> Self {
|
||||
LispValue::String(value.to_string())
|
||||
PreLispValue::String(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for LispValue {
|
||||
impl From<String> for PreLispValue {
|
||||
fn from(value: String) -> Self {
|
||||
LispValue::String(value)
|
||||
PreLispValue::String(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for LispValue {
|
||||
impl From<i32> for PreLispValue {
|
||||
fn from(value: i32) -> Self {
|
||||
LispValue::Integer(value)
|
||||
PreLispValue::Integer(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum OpCode {
|
||||
Call(String, Vec<LispValue>),
|
||||
Exp(Vec<OpCode>)
|
||||
impl From<f32> for PreLispValue {
|
||||
fn from(value: f32) -> Self {
|
||||
PreLispValue::Float(value)
|
||||
}
|
||||
}
|
||||
impl From<Vec<PreLispValue>> for PreLispValue {
|
||||
fn from(value: Vec<PreLispValue>) -> Self {
|
||||
PreLispValue::List(value, false)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Handle failure
|
||||
|
@ -83,60 +82,64 @@ fn read_exp(open_paren_idx: usize, tokens: &Vec<Token>) -> Option<(Vec<Token>, u
|
|||
None
|
||||
}
|
||||
|
||||
fn parse_exp(tokens: Vec<Token>) -> Vec<OpCode> {
|
||||
let mut opcodes = Vec::new();
|
||||
fn parse_exp(tokens: Vec<Token>, quoted: bool) -> PreLispValue {
|
||||
let mut values = Vec::new();
|
||||
|
||||
if tokens.len() < 1 {
|
||||
return opcodes;
|
||||
return PreLispValue::List(values, false);
|
||||
}
|
||||
|
||||
if let Token::Identifier(name) = &tokens[0] {
|
||||
let mut args = Vec::new();
|
||||
let mut quote_next_list = false;
|
||||
let mut unquote_next_list = false;
|
||||
|
||||
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");
|
||||
},
|
||||
let mut i = 0;
|
||||
while i < tokens.len() {
|
||||
let tkn = &tokens[i];
|
||||
match tkn {
|
||||
Token::Quote => {
|
||||
quote_next_list = true;
|
||||
},
|
||||
Token::Unquote => {
|
||||
unquote_next_list = true;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
Token::OpenParen => {
|
||||
let (tkns, close_paren_idx) = read_exp(i, &tokens).unwrap();
|
||||
values.push(parse_exp(tkns, if unquote_next_list {false} else {quote_next_list || quoted}));
|
||||
i = close_paren_idx;
|
||||
quote_next_list = false;
|
||||
unquote_next_list = false;
|
||||
},
|
||||
Token::Identifier(name) => {
|
||||
values.push(PreLispValue::Var(name.to_owned()));
|
||||
},
|
||||
Token::Integer(num) => {
|
||||
values.push(PreLispValue::Integer(*num));
|
||||
},
|
||||
Token::Float(num) => {
|
||||
values.push(PreLispValue::Float(*num));
|
||||
},
|
||||
Token::String(str) => {
|
||||
values.push(PreLispValue::String(str.to_owned()));
|
||||
},
|
||||
Token::CloseParen => {
|
||||
panic!("Unexpected closing parenthesis");
|
||||
},
|
||||
}
|
||||
|
||||
opcodes.push(OpCode::Call(name.to_owned(), args))
|
||||
i += 1;
|
||||
}
|
||||
|
||||
opcodes
|
||||
PreLispValue::List(values, quoted)
|
||||
}
|
||||
|
||||
pub fn parse(tokens: Vec<Token>) -> Vec<OpCode> {
|
||||
let mut opcodes = Vec::new();
|
||||
pub fn parse(tokens: Vec<Token>) -> Vec<PreLispValue> {
|
||||
let mut values = 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)));
|
||||
values.push(parse_exp(tkns, false));
|
||||
i = close_paren_idx;
|
||||
}
|
||||
tkn => {
|
||||
|
@ -147,5 +150,5 @@ pub fn parse(tokens: Vec<Token>) -> Vec<OpCode> {
|
|||
i += 1;
|
||||
}
|
||||
|
||||
opcodes
|
||||
values
|
||||
}
|
|
@ -1,8 +1,14 @@
|
|||
; This is a comment
|
||||
|
||||
(print
|
||||
(add
|
||||
1.0
|
||||
(mul 2 3)
|
||||
)
|
||||
)
|
||||
(add 0.5 3)
|
||||
)
|
||||
|
||||
; LispValue::List({
|
||||
; LispValue::RustFunction("print", <rust fn type>),
|
||||
; LispValue::List({
|
||||
; LispValue::RustFunction("add", <rust fn type>),
|
||||
; LispValue::Float(1.0),
|
||||
; LispValue::Integer(3)
|
||||
; })
|
||||
; })
|
|
@ -4,6 +4,8 @@ use std::fmt;
|
|||
pub enum Token {
|
||||
OpenParen,
|
||||
CloseParen,
|
||||
Quote,
|
||||
Unquote,
|
||||
Identifier(String),
|
||||
String(String),
|
||||
Integer(i32),
|
||||
|
@ -113,6 +115,8 @@ impl Tokenizer {
|
|||
tokens.push(Token::Integer(self.storage.iter().collect::<String>().parse().unwrap()));
|
||||
}
|
||||
|
||||
self.is_float = false;
|
||||
|
||||
self.storage.clear();
|
||||
} else {
|
||||
if char == '.' {
|
||||
|
@ -164,6 +168,8 @@ impl Tokenizer {
|
|||
self.reading_string = true;
|
||||
self.storage.clear();
|
||||
},
|
||||
'\'' => tokens.push(Token::Quote),
|
||||
',' => tokens.push(Token::Unquote),
|
||||
c => {
|
||||
if c.is_alphabetic() {
|
||||
self.reading_identifier = true;
|
||||
|
|
Reference in a new issue