1
1
Fork 0
mirror of https://github.com/azur1s/bobbylisp.git synced 2024-10-16 02:37:40 -05:00

Compare commits

...

2 commits

Author SHA1 Message Date
azur 0a62f14571 fix comment not being ignored 2022-12-14 13:00:16 +07:00
azur a53d7b31f0 fix function with lambda body 2022-12-14 12:50:02 +07:00
6 changed files with 80 additions and 29 deletions

View file

@ -43,15 +43,15 @@ impl Compiler {
parser::BinaryOp::Sub => Instr::NumSub, parser::BinaryOp::Sub => Instr::NumSub,
parser::BinaryOp::Mul => Instr::NumMul, parser::BinaryOp::Mul => Instr::NumMul,
parser::BinaryOp::Div => Instr::NumDiv, parser::BinaryOp::Div => Instr::NumDiv,
// parser::BinaryOp::Eq => Instr::Eq, parser::BinaryOp::Eq => Instr::NumEq,
// parser::BinaryOp::Ne => Instr::Neq, parser::BinaryOp::Ne => todo!(),
// parser::BinaryOp::Lt => Instr::Lt, parser::BinaryOp::Lt => todo!(),
// parser::BinaryOp::Gt => Instr::Gt, parser::BinaryOp::Gt => todo!(),
// parser::BinaryOp::Le => Instr::Lte, parser::BinaryOp::Le => todo!(),
// parser::BinaryOp::Ge => Instr::Gte, parser::BinaryOp::Ge => todo!(),
parser::BinaryOp::And => Instr::BoolAnd, parser::BinaryOp::And => Instr::BoolAnd,
parser::BinaryOp::Or => Instr::BoolOr, parser::BinaryOp::Or => Instr::BoolOr,
_ => todo!(), parser::BinaryOp::Pipe => todo!(),
}); });
instrs instrs
} }
@ -128,10 +128,13 @@ impl Compiler {
match stmt { match stmt {
Stmt::Fun(name, args, body) => { Stmt::Fun(name, args, body) => {
let is_main = name == "main"; let is_main = name == "main";
let mut instrs = vec![ let mut instrs = match body.0 {
Instr::FuncMake(args, self.compile_expr(body.0)), // If the body is a lambda then we don't have to compile
Instr::Set(name), // it into a function
]; Expr::Lambda(_, _) => self.compile_expr(body.0),
_ => vec![Instr::FuncMake(args, self.compile_expr(body.0))],
};
instrs.push(Instr::Set(name));
if is_main { if is_main {
instrs.pop(); instrs.pop();
instrs.push(Instr::FuncApply); instrs.push(Instr::FuncApply);

View file

@ -13,9 +13,12 @@ fn main() {
if let Some(ast) = ast { if let Some(ast) = ast {
let mut compiler = Compiler::new(); let mut compiler = Compiler::new();
let instrs = compiler.compile_program(ast); let instrs = compiler.compile_program(ast);
instrs.iter().for_each(|i| println!("{:?}", i)); // instrs.iter().for_each(|i| println!("{:?}", i));
let mut executor = Executor::new(instrs); let mut executor = Executor::new(instrs);
match executor.run() { match executor.run_with(|exec| {
// println!("{:?}", exec.stack);
Ok(())
}) {
Ok(_) => {} Ok(_) => {}
Err(e) => println!("Runtime error: {:?}", e), Err(e) => println!("Runtime error: {:?}", e),
} }

View file

@ -1,4 +1,22 @@
fun main = do // start
let foo = if true then 10 else 5 in
print(foo) fun foo x = do
69 // unused
print("Hi")
x
end end
/* block comment
fun invalid =
*/
fun fac n = if n == 0 then 1 else n * fac(n - 1)
fun main = do
print(foo(1))
print(fac(5))
end
// end

View file

@ -174,15 +174,25 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = Simple<char>> {
.or(symbol) .or(symbol)
.or(delim) .or(delim)
.or(keyword) .or(keyword)
.map_with_span(move |token, span| (token, span))
.padded()
.recover_with(skip_then_retry_until([])); .recover_with(skip_then_retry_until([]));
let comment = just("--").then(take_until(just('\n'))).padded(); let comments = just('/')
.then_ignore(
just('*')
.ignore_then(take_until(just("*/")).ignored())
.or(just('/').ignore_then(none_of('\n').ignored().repeated().ignored())),
)
.padded()
.ignored()
.repeated();
token token
.padded_by(comment.repeated()) .padded_by(comments)
.map_with_span(|token, span| (token, span))
.padded()
.repeated() .repeated()
.padded()
.then_ignore(end())
} }
pub fn lex(src: String) -> (Option<Vec<(Token, Span)>>, Vec<Simple<char>>) { pub fn lex(src: String) -> (Option<Vec<(Token, Span)>>, Vec<Simple<char>>) {

View file

@ -38,6 +38,15 @@ impl Executor {
Ok(()) Ok(())
} }
pub fn run_with<F: Fn(&mut Self) -> Result<(), Error>>(&mut self, f: F) -> Result<(), Error> {
while self.ip < self.instrs.len() {
self.step()?;
self.ip += 1;
f(self)?;
}
Ok(())
}
fn err(&self, msg: &str) -> Error { fn err(&self, msg: &str) -> Error {
Error::make(msg, self.ip) Error::make(msg, self.ip)
} }
@ -93,10 +102,10 @@ impl Executor {
.ok_or_else(|| self.err("invalid instruction pointer"))?; .ok_or_else(|| self.err("invalid instruction pointer"))?;
macro_rules! impl_num_binop { macro_rules! impl_num_binop {
($op:tt) => { ($op:tt, $ret:ident) => {
match (self.pop()?, self.pop()?) { match (self.pop()?, self.pop()?) {
(Value::Num(a), Value::Num(b)) => { (Value::Num(a), Value::Num(b)) => {
self.stack.push(Value::Num(a $op b)); self.stack.push(Value::$ret(a $op b));
} }
_ => return Err(Error::make("can't apply operator to non-numbers", self.ip)), _ => return Err(Error::make("can't apply operator to non-numbers", self.ip)),
} }
@ -117,11 +126,12 @@ impl Executor {
Instr::NumPush(x) => { Instr::NumPush(x) => {
self.push(Value::Num(*x))?; self.push(Value::Num(*x))?;
} }
Instr::NumAdd => impl_num_binop!(+), Instr::NumAdd => impl_num_binop!(+, Num),
Instr::NumSub => impl_num_binop!(-), Instr::NumSub => impl_num_binop!(-, Num),
Instr::NumMul => impl_num_binop!(*), Instr::NumMul => impl_num_binop!(*, Num),
Instr::NumDiv => impl_num_binop!(/), Instr::NumDiv => impl_num_binop!(/, Num),
Instr::NumMod => impl_num_binop!(%), Instr::NumMod => impl_num_binop!(%, Num),
Instr::NumEq => impl_num_binop!(==, Bool),
Instr::BoolPush(x) => { Instr::BoolPush(x) => {
self.push(Value::Bool(*x))?; self.push(Value::Bool(*x))?;

View file

@ -103,7 +103,8 @@ pub enum Instr {
NumSub, // │ 1 byte NumSub, // │ 1 byte
NumMul, // │ NumMul, // │
NumDiv, // │ NumDiv, // │
NumMod, // ┘ NumMod, // │
NumEq, // ┘
BoolPush(bool), // 2 bytes: 1 byte for the enum, 1 byte for the bool BoolPush(bool), // 2 bytes: 1 byte for the enum, 1 byte for the bool
BoolAnd, // ┐ 1 byte BoolAnd, // ┐ 1 byte
@ -171,7 +172,12 @@ impl Instr {
pub fn size(&self) -> usize { pub fn size(&self) -> usize {
match self { match self {
Instr::NumPush(_) => 1 + std::mem::size_of::<i64>(), Instr::NumPush(_) => 1 + std::mem::size_of::<i64>(),
Instr::NumAdd | Instr::NumSub | Instr::NumMul | Instr::NumDiv | Instr::NumMod => 1, Instr::NumAdd
| Instr::NumSub
| Instr::NumMul
| Instr::NumDiv
| Instr::NumMod
| Instr::NumEq => 1,
Instr::BoolPush(_) => 1 + std::mem::size_of::<bool>(), Instr::BoolPush(_) => 1 + std::mem::size_of::<bool>(),
Instr::BoolAnd | Instr::BoolOr | Instr::BoolNot => 1, Instr::BoolAnd | Instr::BoolOr | Instr::BoolNot => 1,
@ -227,6 +233,7 @@ impl Instr {
Instr::NumMul => bytes.push(index!()), Instr::NumMul => bytes.push(index!()),
Instr::NumDiv => bytes.push(index!()), Instr::NumDiv => bytes.push(index!()),
Instr::NumMod => bytes.push(index!()), Instr::NumMod => bytes.push(index!()),
Instr::NumEq => bytes.push(index!()),
Instr::BoolPush(b) => { Instr::BoolPush(b) => {
bytes.push(index!()); bytes.push(index!());