diff --git a/src/compiler.rs b/src/compiler.rs index 9445078..d3f5a12 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,648 +1 @@ -use std::{cell::Cell, rc::Rc}; -use crate::{ - lexer::{Ident, Literal}, - parser::Expr, -}; - -use stack::Stack; - -mod stack; - -struct Scope<'a> { - values: Vec<(Ident, Rc)>, - parent: Option<&'a Scope<'a>>, -} -impl<'a> Stack<'a> for Scope<'a> { - type Value = (Ident, Rc); - type Input = Ident; - type Output = Rc; - - fn with_parent(parent: Option<&'a Self>) -> Self { - Self { - values: Vec::new(), - parent, - } - } - fn parent(&self) -> Option<&'a Self> { - self.parent - } - fn values(&self) -> &Vec { - &self.values - } - fn values_mut(&mut self) -> &mut Vec { - &mut self.values - } - - fn find_map(_: usize, value: &Self::Value, input: &Self::Input) -> Option { - (value.0 == *input).then_some(value.1.clone()) - } -} -impl Scope<'_> { - fn assigned(&mut self, id: Ident) -> Rc { - let Some((rm, _)) = self.find(&id) else { - let rm: Rc = Rc::default(); - self.push((id, rm.clone())); - return rm; - }; - rm - } -} - -#[derive(Debug, Default, Clone)] -pub struct FuncMeta { - pub is_unreturnable: Cell, -} -pub type FuncStat = Rc; - -#[derive(Debug, Clone)] -pub struct RefStat { - pub now: u16, - pub meta: Rc, -} - -#[derive(Debug, Default)] -pub struct RefMeta { - pub total: Cell, - pub is_shared: Cell, -} - -fn analyze(fs: &FuncStat, scope: &mut Scope, e: &mut Expr, gets_captured: bool) { - match e { - Expr::Assign(a, b) => { - let Expr::Literal(Literal::Ident(id, ref_stat)) = &mut **a else { - panic!("invalid assignment"); - }; - - // add to scope - let rm = scope.assigned(id.clone()); - - // add ref stat - *ref_stat = Some(RefStat { - now: rm.total.get(), - meta: rm, - }); - - // analyse the value - analyze(fs, scope, b, true); - } - Expr::Literal(Literal::Ident(id, ref_stat)) => { - // lookup ident - let Some((rm, up_levels)) = scope.find(id) else { - panic!("unfound variable") - }; - - // the var got used, so the compiler will gen code for it - // it is okay to count - if gets_captured { - // increment # of uses - rm.total.update(|c| c + 1); - - // if we used something external to this scope, note it - if up_levels != 0 { - fs.is_unreturnable.set(true); - rm.is_shared.set(true); - } - } - - // set ref meta - *ref_stat = Some(RefStat { - now: rm.total.get(), - meta: rm.clone(), - }); - } - // ignore - Expr::Literal(_) => {} - // for recursion.. - Expr::Block(a) => { - // blocks have their own scope - let mut scope = Scope::with_parent(Some(scope)); - // last is treated differently - let last = a.exprs.pop(); - // analyze the contents in the new scope - for e in &mut a.exprs { - analyze(fs, &mut scope, e, false); - } - // analyze last - if let Some(mut last) = last { - analyze(fs, &mut scope, &mut last, gets_captured); - a.exprs.push(last); - } - } - Expr::Func(a, b, func_stat) => { - // new function new context - let fs = FuncStat::default(); - *func_stat = Some(fs.clone()); - // functions have their own scope, because they have args - let mut scope = Scope::with_parent(Some(scope)); - - // init args - for e in a { - let Expr::Literal(Literal::Ident(id, _)) = e else { - panic!("invalid arg def"); - }; - scope.assigned(id.clone()); - } - - // now analyze the body in the new scope - analyze(&fs, &mut scope, b, true); - } - Expr::If(a, b, c) => { - analyze(fs, scope, a, true); - analyze(fs, scope, b, gets_captured); - if let Some(c) = c { - analyze(fs, scope, c, gets_captured); - } - } - Expr::Call(a, b) => { - analyze(fs, scope, a, true); - for e in b { - analyze(fs, scope, e, true); - } - } - Expr::Return(a) | Expr::Negate(a) | Expr::Not(a) => analyze(fs, scope, a, true), - Expr::EqualTo(a, b) - | Expr::NotEqualTo(a, b) - | Expr::And(a, b) - | Expr::Or(a, b) - | Expr::LessThan(a, b) - | Expr::LessThanOrEqualTo(a, b) - | Expr::GreaterThan(a, b) - | Expr::GreaterThanOrEqualTo(a, b) - | Expr::Add(a, b) - | Expr::Subtract(a, b) - | Expr::Multiply(a, b) - | Expr::Divide(a, b) - | Expr::Exponent(a, b) - | Expr::Modulo(a, b) => { - analyze(fs, scope, a, gets_captured); - analyze(fs, scope, b, gets_captured); - } - Expr::AddAssign(a, b) - | Expr::SubtractAssign(a, b) - | Expr::MultiplyAssign(a, b) - | Expr::DivideAssign(a, b) => { - analyze(fs, scope, a, true); - analyze(fs, scope, b, true); - } - } -} - -// --- translate pass --- // - -/* 1b is up? */ -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Stkval { - /* 12b offset */ - Local(u8), - /* 4b up levels ; 8b offset */ - Shared(u8, u8), -} -/* 3b type tag */ -#[derive(Debug, Clone, PartialEq)] -pub enum Val { - /* where? ; pop after use? */ - Stack(Stkval, bool), - /* u16 len, LEN data */ - String(String), - /* 1b returnability, 4b arity, insts */ - Func(bool, u8, Vec), - /* 1b value */ - Bool(bool), - /* i64 data */ - Int64(i64), - /* f64 data */ - Float64(f64), - /* ... */ - Nil, -} -/* 3b inst type */ -#[derive(Debug, Clone, PartialEq)] -pub enum Inst { - /* is shared? ; val to copy */ - Copy(bool, Val), - /* where to write, val to write */ - Move(Stkval, Val), - /* how much to increment PC */ - CJump(usize), - /* push result? ; # args provided ; val to call */ - Call(bool, u8, Val), - /* value to return */ - Return(Val), - /* lhs, rhs */ - Eq(Val, Val), - Gt(Val, Val), - GtEq(Val, Val), - Add(Val, Val), - Mul(Val, Val), - Div(Val, Val), - Mod(Val, Val), - Pow(Val, Val), - And(Val, Val), - Or(Val, Val), - /* rhs */ - Not(Val), -} - -/// Value on fake stack. -#[derive(Debug)] -enum FSValue { - Var(Ident), - Any, -} - -/// A stack that keeps track of values during translation. -/// (Local or shared) -struct FakeStack<'a> { - values: Vec, - parent: Option<&'a FakeStack<'a>>, -} -impl<'a> Stack<'a> for FakeStack<'a> { - type Value = FSValue; - type Input = Ident; - type Output = usize; - - fn with_parent(parent: Option<&'a Self>) -> Self { - Self { - values: Vec::new(), - parent, - } - } - fn parent(&self) -> Option<&'a Self> { - self.parent - } - fn values(&self) -> &Vec { - &self.values - } - fn values_mut(&mut self) -> &mut Vec { - &mut self.values - } - - fn find_map(index: usize, value: &Self::Value, input: &Self::Input) -> Option { - matches!(value, FSValue::Var(x) if x == input).then_some(index) - } -} - -/// Build scope of a function. -/// -/// * Starts with a base block scope that includes any arguments passed -/// * Contains the compiled instructions of all blocks inside it -/// * Keeps track of its own shared stack (contains vars that higher functions access) -/// * Keeps track of its own local stack (vars only used locally) -struct FuncBuild<'a> { - insts: Vec, - shared: FakeStack<'a>, - local: FakeStack<'a>, -} - -impl<'a> FuncBuild<'a> { - fn new_root() -> Self { - FuncBuild { - insts: Vec::new(), - shared: FakeStack::with_parent(None), - local: FakeStack::with_parent(None), - } - } - fn with_parent(parent: &'a FuncBuild<'a>) -> Self { - FuncBuild { - insts: Vec::new(), - shared: FakeStack::with_parent(Some(&parent.shared)), - local: FakeStack::with_parent(None), - } - } - - fn find(&mut self, id: &Ident) -> Option { - self.shared - .find(id) - .map(|(count, up_levels)| Stkval::Shared(up_levels as u8, count as u8)) - .or_else(|| self.local.find(id).map(|(c, _)| Stkval::Local(c as u8))) - } - - /// Returns stackval for top item of stack. - /// (Panics if empty) - fn top(&self) -> Stkval { - Stkval::Local(self.local.top_index() as u8) - } - /// Returns stackval for top item of shared stack. - /// (Panics if empty) - fn top_shared(&self) -> Stkval { - Stkval::Shared(0, self.shared.top_index() as u8) - } - - /// Pushes a value to stack and returns its stackval. - fn push_any(&mut self) -> Stkval { - self.local.push(FSValue::Any); - self.top() - } - - fn check_drop(&mut self, v: &Val) { - if let Val::Stack(Stkval::Local(i), true) = v { - self.local.pop(*i as usize); - } - } - - fn check_drops(&mut self, mut vl: [&mut Val; N]) { - use {Stkval::*, Val::*}; - - // Sort low->high - vl.sort_by_key(|v| match v { - Val::Stack(Stkval::Local(o), _) => *o as i16, - // It doesn't matter - _ => 0, - }); - - // Fix indices - let mut to_pop = Vec::new(); - for v in vl { - if let Stack(Local(o), p) = v { - *o -= to_pop.len() as u8; - if *p { - to_pop.push(*o as usize); - } - } - } - - // Pop - for o in to_pop { - self.local.pop(o); - } - } - - fn gen_unop(&mut self, r: Expr, f: impl Fn(Val) -> Inst, do_compute: bool) -> Val { - let v1 = self.translate(r, do_compute, false); - - // Don't compute anything unnecessarily - if !do_compute { - return Val::Nil; - } - - self.check_drop(&v1); - - self.insts.push(f(v1)); - Val::Stack(self.push_any(), true) - } - fn gen_binop( - &mut self, - l: Expr, - r: Expr, - f: impl Fn(Val, Val) -> Inst, - do_compute: bool, - ) -> Val { - let (mut v1, mut v2) = ( - self.translate(l, do_compute, false), - self.translate(r, do_compute, false), - ); - - // If this is unused, do not generate code - if !do_compute { - return Val::Nil; - } - - self.check_drops([&mut v1, &mut v2]); - - self.insts.push(f(v1, v2)); - Val::Stack(self.push_any(), true) - } - fn gen_copy(&mut self, v1: Val) -> Val { - self.check_drop(&v1); - self.insts.push(Inst::Copy(false, v1)); - Val::Stack(self.push_any(), false) - } - - fn translate(&mut self, e: Expr, do_compute: bool, do_yield: bool) -> Val { - match e { - /* organisational */ - Expr::Block(mut b) => { - let last = b.exprs.pop(); - for e in b.exprs { - self.translate(e, false, false); - } - // compute/yield last expr if requested - last.map_or(Val::Nil, |e| self.translate(e, do_compute, do_yield)) - } - Expr::Func(args, expr, fs) => { - // neww function!!!! - let mut fb = FuncBuild::with_parent(self); - // push args to stack - let arity = args.len() as u8; - for arg in args { - let Expr::Literal(Literal::Ident(id, _)) = arg else { - unreachable!() - }; - fb.local.push(FSValue::Var(id)); - } - // translate expr - fb.translate(*expr, true, false); - // pack - let returnability = fs.unwrap().is_unreturnable.get(); - Val::Func(returnability, arity, fb.insts) - } - - /* control flow */ - Expr::Return(r) => { - // calculate return value - let v1 = self.translate(*r, true, false); - // add return inst, eval to nil - self.insts.push(Inst::Return(v1)); - Val::Nil - } - Expr::Call(func, args) => { - // yield all args to stack - let n_args = args.len(); - for arg in args { - self.translate(arg, true, true); - } - // pop all of them - self.local.pop_top_n(n_args); - - // get the function - let v1 = self.translate(*func, true, false); - self.check_drop(&v1); - - // decide if we push result to stack - // if we are computing a value or yielding one, then yes - let push = do_compute || do_yield; - - // add call - self.insts.push(Inst::Call(push, n_args as u8, v1)); - - // whatever we output - if push { - Val::Stack(self.push_any(), true) - } else { - Val::Nil - } - } - Expr::If(cond, true_case, false_case) => todo!(), - - /* captured literal */ - Expr::Literal(lit) if do_yield => { - let v1 = self.translate(Expr::Literal(lit), true, false); - self.gen_copy(v1) - } - - /* 1 to 1 literals */ - Expr::Literal(Literal::Boolean(b)) => Val::Bool(b), - Expr::Literal(Literal::Float(f)) => Val::Float64(f), - Expr::Literal(Literal::Integer(i)) => Val::Int64(i), - Expr::Literal(Literal::Nil) => Val::Nil, - Expr::Literal(Literal::String(s)) => Val::String(s), - - /* vars */ - Expr::Literal(Literal::Ident(id, Some(rs))) if do_compute => { - let is_last_use = rs.now == rs.meta.total.get(); - let is_shared = rs.meta.is_shared.get(); - Val::Stack(self.find(&id).unwrap(), is_last_use && !is_shared) - } - Expr::Literal(Literal::Ident(_, _)) => Val::Nil, - Expr::Assign(l, r) => { - let Expr::Literal(Literal::Ident(id, Some(ref_stat))) = *l else { - unreachable!() - }; - - // will the var ever get referenced? - let gets_referenced = ref_stat.now != ref_stat.meta.total.get(); - - // if this isn't getting used for computation OR referenced, - // just continue translation without adding to stack - if !(do_compute || gets_referenced) { - self.translate(*r, false, false) - } else { - // get val - let val = match *r { - // the var's value is a literal - // if the var gets used as a var, yield to stack - // otherwise just return the literal - Expr::Literal(lit) => { - self.translate(Expr::Literal(lit), true, gets_referenced) - } - - // value is an expr - // compute it and yield to stack if it gets used - e => self.translate(e, true, gets_referenced), - }; - - // handle value - let val = match val { - // apply appropriate drop rule - Val::Stack(sv, _) => Val::Stack(sv, gets_referenced), - // non-literal type - val if matches!(val, Val::Func(_, _, _)) => self.gen_copy(val), - // okay as-is - val => val, - }; - - // check if var already exists - if let Some(sv) = self.find(&id) { - // yes, move it there - self.insts.push(Inst::Move(sv.clone(), val)); - self.local.pop_top(); - // find out if it should be popped - let is_shared = matches!(sv, Stkval::Shared(_, _)); - let should_pop = gets_referenced && !is_shared; - // return new stackval - return Val::Stack(sv, should_pop); - } else if matches!(val, Val::Stack(_, _)) { - // no, keep track of new stackval - self.local.swap_top(FSValue::Var(id)); - - // also move to shared if we're supposed to do that :) - if ref_stat.meta.is_shared.get() - && let Val::Stack(sv, _) = val - { - // move fs value - let v = self.local.pop_top(); - self.shared.push(v); - // copy to shared w pop - self.insts.push(Inst::Copy(true, Val::Stack(sv, true))); - return Val::Stack(self.top_shared(), false); - } - } - val - } - } - - /* math */ - Expr::Add(l, r) => self.gen_binop(*l, *r, Inst::Add, do_compute), - Expr::Multiply(l, r) => self.gen_binop(*l, *r, Inst::Mul, do_compute), - Expr::Divide(l, r) => self.gen_binop(*l, *r, Inst::Div, do_compute), - Expr::Modulo(l, r) => self.gen_binop(*l, *r, Inst::Mod, do_compute), - Expr::Exponent(l, r) => self.gen_binop(*l, *r, Inst::Pow, do_compute), - - /* math assignments */ - Expr::AddAssign(l, r) => self.translate( - Expr::Assign(l.clone(), Box::new(Expr::Add(l, r))), - do_compute, - do_yield, - ), - Expr::SubtractAssign(l, r) => self.translate( - Expr::Assign(l.clone(), Box::new(Expr::Subtract(l, r))), - do_compute, - do_yield, - ), - Expr::MultiplyAssign(l, r) => self.translate( - Expr::Assign(l.clone(), Box::new(Expr::Multiply(l, r))), - do_compute, - do_yield, - ), - Expr::DivideAssign(l, r) => self.translate( - Expr::Assign(l.clone(), Box::new(Expr::Divide(l, r))), - do_compute, - do_yield, - ), - - /* math substitutions */ - Expr::Negate(r) if do_compute => { - // negate - match *r { - // statically - Expr::Literal(Literal::Integer(i)) => Val::Int64(-i), - Expr::Literal(Literal::Float(f)) => Val::Float64(-f), - - // at runtime - e => { - let e = Box::new(e); - let minus_one = Box::new(Expr::Literal(Literal::Integer(-1))); - self.translate(Expr::Multiply(e, minus_one), do_compute, do_yield) - } - } - } - Expr::Negate(_) => Val::Nil, - Expr::Subtract(l, r) => self.translate( - Expr::Add(l, Box::new(Expr::Negate(r))), - do_compute, - do_yield, - ), - - /* logic */ - Expr::And(l, r) => self.gen_binop(*l, *r, Inst::And, do_compute), - Expr::Or(l, r) => self.gen_binop(*l, *r, Inst::Or, do_compute), - Expr::EqualTo(l, r) => self.gen_binop(*l, *r, Inst::Eq, do_compute), - Expr::GreaterThan(l, r) => self.gen_binop(*l, *r, Inst::Gt, do_compute), - Expr::GreaterThanOrEqualTo(l, r) => self.gen_binop(*l, *r, Inst::GtEq, do_compute), - Expr::Not(r) => self.gen_unop(*r, Inst::Not, do_compute), - - /* logic substitutions */ - Expr::NotEqualTo(l, r) => { - self.translate(Expr::Not(Box::new(Expr::EqualTo(l, r))), do_compute, false) - } - Expr::LessThan(l, r) => self.translate(Expr::GreaterThan(r, l), do_compute, false), - Expr::LessThanOrEqualTo(l, r) => { - self.translate(Expr::GreaterThanOrEqualTo(r, l), do_compute, false) - } - } - } -} - -pub fn analysis_demo(e: &mut Expr) { - // analysis pass - let fs = FuncStat::default(); - let mut scope = Scope::with_parent(None); - analyze(&fs, &mut scope, e, false); -} -pub fn translation_demo(e: Expr) -> Vec { - // translation pass - let mut fb = FuncBuild::new_root(); - fb.translate(e, false, false); - fb.insts -} diff --git a/src/compiler/stack.rs b/src/compiler/stack.rs deleted file mode 100644 index 799df25..0000000 --- a/src/compiler/stack.rs +++ /dev/null @@ -1,58 +0,0 @@ -pub trait Stack<'a> -where - Self: 'a, -{ - type Value; - type Input; - type Output; - - fn with_parent(parent: Option<&'a Self>) -> Self; - - fn parent(&self) -> Option<&'a Self>; - fn values(&self) -> &Vec; - fn values_mut(&mut self) -> &mut Vec; - - fn find_map(index: usize, value: &Self::Value, input: &Self::Input) -> Option; - - fn push(&mut self, value: Self::Value) { - self.values_mut().push(value); - } - fn pop(&mut self, index: usize) { - self.values_mut().remove(index); - } - fn top_index(&self) -> usize { - self.values().len() - 1 - } - fn swap_top(&mut self, new: Self::Value) { - *self.values_mut().last_mut().unwrap() = new; - } - fn pop_top(&mut self) -> Self::Value { - self.values_mut().pop().unwrap() - } - fn pop_top_n(&mut self, n: usize) -> Vec { - let start = self.values().len() - n; - self.values_mut().split_off(start) - } - - fn find(&self, input: &Self::Input) -> Option<(Self::Output, u16)> { - let mut cur = Some(self); - let mut up_levels = 0; - - while let Some(stack) = cur { - let Some(output) = stack - .values() - .iter() - .enumerate() - .rev() - .find_map(|(index, value)| Self::find_map(index, value, input)) - else { - cur = stack.parent(); - up_levels += 1; - continue; - }; - return Some((output, up_levels)); - } - - None - } -} diff --git a/src/lexer.rs b/src/lexer.rs index ae1cabf..5e35bd1 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -4,7 +4,7 @@ use std::{ num::{ParseFloatError, ParseIntError}, }; -use crate::{compiler::RefStat, kinds}; +use crate::kinds; #[derive(Debug, PartialEq, Eq, Clone)] pub struct Ident(String); @@ -21,7 +21,7 @@ pub enum Literal { Float(f64), Boolean(bool), Nil, - Ident(Ident, Option), + Ident(Ident), } impl fmt::Display for Literal { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -30,19 +30,7 @@ impl fmt::Display for Literal { Literal::Integer(n) => write!(f, "{n}"), Literal::Float(n) => write!(f, "{n}"), Literal::Boolean(b) => write!(f, "{b}"), - Literal::Ident(id, ref_stat) => write!( - f, - "{id}{}", - ref_stat - .as_ref() - .map(|rs| format!( - "@{}{}/{}", - rs.meta.is_shared.get().then_some("sh+").unwrap_or(""), - rs.now, - rs.meta.total.get() - )) - .unwrap_or_default() - ), + Literal::Ident(id) => write!(f, "{id}"), Literal::Nil => write!(f, "nil"), } } @@ -86,6 +74,7 @@ kinds!( #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum Precedence { Min, + Return, Assign, WithAssign, Logical, @@ -104,9 +93,8 @@ pub enum Associativity { impl Token { pub fn prefix_precedence(&self) -> Option { Some(match self { - Token::Return | Token::If | Token::Func | Token::Minus | Token::Not => { - Precedence::Prefix - } + Token::Return => Precedence::Return, + Token::If | Token::Func | Token::Minus | Token::Not => Precedence::Prefix, _ => return None, }) } @@ -162,18 +150,14 @@ impl From for LexError { } } -pub type Result = std::result::Result; +type Result = std::result::Result; pub struct Lexer where I: Iterator, { chars: Peekable, -} - -#[allow(clippy::unnecessary_wraps)] -fn t(tk: Token) -> Option> { - Some(Ok(tk)) + offset: usize, } impl Lexer @@ -181,8 +165,10 @@ where I: Iterator, { pub fn new(chars: I) -> Self { - let chars = chars.peekable(); - Self { chars } + Self { + chars: chars.peekable(), + offset: 0, + } } fn peek(&mut self) -> Option { @@ -190,7 +176,7 @@ where } fn next(&mut self) -> Option { - self.chars.next() + self.chars.next().inspect(|_| self.offset += 1) } fn next_unwrap(&mut self) -> char { match self.next() { @@ -243,16 +229,17 @@ where "true" => Token::Literal(Literal::Boolean(true)), "false" => Token::Literal(Literal::Boolean(false)), "nil" => Token::Literal(Literal::Nil), - _ => Token::Literal(Literal::Ident(Ident(word), Option::default())), + _ => Token::Literal(Literal::Ident(Ident(word))), } } - fn lex_number(&mut self) -> Result { + fn lex_number(&mut self, is_neg: bool) -> Result { let mut n_str = String::new(); - // we don't lex negatives. the impl for that is - // a negation of a positive number at runtime. - // maybe that's kind of stupid though, lol + if is_neg { + n_str.push('-'); + } + let mut is_float = false; while let Some('0'..='9' | '.') = self.peek() { if self.peek() == Some('.') { @@ -296,6 +283,11 @@ where } fn lex(&mut self) -> Option> { + #[allow(clippy::unnecessary_wraps)] + fn t(tk: Token) -> Option> { + Some(Ok(tk)) + } + loop { break match self.lex_whitespace()? { // { and } start/end of code block @@ -315,8 +307,10 @@ where // - subtract // or -= sub eq + // or 0-9 number '-' => match self.eat_peek() { Some('=') => self.eat_to(Token::MinusEquals), + Some('0'..='9' | '.') => Some(self.lex_number(true)), _ => t(Token::Minus), }, @@ -389,7 +383,7 @@ where 'a'..='z' | 'A'..='Z' | '_' => Some(Ok(self.lex_word())), // 0-9 integer - '0'..='9' | '.' => Some(self.lex_number()), + '0'..='9' | '.' => Some(self.lex_number(false)), // " strings '"' => Some(self.lex_string()), diff --git a/src/main.rs b/src/main.rs index 6009c3d..0fbe4c3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ mod parser; mod vm; fn main() { - // lexer (iterator) + // lexer let script = std::fs::read_to_string("./start.lf").unwrap(); let lexer = Lexer::new(script.chars()); let mut parser = Parser::new(lexer.map(Result::unwrap)); @@ -18,26 +18,5 @@ fn main() { let start = Instant::now(); let block = parser.parse().unwrap(); println!("Parse took {:?}", start.elapsed()); - let mut e = parser::Expr::Block(block); - parser::util::display(&e); - - // compiler - analysis - let start = Instant::now(); - compiler::analysis_demo(&mut e); - println!("Analysis took {:?}", start.elapsed()); - parser::util::display(&e); - - // compiler - translation - let start = Instant::now(); - let insts = compiler::translation_demo(e); - println!("Translation took {:?}", start.elapsed()); - for i in &insts { - println!("=> {i:?}"); - } - - // vm - println!("Starting VM!!!!!!!!!!!!!!!!"); - let start = Instant::now(); - let out = vm::run(&insts); - println!("!! Got result (in {:?}): {out:?}", start.elapsed()); + parser::util::display(&block); } diff --git a/src/parser.rs b/src/parser.rs index a0542f4..bf74632 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,7 +1,6 @@ use std::{fmt, iter::Peekable}; use crate::{ - compiler::FuncStat, kind::Kind, lexer::{Associativity, LexError, Literal, Precedence, Token, TokenKind}, }; @@ -14,8 +13,8 @@ pub enum Expr { Assign(Box, Box), Literal(Literal), // Non-literal datatypes - Block(Block), - Func(Vec, Box, Option), + Block(Vec), + Func(Vec, Box), // Control flow If(Box, Box, Option>), Return(Box), @@ -47,11 +46,6 @@ pub enum Expr { DivideAssign(Box, Box), } -#[derive(Debug, Default, Clone)] -pub struct Block { - pub exprs: Vec, -} - #[derive(Debug)] pub enum ParseError { UnexpectedToken(Token), @@ -101,6 +95,15 @@ where self.tokens.next().ok_or(ParseError::UnexpectedEnd) } + fn expect_peek(&mut self, kind: TokenKind) -> Result<()> { + let t = self.try_peek()?; + + if t.kind() != kind { + return Err(ParseError::UnexpectedToken(self.next_unwrap())); + } + + Ok(()) + } fn expect_next(&mut self, kind: TokenKind) -> Result<()> { let t = self.try_next()?; @@ -110,6 +113,7 @@ where Ok(()) } + fn is_next(&mut self, kind: Option) -> bool { match self.try_peek() { Ok(t) if Some(t.kind()) == kind => true, @@ -138,7 +142,7 @@ where let exprs = self.parse_until(Some(TokenKind::CurlyClose))?; // skip curly brace self.eat(); - Box::new(Expr::Block(Block { exprs })) + Box::new(Expr::Block(exprs)) } // unary ops!! (prefix) @@ -155,7 +159,7 @@ where // parse body let body = self.parse_expr(prec, in_group)?; // pack - Box::new(Expr::Func(args, body, None)) + Box::new(Expr::Func(args, body)) } // parse if Token::If => { @@ -193,6 +197,7 @@ where }; loop { + // look for op, end, or special let op = match self.try_peek() { // end (group) Ok(Token::ParenClose) if in_group => break, @@ -223,6 +228,7 @@ where Ok(_) => break, }; + // get op precedence let (prec, assoc) = op.infix_precedence().unwrap(); // break if this op is meant for previous recursion @@ -296,10 +302,9 @@ where let mut exprs = Vec::new(); while !self.is_next(until) { - // skip delimiter - if self.is_next(Some(delim)) { + // skip delimiter (if it's not the first iteration) + if !exprs.is_empty() && self.is_next(Some(delim)) { self.eat(); - continue; } // try to parse expr @@ -311,13 +316,12 @@ where } // check for delim - self.expect_next(delim)?; + self.expect_peek(delim)?; } Ok(exprs) } - pub fn parse(&mut self) -> Result { - let exprs = self.parse_until(None)?; - Ok(Block { exprs }) + pub fn parse(&mut self) -> Result { + Ok(Expr::Block(self.parse_until(None)?)) } } diff --git a/src/parser/util.rs b/src/parser/util.rs index c27ecc4..4999a86 100644 --- a/src/parser/util.rs +++ b/src/parser/util.rs @@ -47,8 +47,8 @@ fn fmt_expr(e: &Expr, depth: usize) -> String { Expr::Return(l) => format!("return ({})", fmt_expr(l, depth)), Expr::Block(b) => { let mut result = String::new(); - let len = b.exprs.len(); - for (i, expr) in b.exprs.iter().enumerate() { + let len = b.len(); + for (i, expr) in b.iter().enumerate() { result.push_str(&" ".repeat(depth)); result.push_str(&fmt_expr(expr, depth + 1)); if depth != 0 || i + 1 != len { @@ -60,20 +60,12 @@ fn fmt_expr(e: &Expr, depth: usize) -> String { } result } - Expr::Func(a, e, func_stat) => format!( - "(func({}){} ({}))", + Expr::Func(a, e) => format!( + "(func({}) ({}))", a.iter() .map(|e| fmt_expr(e, depth)) .collect::>() .join(", "), - func_stat - .as_ref() - .map(|fm| fm - .is_unreturnable - .get() - .then_some("@UNRET") - .unwrap_or("@OK")) - .unwrap_or_default(), fmt_expr(e, depth) ), Expr::Negate(l) => format!("(-{})", fmt_expr(l, depth)), diff --git a/src/vm.rs b/src/vm.rs index 172c7c7..d3f5a12 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,153 +1 @@ -use std::cell::RefCell; -use crate::compiler::{Inst, Stkval, Val}; - -#[derive(Default)] -struct FuncVm<'a> { - depth: usize, - parent_vm: Option<&'a FuncVm<'a>>, - shared: RefCell>, - locals: Vec, -} -impl<'a> FuncVm<'a> { - fn with(parent_vm: &'a FuncVm<'a>, locals: Vec) -> Self { - Self { - parent_vm: Some(parent_vm), - depth: parent_vm.depth + 1, - shared: RefCell::default(), - locals, - } - } - - fn get(&mut self, v: &Val) -> Val { - use {Stkval::*, Val::*}; - - match v { - Stack(Local(o), true) => self.locals.remove(*o as usize), - Stack(Local(o), false) => self.locals[*o as usize].clone(), - - Stack(Shared(l, o), false) => { - let mut vm = &*self; - for _ in 0..*l { - vm = vm.parent_vm.as_ref().unwrap(); - } - vm.shared.borrow_mut()[*o as usize].clone() - } - Stack(Shared(_, _), true) => panic!("not allowed"), - - v => v.clone(), - } - } - - fn eval_all(&mut self, insts: &[Inst]) -> Val { - use {Inst::*, Val::*}; - - let mut pc = 0; - while pc < insts.len() { - let inst = &insts[pc]; - - match inst { - /* rhs */ - Not(a) | Return(a) => { - let r = match (inst, self.get(a)) { - (Not(_), Bool(a)) => Bool(!a), - (Return(_), Func(true, _, _)) => panic!("func is unreturnable"), - (Return(_), a) => return a, - _ => unimplemented!(), - }; - self.locals.push(r); - } - /* s rhs */ - Copy(s, a) => { - let a = self.get(a); - if !*s { - self.locals.push(a); - } else { - self.shared.borrow_mut().push(a); - } - } - /* k rhs */ - Call(k, n, a) => { - // check validity - let a = self.get(a); - let Func(_, arity, insts) = a else { - panic!("called non-function {a:?}") - }; - - // collect args from stack :) - let args_start = self.locals.len() - *n as usize; - let args = self.locals.split_off(args_start); - - // make sure its the right amount - if *n != arity { - panic!("wrong # args") - } - - // exec - let mut vm = FuncVm::with(self, args); - let r = vm.eval_all(&insts); - // push value if were supposed to - if *k { - self.locals.push(r); - } - } - - /* sv rhs */ - Move(sv, a) => { - let a = self.get(a); - match sv { - Stkval::Local(o) => { - self.locals[*o as usize] = a; - } - Stkval::Shared(l, o) => { - let mut vm = &*self; - for _ in 0..*l { - vm = vm.parent_vm.unwrap(); - } - vm.shared.borrow_mut()[*o as usize] = a; - } - } - } - - /* lhs rhs */ - Eq(a, b) - | Gt(a, b) - | GtEq(a, b) - | Add(a, b) - | Mul(a, b) - | Div(a, b) - | Mod(a, b) - | Pow(a, b) - | And(a, b) - | Or(a, b) => { - let r = match (inst, self.get(a), self.get(b)) { - (Add(_, _), Int64(a), Int64(b)) => Int64(a + b), - (Mul(_, _), Int64(a), Int64(b)) => Int64(a * b), - (Div(_, _), Int64(a), Int64(b)) => Int64(a / b), - (Mod(_, _), Int64(a), Int64(b)) => Int64(a % b), - (Pow(_, _), Int64(a), Int64(b)) => Int64(a.pow(b.try_into().unwrap())), - (And(_, _), Bool(a), Bool(b)) => Bool(a && b), - (Or(_, _), Bool(a), Bool(b)) => Bool(a || b), - (Eq(_, _), a, b) => Bool(a == b), - (Gt(_, _), Int64(a), Int64(b)) => Bool(a > b), - (GtEq(_, _), Int64(a), Int64(b)) => Bool(a >= b), - - x => unimplemented!("{x:?}"), - }; - self.locals.push(r); - } - - _ => unimplemented!(), - } - - pc += 1; - } - - Nil - } -} - -pub fn run(insts: &[Inst]) -> Val { - let mut vm = FuncVm::default(); - vm.eval_all(insts) -}