diff --git a/operator-precedence.txt b/operator-precedence.txt new file mode 100644 index 0000000..6213272 --- /dev/null +++ b/operator-precedence.txt @@ -0,0 +1,17 @@ +L2R: , +R2L: = += -= *= **= /= %= &= |= ^= <<= >>= +L2R: || +L2R: && +L2R: == != < <= > >= +L2R: | +L2R: ^ +L2R: & +L2R: << >> +L2R: + - (binary minus) +L2R: * / % +L2R: ** +R2L: ! - (unary minus) +L2R: () [] . + +line numbers are precedence values +higher values mean higher precedence diff --git a/src/ast/tree.rs b/src/ast/tree.rs index 89fda8a..ee4972d 100644 --- a/src/ast/tree.rs +++ b/src/ast/tree.rs @@ -41,11 +41,87 @@ pub enum Node { #[derive(Debug)] pub enum Operator { Eq, + EqEq, + Bang, + BangEq, + Gt, + GtGt, + GtEq, + GtGtEq, + Lt, + LtLt, + LtEq, + LtLtEq, Plus, + PlusEq, Minus, + MinusEq, Asterisk, + AsteriskAsterisk, + AsteriskEq, + AsteriskAsteriskEq, Slash, + SlashEq, Percent, + PercentEq, + Pipe, + PipePipe, + PipeEq, + Amp, + AmpAmp, + AmpEq, + Caret, + CaretEq, +} + +impl Operator { + pub const fn precedence(&self) -> u8 { + match self { + Operator::Eq => 2, + Operator::PlusEq => 2, + Operator::MinusEq => 2, + Operator::AsteriskEq => 2, + Operator::AsteriskAsteriskEq => 2, + Operator::SlashEq => 2, + Operator::PercentEq => 2, + Operator::AmpEq => 2, + Operator::PipeEq => 2, + Operator::CaretEq => 2, + Operator::GtGtEq => 2, + Operator::LtLtEq => 2, + + Operator::PipePipe => 3, + + Operator::AmpAmp => 4, + + Operator::EqEq => 5, + Operator::BangEq => 5, + Operator::Lt => 5, + Operator::LtEq => 5, + Operator::Gt => 5, + Operator::GtEq => 5, + + Operator::Pipe => 6, + + Operator::Caret => 7, + + Operator::Amp => 8, + + Operator::GtGt => 9, + Operator::LtLt => 9, + + Operator::Plus => 10, + Operator::Minus => 10, + + Operator::Asterisk => 11, + Operator::Slash => 11, + Operator::Percent => 11, + + Operator::AsteriskAsterisk => 12, + + Operator::Bang => 13, + } + } } impl Node { @@ -92,7 +168,7 @@ impl Node { impl fmt::Display for Node { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let mut tmp: String; + let tmp: String; write!( f, "{}", @@ -121,11 +197,37 @@ impl Operator { pub fn from_token(token: &Token) -> Result { match token.kind { token::Kind::Eq => Ok(Operator::Eq), + token::Kind::EqEq => Ok(Operator::EqEq), + token::Kind::BangEq => Ok(Operator::BangEq), + token::Kind::Bang => Ok(Operator::Bang), + token::Kind::Gt => Ok(Operator::Gt), + token::Kind::GtGt => Ok(Operator::GtGt), + token::Kind::GtEq => Ok(Operator::GtEq), + token::Kind::GtGtEq => Ok(Operator::GtGtEq), + token::Kind::Lt => Ok(Operator::Lt), + token::Kind::LtLt => Ok(Operator::LtLt), + token::Kind::LtEq => Ok(Operator::LtEq), + token::Kind::LtLtEq => Ok(Operator::LtLtEq), token::Kind::Plus => Ok(Operator::Plus), + token::Kind::PlusEq => Ok(Operator::PlusEq), token::Kind::Minus => Ok(Operator::Minus), + token::Kind::MinusEq => Ok(Operator::MinusEq), token::Kind::Asterisk => Ok(Operator::Asterisk), + token::Kind::AsteriskAsterisk => Ok(Operator::AsteriskAsterisk), + token::Kind::AsteriskEq => Ok(Operator::AsteriskEq), + token::Kind::AsteriskAsteriskEq => Ok(Operator::AsteriskAsteriskEq), token::Kind::Slash => Ok(Operator::Slash), + token::Kind::SlashEq => Ok(Operator::SlashEq), token::Kind::Percent => Ok(Operator::Percent), + token::Kind::PercentEq => Ok(Operator::PercentEq), + token::Kind::Pipe => Ok(Operator::Pipe), + token::Kind::PipePipe => Ok(Operator::PipePipe), + token::Kind::PipeEq => Ok(Operator::PipeEq), + token::Kind::Amp => Ok(Operator::Amp), + token::Kind::AmpAmp => Ok(Operator::AmpAmp), + token::Kind::AmpEq => Ok(Operator::AmpEq), + token::Kind::Caret => Ok(Operator::Caret), + token::Kind::CaretEq => Ok(Operator::CaretEq), _ => Err(Error::syntax_error( token.pos.clone(), format!("\"{}\" is not an operator", token.raw), @@ -136,11 +238,37 @@ impl Operator { pub fn raw(&self) -> &'static str { match self { Operator::Eq => "=", + Operator::EqEq => "==", + Operator::BangEq => "!=", + Operator::Gt => ">", + Operator::GtGt => ">>", + Operator::GtEq => ">=", + Operator::GtGtEq => ">>=", + Operator::Lt => "<", + Operator::LtLt => "<<", + Operator::LtEq => "<=", + Operator::LtLtEq => "<<=", Operator::Plus => "+", + Operator::PlusEq => "+=", Operator::Minus => "-", + Operator::MinusEq => "-=", Operator::Asterisk => "*", + Operator::AsteriskAsterisk => "**", + Operator::AsteriskEq => "*=", + Operator::AsteriskAsteriskEq => "**=", Operator::Slash => "/", + Operator::SlashEq => "/=", Operator::Percent => "%", + Operator::PercentEq => "%=", + Operator::Bang => "!", + Operator::Pipe => "|", + Operator::PipePipe => "||", + Operator::PipeEq => "|=", + Operator::Amp => "&", + Operator::AmpAmp => "&&", + Operator::AmpEq => "&=", + Operator::Caret => "^", + Operator::CaretEq => "^=", } } } diff --git a/src/lex/mod.rs b/src/lex/mod.rs index d8c1bfa..054d3e1 100644 --- a/src/lex/mod.rs +++ b/src/lex/mod.rs @@ -60,12 +60,43 @@ impl Iterator for Lexer { '}' => self.token_ok(token::Kind::CBrace), '[' => self.token_ok(token::Kind::OBracket), ']' => self.token_ok(token::Kind::CBracket), + '(' => self.token_ok(token::Kind::OParen), + ')' => self.token_ok(token::Kind::CParen), + '=' if self.skip_if_match("=") => self.token_ok(token::Kind::EqEq), '=' => self.token_ok(token::Kind::Eq), + '!' if self.skip_if_match("=") => self.token_ok(token::Kind::BangEq), + '!' => self.token_ok(token::Kind::Bang), + '>' if self.skip_if_match(">=") => self.token_ok(token::Kind::GtGtEq), + '>' if self.skip_if_match("=") => self.token_ok(token::Kind::GtEq), + '>' if self.skip_if_match("<") => self.token_ok(token::Kind::GtGt), + '>' => self.token_ok(token::Kind::Gt), + '<' if self.skip_if_match("<=") => self.token_ok(token::Kind::LtLtEq), + '<' if self.skip_if_match("=") => self.token_ok(token::Kind::LtEq), + '<' if self.skip_if_match("<") => self.token_ok(token::Kind::LtLt), + '<' => self.token_ok(token::Kind::Lt), + '|' if self.skip_if_match("|=") => self.token_ok(token::Kind::PipePipeEq), + '|' if self.skip_if_match("|") => self.token_ok(token::Kind::PipePipe), + '|' if self.skip_if_match("=") => self.token_ok(token::Kind::PipeEq), + '|' => self.token_ok(token::Kind::Pipe), + '&' if self.skip_if_match("&=") => self.token_ok(token::Kind::AmpAmpEq), + '&' if self.skip_if_match("&") => self.token_ok(token::Kind::AmpAmp), + '&' if self.skip_if_match("=") => self.token_ok(token::Kind::AmpEq), + '&' => self.token_ok(token::Kind::Amp), + '^' if self.skip_if_match("=") => self.token_ok(token::Kind::CaretEq), + '^' => self.token_ok(token::Kind::Caret), + + '+' if self.skip_if_match("=") => self.token_ok(token::Kind::PlusEq), '+' => self.token_ok(token::Kind::Plus), + '-' if self.skip_if_match("=") => self.token_ok(token::Kind::MinusEq), '-' => self.token_ok(token::Kind::Minus), + '*' if self.skip_if_match("*=") => self.token_ok(token::Kind::AsteriskAsteriskEq), + '*' if self.skip_if_match("*") => self.token_ok(token::Kind::AsteriskAsterisk), + '*' if self.skip_if_match("=") => self.token_ok(token::Kind::AsteriskEq), '*' => self.token_ok(token::Kind::Asterisk), + '/' if self.skip_if_match("=") => self.token_ok(token::Kind::SlashEq), '/' => self.token_ok(token::Kind::Slash), + '%' if self.skip_if_match("=") => self.token_ok(token::Kind::PercentEq), '%' => self.token_ok(token::Kind::Percent), '#' => { diff --git a/src/lex/token.rs b/src/lex/token.rs index 724fa45..37f7b27 100644 --- a/src/lex/token.rs +++ b/src/lex/token.rs @@ -29,15 +29,46 @@ pub enum Kind { CBrace, OBracket, CBracket, + OParen, + CParen, Comma, Semi, Eq, + EqEq, + Bang, + BangEq, + Gt, + GtGt, + GtEq, + GtGtEq, + Lt, + LtLt, + LtEq, + LtLtEq, + Amp, + AmpAmp, + AmpEq, + AmpAmpEq, + Pipe, + PipePipe, + PipeEq, + PipePipeEq, + Caret, + CaretEq, + Plus, + PlusEq, Minus, + MinusEq, Asterisk, + AsteriskAsterisk, + AsteriskEq, + AsteriskAsteriskEq, Slash, + SlashEq, Percent, + PercentEq, DependKeyword, IncludeKeyword, @@ -62,15 +93,46 @@ impl fmt::Display for Kind { Kind::CBrace => "cbrace", Kind::OBracket => "obracket", Kind::CBracket => "cbracket", + Kind::OParen => "oparen", + Kind::CParen => "cparen", Kind::Comma => "comma", Kind::Semi => "semi", Kind::Eq => "eq", + Kind::EqEq => "eqeq", + Kind::Bang => "bang", + Kind::BangEq => "bangeq", + Kind::Gt => "gt", + Kind::GtGt => "gtgt", + Kind::GtEq => "gteq", + Kind::GtGtEq => "gtgteq", + Kind::Lt => "lt", + Kind::LtLt => "ltlt", + Kind::LtEq => "lteq", + Kind::LtLtEq => "ltlteq", + Kind::Amp => "amp", + Kind::AmpAmp => "ampamp", + Kind::AmpEq => "ampeq", + Kind::AmpAmpEq => "ampampeq", + Kind::Pipe => "pipe", + Kind::PipePipe => "pipepipe", + Kind::PipeEq => "pipeeq", + Kind::PipePipeEq => "pipepipeeq", + Kind::Caret => "caret", + Kind::CaretEq => "careteq", + Kind::Plus => "plus", + Kind::PlusEq => "pluseq", Kind::Minus => "minus", + Kind::MinusEq => "minuseq", Kind::Asterisk => "asterisk", + Kind::AsteriskAsterisk => "asteriskasterisk", + Kind::AsteriskEq => "asteriskeq", + Kind::AsteriskAsteriskEq => "asteriskasteriskeq", Kind::Slash => "slash", + Kind::SlashEq => "slasheq", Kind::Percent => "percent", + Kind::PercentEq => "percenteq", Kind::DependKeyword => "keyword", Kind::IncludeKeyword => "keyword",