smol lang
Diffstat (limited to 'src/parser/expression.rs')
| -rw-r--r-- | src/parser/expression.rs | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/src/parser/expression.rs b/src/parser/expression.rs new file mode 100644 index 0000000..3973f3c --- /dev/null +++ b/src/parser/expression.rs @@ -0,0 +1,195 @@ +use super::*; +use chumsky::prelude::*; +use match_deref::match_deref; +use std::collections::{hash_map::Entry, HashMap}; + +#[derive(Eq, Clone, Copy, Debug)] +pub struct Proto<'s> { + name: &'s str, + prec: Precedence, +} + +impl<'s> Proto<'s> { + pub fn new(name: &'s str) -> Proto<'s> { + Proto { + name, + prec: Precedence::Ambigous, + } + } + + pub fn then(self, prec: Precedence) -> Proto<'s> { + Self { prec, ..self } + } +} + +impl std::hash::Hash for Proto<'_> { + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + self.name.hash(state); + } +} + +impl PartialEq for Proto<'_> { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +enum Precedence { + Ambigous, + Prefix(u16), + Postfix(u16), + Infix(u16), +} + +#[derive(Debug, Clone)] +pub struct Context<'s> { + precedence: HashMap<Proto<'s>, Vec<&'s str>>, +} + +#[derive(thiserror::Error, Debug, Clone)] +pub enum Err<'s> { + #[error("unable to find function {0}. are you sure it exists?")] + CannotFind(Spanned<&'s str>), + #[error("problem.")] + Mismatch(Spanned<(Precedence, Fix)>), + #[error("{0} != 2")] + InfixWithNot2(u8), + #[error("you cant bind higher than top")] + TtTop(Span), + #[error("you cant bind lower than bottom")] + LtBot(Span), +} + +/// precedence of "function" defined as (infix) tt bottom (postfix) tt bottom (prefix) lt top +impl<'s> Context<'s> { + fn add(&mut self, dat: FixMeta, proto: Proto<'s>) -> Result<(), Err> { + use Fix::*; + use Precedence::*; + if dat.fix() == In && proto.argc != 2 { + return Err(Err::InfixWithNot2(*Spanned::from((proto.argc, dat.span())))); + } + if let Some(n) = match_deref! { + match &dat { + FixMeta::Data(Deref @ FixMetaData { looser_than: Some(Deref @ &"top"), .. }) =>Some( 0xfffd), + FixMeta::Default(Deref @ Pre) =>Some( 0xfffe), + _ => None, + } + } { + let value = match dat.fix() { + In => Infix(n), + Pre => Prefix(n), + Post => Postfix(n), + }; + match self.precedence.entry(proto) { + Entry::Occupied(x) => { + x.into_mut().push(proto.then(value)); + } + Entry::Vacant(x) => { + x.insert(vec![]); + } + }; + return Ok(()); + } + if let Some(x) = tt + && *x == "top" + { + return Err(Err::TtTop(s)); + } // TODO graphs + if let Some(lt) = lt { + let &position = self + .precedence + .get(&Proto { + name: &*lt, + argc: 0, + }) + .ok_or(Err::CannotFind(lt))?; + let value = match (position, fix) { + (Infix(x), In) => Infix(x - 1), + (Prefix(x), Pre) => Prefix(x - 1), + (Postfix(x), Post) => Postfix(x - 1), + (x, y) => return Err(Err::Mismatch(lt.copys((x, y)))), + }; + self.precedence.insert(proto, value); + } + if let Some(lt) = tt { + let &position = self + .precedence + .get(&Proto { + name: &*lt, + argc: 0, + }) + .ok_or(Err::CannotFind(lt))?; + let value = match (position, fix) { + (Infix(x), In) => Infix(x - 1), + (Prefix(x), Pre) => Prefix(x - 1), + (Postfix(x), Post) => Postfix(x - 1), + (x, y) => return Err(Err::Mismatch(lt.copys((x, y)))), + }; + self.precedence.insert(proto, value); + } + if let Some(gt) = tt { + let &position = self + .precedence + .get(&Proto { + name: &*gt, + argc: 0, + }) + .ok_or(Err::CannotFind(gt))?; + let value = match (position, fix) { + (Infix(x), In) => Infix(x + 1), + (Prefix(x), Pre) => Prefix(x + 1), + (Postfix(x), Post) => Postfix(x + 1), + (x, y) => return Err(Err::Mismatch(gt.copys((x, y)))), + }; + self.precedence.insert(proto, value); + } + Ok(()) + } +} + +#[test] +fn hmm() { + let mut hm = std::collections::HashMap::new(); + hm.insert(Proto { name: "*", argc: 2 }, 32768 - 1); + hm.insert(Proto { name: "/", argc: 2 }, 32768 - 1); + hm.insert(Proto { name: "+", argc: 2 }, 32768 - 2); + hm.insert(Proto { name: "-", argc: 2 }, 32768 - 2); + let mut c = Context { + precedence: HashMap::default(), + }; + c.add( + Proto { name: "*", argc: 2 }, + None, + Some(Spanned::dummy("top")), + Fix::In, + (0..0).into(), + ) + .unwrap(); + c.add( + Proto { name: "/", argc: 2 }, + None, + Some(Spanned::dummy("top")), + Fix::In, + (0..0).into(), + ) + .unwrap(); + println!("{c:#?}"); + c.add( + Proto { name: "+", argc: 2 }, + None, + Some(Spanned::dummy("*")), + Fix::In, + (0..0).into(), + ) + .unwrap(); + c.add( + Proto { name: "-", argc: 2 }, + None, + Some(Spanned::dummy("*")), + Fix::In, + (0..0).into(), + ) + .unwrap(); + panic!("{c:#?}"); +} |