use std::rc::Rc; use std::str::FromStr; use crate::tokenizing::TokenKind; use crate::builtin::Builtin; #[derive(Debug, PartialEq, Clone)] pub struct PrefixOp { sigil: Rc, pub builtin: Option, } impl PrefixOp { #[allow(dead_code)] pub fn sigil(&self) -> &Rc { &self.sigil } pub fn is_prefix(op: &str) -> bool { match op { "+" => true, "-" => true, "!" => true, _ => false } } } impl FromStr for PrefixOp { type Err = (); fn from_str(s: &str) -> Result { use Builtin::*; let builtin = match s { "+" => Ok(Increment), "-" => Ok(Negate), "!" => Ok(BooleanNot), _ => Err(()) }; builtin.map(|builtin| PrefixOp { sigil: Rc::new(s.to_string()), builtin: Some(builtin) }) } } #[derive(Debug, PartialEq, Clone)] pub struct BinOp { sigil: Rc, pub builtin: Option, } impl BinOp { pub fn from_sigil(sigil: &str) -> BinOp { let builtin = Builtin::from_str(sigil).ok(); BinOp { sigil: Rc::new(sigil.to_string()), builtin } } pub fn sigil(&self) -> &Rc { &self.sigil } pub fn from_sigil_token(tok: &TokenKind) -> Option { let s = token_kind_to_sigil(tok)?; Some(BinOp::from_sigil(s)) } pub fn min_precedence() -> i32 { i32::min_value() } pub fn get_precedence_from_token(op_tok: &TokenKind) -> Option { let s = token_kind_to_sigil(op_tok)?; Some(binop_precedences(s)) } } fn token_kind_to_sigil<'a>(tok: &'a TokenKind) -> Option<&'a str> { use self::TokenKind::*; Some(match tok { Operator(op) => op.as_str(), Period => ".", Pipe => "|", Slash => "/", LAngleBracket => "<", RAngleBracket => ">", Equals => "=", _ => return None }) } fn binop_precedences(s: &str) -> i32 { let default = 10_000_000; match s { "+" => 10, "-" => 10, "*" => 20, "/" => 20, "%" => 20, "++" => 30, "^" => 30, "&" => 20, "|" => 20, ">" => 20, ">=" => 20, "<" => 20, "<=" => 20, "==" => 40, "=" => 10, "<=>" => 30, _ => default, } }