diff --git a/grammar.ebnf b/grammar.ebnf index 59bd24d..6607877 100644 --- a/grammar.ebnf +++ b/grammar.ebnf @@ -8,8 +8,8 @@ Identifier = IDENTIFIER ; (* # Expressions *) (* expression *) -Block = '{' Expr? '}' ; Expr = Ignore ; +Block = '{' Stmt* Expr? '}' ; Group = '(' Expr? ')' ; Primary = Item | Identifier | Literal | Block | Group | Branch ; @@ -30,6 +30,7 @@ IgnoreOp = ';' ; AssignOp = '=' | "+=" | "-=" | "*=" | "/=" | "&=" | "|=" | "^=" |"<<=" |">>=" ; CompareOp = '<' | "<=" | "==" | "!=" | ">=" | '>' ; +RangeOp = ".." | "..=" ; LogicOp = "&&" | "||" | "^^" ; BitwiseOp = '&' | '|' | '^' ; diff --git a/libconlang/src/ast.rs b/libconlang/src/ast.rs index 6a3a032..1b0fb71 100644 --- a/libconlang/src/ast.rs +++ b/libconlang/src/ast.rs @@ -609,7 +609,7 @@ pub mod expression { /// (`*`, `/`, `%`) Factor { Mul := Type::Star, - Div := Type::Div, + Div := Type::Slash, Rem := Type::Rem, } /// (`+`, `-`) @@ -619,8 +619,8 @@ pub mod expression { } /// (`<<`, `>>`) Shift { - Lsh := Type::Lsh, - Rsh := Type::Rsh, + Lsh := Type::LtLt, + Rsh := Type::GtGt, } /// (`&`, `|`, `^`) Bitwise { @@ -632,14 +632,14 @@ pub mod expression { Logic { LogAnd := Type::AmpAmp, LogOr := Type::BarBar, - LogXor := Type::CatEar, + LogXor := Type::XorXor, } /// (`<`, `<=`, `==`, `!=`, `>=`, `>`) Compare { Less := Type::Lt, LessEq := Type::LtEq, Equal := Type::EqEq, - NotEq := Type::NotEq, + NotEq := Type::BangEq, GreaterEq := Type::GtEq, Greater := Type::Gt, } @@ -647,15 +647,15 @@ pub mod expression { /// `&=`, `|=`, `^=`, `<<=`, `>>=`) Assign { Assign := Type::Eq, - AddAssign := Type::AddEq, - SubAssign := Type::SubEq, + AddAssign := Type::PlusEq, + SubAssign := Type::MinusEq, MulAssign := Type::StarEq, - DivAssign := Type::DivEq, - BitAndAssign := Type::AndEq, - BitOrAssign := Type::OrEq, + DivAssign := Type::SlashEq, + BitAndAssign := Type::AmpEq, + BitOrAssign := Type::BarEq, BitXorAssign := Type::XorEq, - ShlAssign := Type::LshEq, - ShrAssign := Type::RshEq, + ShlAssign := Type::LtLtEq, + ShrAssign := Type::GtGtEq, } /// (`;`) Ignore { diff --git a/libconlang/src/lexer.rs b/libconlang/src/lexer.rs index 0bdf198..a5f5002 100644 --- a/libconlang/src/lexer.rs +++ b/libconlang/src/lexer.rs @@ -104,53 +104,55 @@ impl<'t> Lexer<'t> { } /// Evaluates punctuation rules pub fn punctuation(&mut self) -> Option { - None.or_else(|| self.amp_amp()) - .or_else(|| self.bar_bar()) - .or_else(|| self.not_not()) - .or_else(|| self.cat_ear()) - .or_else(|| self.eq_eq()) - .or_else(|| self.gt_eq()) - .or_else(|| self.lt_eq()) - .or_else(|| self.not_eq()) - .or_else(|| self.lsh_eq()) - .or_else(|| self.rsh_eq()) - .or_else(|| self.star_eq()) - .or_else(|| self.div_eq()) - .or_else(|| self.rem_eq()) - .or_else(|| self.add_eq()) - .or_else(|| self.sub_eq()) - .or_else(|| self.and_eq()) - .or_else(|| self.or_eq()) - .or_else(|| self.xor_eq()) - .or_else(|| self.lsh()) - .or_else(|| self.rsh()) - .or_else(|| self.arrow()) - .or_else(|| self.fatarrow()) - .or_else(|| self.semi()) - .or_else(|| self.dot()) - .or_else(|| self.star()) - .or_else(|| self.div()) - .or_else(|| self.plus()) - .or_else(|| self.sub()) - .or_else(|| self.rem()) - .or_else(|| self.bang()) - .or_else(|| self.eq()) - .or_else(|| self.lt()) - .or_else(|| self.gt()) - .or_else(|| self.amp()) - .or_else(|| self.bar()) - .or_else(|| self.xor()) - .or_else(|| self.hash()) - .or_else(|| self.at()) - .or_else(|| self.colon()) - .or_else(|| self.backslash()) - .or_else(|| self.question()) - .or_else(|| self.comma()) - .or_else(|| self.tilde()) - .or_else(|| self.grave()) + None.or_else(|| self.amp_amp()) // && + .or_else(|| self.amp_eq()) // &= + .or_else(|| self.amp()) // & + .or_else(|| self.at()) // @ + .or_else(|| self.backslash()) // \ + .or_else(|| self.bang_bang()) // !! + .or_else(|| self.bang_eq()) // != + .or_else(|| self.bang()) // ! + .or_else(|| self.bar_bar()) // || + .or_else(|| self.bar_eq()) // |= + .or_else(|| self.bar()) // | + .or_else(|| self.colon()) // : + .or_else(|| self.comma()) // , + .or_else(|| self.dot_dot_eq()) // ..= + .or_else(|| self.dot_dot()) // .. + .or_else(|| self.dot()) // . + .or_else(|| self.eq_eq()) // == + .or_else(|| self.fatarrow()) // => + .or_else(|| self.eq()) // = + .or_else(|| self.grave()) // ` + .or_else(|| self.gt_eq()) // >= + .or_else(|| self.gt_gt_eq()) // >>= + .or_else(|| self.gt_gt()) // >> + .or_else(|| self.gt()) // > + .or_else(|| self.hash()) // # + .or_else(|| self.lt_eq()) // <= + .or_else(|| self.lt_lt_eq()) // <<= + .or_else(|| self.lt_lt()) // << + .or_else(|| self.lt()) // < + .or_else(|| self.minus_eq()) // -= + .or_else(|| self.arrow()) // -> + .or_else(|| self.minus()) // - + .or_else(|| self.plus_eq()) // += + .or_else(|| self.plus()) // + + .or_else(|| self.question()) // ? + .or_else(|| self.rem_eq()) // %= + .or_else(|| self.rem()) // % + .or_else(|| self.semi()) // ; + .or_else(|| self.slash_eq()) // /= + .or_else(|| self.slash()) // / + .or_else(|| self.star_eq()) // *= + .or_else(|| self.star()) // * + .or_else(|| self.tilde()) // ~ + .or_else(|| self.xor_eq()) // ^= + .or_else(|| self.xor_xor()) // ^^ + .or_else(|| self.xor()) // ^ } pub fn unary_op(&mut self) -> Option { - self.bang().or_else(|| self.sub()) + self.bang().or_else(|| self.minus()) } // functions for lexing individual tokens pub fn invalid(&mut self) -> Option { @@ -204,11 +206,11 @@ impl<'t> Lexer<'t> { self.map_rule(|r| r.char(')'), Type::RParen) } // compound punctuation - pub fn lsh(&mut self) -> Option { - self.map_rule(|r| r.str("<<"), Type::Lsh) + pub fn lt_lt(&mut self) -> Option { + self.map_rule(|r| r.str("<<"), Type::LtLt) } - pub fn rsh(&mut self) -> Option { - self.map_rule(|r| r.str(">>"), Type::Rsh) + pub fn gt_gt(&mut self) -> Option { + self.map_rule(|r| r.str(">>"), Type::GtGt) } pub fn amp_amp(&mut self) -> Option { self.map_rule(|r| r.str("&&"), Type::AmpAmp) @@ -216,11 +218,11 @@ impl<'t> Lexer<'t> { pub fn bar_bar(&mut self) -> Option { self.map_rule(|r| r.str("||"), Type::BarBar) } - pub fn not_not(&mut self) -> Option { - self.map_rule(|r| r.str("!!"), Type::NotNot) + pub fn bang_bang(&mut self) -> Option { + self.map_rule(|r| r.str("!!"), Type::BangBang) } - pub fn cat_ear(&mut self) -> Option { - self.map_rule(|r| r.str("^^"), Type::CatEar) + pub fn xor_xor(&mut self) -> Option { + self.map_rule(|r| r.str("^^"), Type::XorXor) } pub fn eq_eq(&mut self) -> Option { self.map_rule(|r| r.str("=="), Type::EqEq) @@ -231,38 +233,44 @@ impl<'t> Lexer<'t> { pub fn lt_eq(&mut self) -> Option { self.map_rule(|r| r.str("<="), Type::LtEq) } - pub fn not_eq(&mut self) -> Option { - self.map_rule(|r| r.str("!="), Type::NotEq) + pub fn bang_eq(&mut self) -> Option { + self.map_rule(|r| r.str("!="), Type::BangEq) } pub fn star_eq(&mut self) -> Option { self.map_rule(|r| r.str("*="), Type::StarEq) } - pub fn div_eq(&mut self) -> Option { - self.map_rule(|r| r.str("/="), Type::DivEq) + pub fn slash_eq(&mut self) -> Option { + self.map_rule(|r| r.str("/="), Type::SlashEq) } pub fn rem_eq(&mut self) -> Option { self.map_rule(|r| r.str("%="), Type::RemEq) } - pub fn add_eq(&mut self) -> Option { - self.map_rule(|r| r.str("+="), Type::AddEq) + pub fn plus_eq(&mut self) -> Option { + self.map_rule(|r| r.str("+="), Type::PlusEq) } - pub fn sub_eq(&mut self) -> Option { - self.map_rule(|r| r.str("-="), Type::SubEq) + pub fn minus_eq(&mut self) -> Option { + self.map_rule(|r| r.str("-="), Type::MinusEq) } - pub fn and_eq(&mut self) -> Option { - self.map_rule(|r| r.str("&="), Type::AndEq) + pub fn amp_eq(&mut self) -> Option { + self.map_rule(|r| r.str("&="), Type::AmpEq) } - pub fn or_eq(&mut self) -> Option { - self.map_rule(|r| r.str("|="), Type::OrEq) + pub fn bar_eq(&mut self) -> Option { + self.map_rule(|r| r.str("|="), Type::BarEq) } pub fn xor_eq(&mut self) -> Option { self.map_rule(|r| r.str("^="), Type::XorEq) } - pub fn lsh_eq(&mut self) -> Option { - self.map_rule(|r| r.str("<<="), Type::LshEq) + pub fn lt_lt_eq(&mut self) -> Option { + self.map_rule(|r| r.str("<<="), Type::LtLtEq) } - pub fn rsh_eq(&mut self) -> Option { - self.map_rule(|r| r.str(">>="), Type::RshEq) + pub fn gt_gt_eq(&mut self) -> Option { + self.map_rule(|r| r.str(">>="), Type::GtGtEq) + } + pub fn dot_dot_eq(&mut self) -> Option { + self.map_rule(|r| r.str("..="), Type::DotDotEq) + } + pub fn dot_dot(&mut self) -> Option { + self.map_rule(|r| r.str(".."), Type::DotDot) } pub fn arrow(&mut self) -> Option { self.map_rule(|r| r.str("->"), Type::Arrow) @@ -280,13 +288,13 @@ impl<'t> Lexer<'t> { pub fn star(&mut self) -> Option { self.map_rule(|r| r.char('*'), Type::Star) } - pub fn div(&mut self) -> Option { - self.map_rule(|r| r.char('/'), Type::Div) + pub fn slash(&mut self) -> Option { + self.map_rule(|r| r.char('/'), Type::Slash) } pub fn plus(&mut self) -> Option { self.map_rule(|r| r.char('+'), Type::Plus) } - pub fn sub(&mut self) -> Option { + pub fn minus(&mut self) -> Option { self.map_rule(|r| r.char('-'), Type::Minus) } pub fn rem(&mut self) -> Option { diff --git a/libconlang/src/tests.rs b/libconlang/src/tests.rs index 509ba6f..3efcf3e 100644 --- a/libconlang/src/tests.rs +++ b/libconlang/src/tests.rs @@ -90,11 +90,7 @@ mod lexer { #[test] fn identifier() { - assert_whole_input_is_token( - "valid_identifier", - Lexer::identifier, - Type::Identifier, - ); + assert_whole_input_is_token("valid_identifier", Lexer::identifier, Type::Identifier); assert_whole_input_is_token("_0", Lexer::identifier, Type::Identifier); assert_whole_input_is_token("_", Lexer::identifier, Type::Identifier); } @@ -129,12 +125,7 @@ mod lexer { #[test] fn base16() { assert_has_type_and_range("0x1234", Lexer::integer, Type::Integer, 0..6); - assert_has_type_and_range( - "0x1234 \"hello\"", - Lexer::integer, - Type::Integer, - 0..6, - ); + assert_has_type_and_range("0x1234 \"hello\"", Lexer::integer, Type::Integer, 0..6); } #[test] fn base10() { @@ -186,7 +177,7 @@ mod lexer { "\" \\\"This is a quote\\\" \"", Lexer::string, Type::String, - 1..22 + 1..22, ); } } @@ -254,14 +245,21 @@ mod lexer { use super::*; mod compound { use super::*; - #[test] - fn lsh() { - assert_whole_input_is_token("<<", Lexer::lsh, Type::Lsh) + fn dot_dot() { + assert_whole_input_is_token("..", Lexer::dot_dot, Type::DotDot) } #[test] - fn rsh() { - assert_whole_input_is_token(">>", Lexer::rsh, Type::Rsh) + fn dot_dot_eq() { + assert_whole_input_is_token("..=", Lexer::dot_dot_eq, Type::DotDotEq) + } + #[test] + fn lt_lt() { + assert_whole_input_is_token("<<", Lexer::lt_lt, Type::LtLt) + } + #[test] + fn gt_gt() { + assert_whole_input_is_token(">>", Lexer::gt_gt, Type::GtGt) } #[test] fn amp_amp() { @@ -272,12 +270,12 @@ mod lexer { assert_whole_input_is_token("||", Lexer::bar_bar, Type::BarBar) } #[test] - fn not_not() { - assert_whole_input_is_token("!!", Lexer::not_not, Type::NotNot) + fn bang_bang() { + assert_whole_input_is_token("!!", Lexer::bang_bang, Type::BangBang) } #[test] - fn cat_ear() { - assert_whole_input_is_token("^^", Lexer::cat_ear, Type::CatEar) + fn xor_xor() { + assert_whole_input_is_token("^^", Lexer::xor_xor, Type::XorXor) } #[test] fn eq_eq() { @@ -292,44 +290,44 @@ mod lexer { assert_whole_input_is_token("<=", Lexer::lt_eq, Type::LtEq) } #[test] - fn not_eq() { - assert_whole_input_is_token("!=", Lexer::not_eq, Type::NotEq) + fn bang_eq() { + assert_whole_input_is_token("!=", Lexer::bang_eq, Type::BangEq) } #[test] fn star_eq() { assert_whole_input_is_token("*=", Lexer::star_eq, Type::StarEq) } #[test] - fn div_eq() { - assert_whole_input_is_token("/=", Lexer::div_eq, Type::DivEq) + fn slash_eq() { + assert_whole_input_is_token("/=", Lexer::slash_eq, Type::SlashEq) } #[test] - fn add_eq() { - assert_whole_input_is_token("+=", Lexer::add_eq, Type::AddEq) + fn plus_eq() { + assert_whole_input_is_token("+=", Lexer::plus_eq, Type::PlusEq) } #[test] - fn sub_eq() { - assert_whole_input_is_token("-=", Lexer::sub_eq, Type::SubEq) + fn minus_eq() { + assert_whole_input_is_token("-=", Lexer::minus_eq, Type::MinusEq) } #[test] - fn and_eq() { - assert_whole_input_is_token("&=", Lexer::and_eq, Type::AndEq) + fn amp_eq() { + assert_whole_input_is_token("&=", Lexer::amp_eq, Type::AmpEq) } #[test] - fn or_eq() { - assert_whole_input_is_token("|=", Lexer::or_eq, Type::OrEq) + fn bar_eq() { + assert_whole_input_is_token("|=", Lexer::bar_eq, Type::BarEq) } #[test] fn xor_eq() { assert_whole_input_is_token("^=", Lexer::xor_eq, Type::XorEq) } #[test] - fn lsh_eq() { - assert_whole_input_is_token("<<=", Lexer::lsh_eq, Type::LshEq) + fn lt_lt_eq() { + assert_whole_input_is_token("<<=", Lexer::lt_lt_eq, Type::LtLtEq) } #[test] - fn rsh_eq() { - assert_whole_input_is_token(">>=", Lexer::rsh_eq, Type::RshEq) + fn gt_gt_eq() { + assert_whole_input_is_token(">>=", Lexer::gt_gt_eq, Type::GtGtEq) } } @@ -337,10 +335,11 @@ mod lexer { use super::*; #[test] fn punctuation_class() { + // go from least to most specific assert_whole_input_is_token(";", Lexer::punctuation, Type::Semi); assert_whole_input_is_token(".", Lexer::punctuation, Type::Dot); assert_whole_input_is_token("*", Lexer::punctuation, Type::Star); - assert_whole_input_is_token("/", Lexer::punctuation, Type::Div); + assert_whole_input_is_token("/", Lexer::punctuation, Type::Slash); assert_whole_input_is_token("+", Lexer::punctuation, Type::Plus); assert_whole_input_is_token("-", Lexer::punctuation, Type::Minus); assert_whole_input_is_token("%", Lexer::punctuation, Type::Rem); @@ -359,6 +358,27 @@ mod lexer { assert_whole_input_is_token("~", Lexer::punctuation, Type::Tilde); assert_whole_input_is_token("`", Lexer::punctuation, Type::Grave); assert_whole_input_is_token("\\", Lexer::punctuation, Type::Backslash); + assert_whole_input_is_token("<<", Lexer::punctuation, Type::LtLt); + assert_whole_input_is_token(">>", Lexer::punctuation, Type::GtGt); + assert_whole_input_is_token("&&", Lexer::punctuation, Type::AmpAmp); + assert_whole_input_is_token("||", Lexer::punctuation, Type::BarBar); + assert_whole_input_is_token("!!", Lexer::punctuation, Type::BangBang); + assert_whole_input_is_token("^^", Lexer::punctuation, Type::XorXor); + assert_whole_input_is_token("==", Lexer::punctuation, Type::EqEq); + assert_whole_input_is_token(">=", Lexer::punctuation, Type::GtEq); + assert_whole_input_is_token("<=", Lexer::punctuation, Type::LtEq); + assert_whole_input_is_token("!=", Lexer::punctuation, Type::BangEq); + assert_whole_input_is_token("*=", Lexer::punctuation, Type::StarEq); + assert_whole_input_is_token("/=", Lexer::punctuation, Type::SlashEq); + assert_whole_input_is_token("+=", Lexer::punctuation, Type::PlusEq); + assert_whole_input_is_token("-=", Lexer::punctuation, Type::MinusEq); + assert_whole_input_is_token("&=", Lexer::punctuation, Type::AmpEq); + assert_whole_input_is_token("|=", Lexer::punctuation, Type::BarEq); + assert_whole_input_is_token("^=", Lexer::punctuation, Type::XorEq); + assert_whole_input_is_token("..", Lexer::punctuation, Type::DotDot); + assert_whole_input_is_token("..=", Lexer::punctuation, Type::DotDotEq); + assert_whole_input_is_token("<<=", Lexer::punctuation, Type::LtLtEq); + assert_whole_input_is_token(">>=", Lexer::punctuation, Type::GtGtEq); } // individual functions below #[test] @@ -374,8 +394,8 @@ mod lexer { assert_whole_input_is_token("*", Lexer::star, Type::Star) } #[test] - fn div() { - assert_whole_input_is_token("/", Lexer::div, Type::Div) + fn slash() { + assert_whole_input_is_token("/", Lexer::slash, Type::Slash) } #[test] fn plus() { @@ -383,7 +403,7 @@ mod lexer { } #[test] fn minus() { - assert_whole_input_is_token("-", Lexer::sub, Type::Minus) + assert_whole_input_is_token("-", Lexer::minus, Type::Minus) } #[test] fn rem() { @@ -406,11 +426,11 @@ mod lexer { assert_whole_input_is_token(">", Lexer::gt, Type::Gt) } #[test] - fn and() { + fn amp() { assert_whole_input_is_token("&", Lexer::amp, Type::Amp) } #[test] - fn or() { + fn bar() { assert_whole_input_is_token("|", Lexer::bar, Type::Bar) } #[test] diff --git a/libconlang/src/token.rs b/libconlang/src/token.rs index 19db027..cb6db1c 100644 --- a/libconlang/src/token.rs +++ b/libconlang/src/token.rs @@ -16,59 +16,59 @@ pub enum Type { Float, String, Character, - // Delimiters - LCurly, - RCurly, - LBrack, - RBrack, - LParen, - RParen, - // Compound punctuation - Lsh, - Rsh, - AmpAmp, - BarBar, - NotNot, - CatEar, - EqEq, - GtEq, - LtEq, - NotEq, - StarEq, - DivEq, - RemEq, - AddEq, - SubEq, - AndEq, - OrEq, - XorEq, - LshEq, - RshEq, - Arrow, - FatArrow, - // Simple punctuation - Semi, - Dot, - Star, - Div, - Plus, - Minus, - Rem, - Bang, - Eq, - Lt, - Gt, - Amp, - Bar, - Xor, - Hash, - At, - Colon, - Backslash, - Question, - Comma, - Tilde, - Grave, + // Delimiters and punctuation + LCurly, // { + RCurly, // } + LBrack, // [ + RBrack, // ] + LParen, // ( + RParen, // ) + Amp, // & + AmpAmp, // && + AmpEq, // &= + Arrow, // -> + At, // @ + Backslash, // \ + Bang, // ! + BangBang, // !! + BangEq, // != + Bar, // | + BarBar, // || + BarEq, // |= + Colon, // : + Comma, // , + Dot, // . + DotDot, // .. + DotDotEq, // ..= + Eq, // = + EqEq, // == + FatArrow, // => + Grave, // ` + Gt, // > + GtEq, // >= + GtGt, // >> + GtGtEq, // >>= + Hash, // # + Lt, // < + LtEq, // <= + LtLt, // << + LtLtEq, // <<= + Minus, // - + MinusEq, // -= + Plus, // + + PlusEq, // += + Question, // ? + Rem, // % + RemEq, // %= + Semi, // ; + Slash, // / + SlashEq, // /= + Star, // * + StarEq, // *= + Tilde, // ~ + Xor, // ^ + XorEq, // ^= + XorXor, // ^^ } /// Represents a reserved word. diff --git a/libconlang/src/token/token_type.rs b/libconlang/src/token/token_type.rs index bb1b98c..ef30d51 100644 --- a/libconlang/src/token/token_type.rs +++ b/libconlang/src/token/token_type.rs @@ -5,64 +5,66 @@ use std::fmt::Display; impl Display for Type { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Type::Invalid => Display::fmt("invalid", f), - Type::Comment => Display::fmt("comment", f), - Type::Identifier => Display::fmt("identifier", f), - Type::Keyword(k) => Display::fmt(k, f), - Type::Integer => Display::fmt("integer literal", f), - Type::Float => Display::fmt("float literal", f), - Type::String => Display::fmt("string literal", f), - Type::Character => Display::fmt("char literal", f), - Type::LCurly => Display::fmt("left curly", f), - Type::RCurly => Display::fmt("right curly", f), - Type::LBrack => Display::fmt("left brack", f), - Type::RBrack => Display::fmt("right brack", f), - Type::LParen => Display::fmt("left paren", f), - Type::RParen => Display::fmt("right paren", f), - Type::Lsh => Display::fmt("shift left", f), - Type::Rsh => Display::fmt("shift right", f), - Type::AmpAmp => Display::fmt("and-and", f), - Type::BarBar => Display::fmt("or-or", f), - Type::NotNot => Display::fmt("not-not", f), - Type::CatEar => Display::fmt("cat-ears", f), - Type::EqEq => Display::fmt("equal to", f), - Type::GtEq => Display::fmt("greater than or equal to", f), - Type::LtEq => Display::fmt("less than or equal to", f), - Type::NotEq => Display::fmt("not equal to", f), - Type::StarEq => Display::fmt("star-assign", f), - Type::DivEq => Display::fmt("div-assign", f), - Type::RemEq => Display::fmt("rem-assign", f), - Type::AddEq => Display::fmt("add-assign", f), - Type::SubEq => Display::fmt("sub-assign", f), - Type::AndEq => Display::fmt("and-assign", f), - Type::OrEq => Display::fmt("or-assign", f), - Type::XorEq => Display::fmt("xor-assign", f), - Type::LshEq => Display::fmt("shift left-assign", f), - Type::RshEq => Display::fmt("shift right-assign", f), - Type::Arrow => Display::fmt("arrow", f), - Type::FatArrow => Display::fmt("fat arrow", f), - Type::Semi => Display::fmt("ignore", f), - Type::Dot => Display::fmt("dot", f), - Type::Star => Display::fmt("star", f), - Type::Div => Display::fmt("div", f), - Type::Plus => Display::fmt("add", f), - Type::Minus => Display::fmt("sub", f), - Type::Rem => Display::fmt("rem", f), - Type::Bang => Display::fmt("bang", f), - Type::Eq => Display::fmt("assign", f), - Type::Lt => Display::fmt("less than", f), - Type::Gt => Display::fmt("greater than", f), - Type::Amp => Display::fmt("and", f), - Type::Bar => Display::fmt("or", f), - Type::Xor => Display::fmt("xor", f), - Type::Hash => Display::fmt("hash", f), - Type::At => Display::fmt("at", f), - Type::Colon => Display::fmt("colon", f), - Type::Backslash => Display::fmt("backslash", f), - Type::Question => Display::fmt("huh?", f), - Type::Comma => Display::fmt("comma", f), - Type::Tilde => Display::fmt("tilde", f), - Type::Grave => Display::fmt("grave", f), + Type::Invalid => "invalid".fmt(f), + Type::Comment => "comment".fmt(f), + Type::Identifier => "identifier".fmt(f), + Type::Keyword(k) => k.fmt(f), + Type::Integer => "integer literal".fmt(f), + Type::Float => "float literal".fmt(f), + Type::String => "string literal".fmt(f), + Type::Character => "char literal".fmt(f), + Type::LCurly => "left curly".fmt(f), + Type::RCurly => "right curly".fmt(f), + Type::LBrack => "left brack".fmt(f), + Type::RBrack => "right brack".fmt(f), + Type::LParen => "left paren".fmt(f), + Type::RParen => "right paren".fmt(f), + Type::Amp => "and".fmt(f), + Type::AmpAmp => "and-and".fmt(f), + Type::AmpEq => "and-assign".fmt(f), + Type::Arrow => "arrow".fmt(f), + Type::At => "at".fmt(f), + Type::Backslash => "backslash".fmt(f), + Type::Bang => "bang".fmt(f), + Type::BangBang => "not-not".fmt(f), + Type::BangEq => "not equal to".fmt(f), + Type::Bar => "or".fmt(f), + Type::BarBar => "or-or".fmt(f), + Type::BarEq => "or-assign".fmt(f), + Type::Colon => "colon".fmt(f), + Type::Comma => "comma".fmt(f), + Type::Dot => "dot".fmt(f), + Type::DotDot => "exclusive range".fmt(f), + Type::DotDotEq => "inclusive range".fmt(f), + Type::Eq => "assign".fmt(f), + Type::EqEq => "equal to".fmt(f), + Type::FatArrow => "fat arrow".fmt(f), + Type::Grave => "grave".fmt(f), + Type::Gt => "greater than".fmt(f), + Type::GtEq => "greater than or equal to".fmt(f), + Type::GtGt => "shift right".fmt(f), + Type::GtGtEq => "shift right-assign".fmt(f), + Type::Hash => "hash".fmt(f), + Type::Lt => "less than".fmt(f), + Type::LtEq => "less than or equal to".fmt(f), + Type::LtLt => "shift left".fmt(f), + Type::LtLtEq => "shift left-assign".fmt(f), + Type::Minus => "sub".fmt(f), + Type::MinusEq => "sub-assign".fmt(f), + Type::Plus => "add".fmt(f), + Type::PlusEq => "add-assign".fmt(f), + Type::Question => "huh?".fmt(f), + Type::Rem => "rem".fmt(f), + Type::RemEq => "rem-assign".fmt(f), + Type::Semi => "ignore".fmt(f), + Type::Slash => "div".fmt(f), + Type::SlashEq => "div-assign".fmt(f), + Type::Star => "star".fmt(f), + Type::StarEq => "star-assign".fmt(f), + Type::Tilde => "tilde".fmt(f), + Type::Xor => "xor".fmt(f), + Type::XorEq => "xor-assign".fmt(f), + Type::XorXor => "cat-ears".fmt(f), } } } @@ -70,23 +72,23 @@ impl Display for Type { impl Display for Keyword { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Break => Display::fmt("break", f), - Self::Continue => Display::fmt("continue", f), - Self::Else => Display::fmt("else", f), - Self::False => Display::fmt("false", f), - Self::For => Display::fmt("for", f), - Self::Fn => Display::fmt("fn", f), - Self::If => Display::fmt("if", f), - Self::In => Display::fmt("in", f), - Self::Let => Display::fmt("let", f), - Self::Return => Display::fmt("return", f), - Self::True => Display::fmt("true", f), - Self::While => Display::fmt("while", f), + Self::Break => "break".fmt(f), + Self::Continue => "continue".fmt(f), + Self::Else => "else".fmt(f), + Self::False => "false".fmt(f), + Self::For => "for".fmt(f), + Self::Fn => "fn".fmt(f), + Self::If => "if".fmt(f), + Self::In => "in".fmt(f), + Self::Let => "let".fmt(f), + Self::Return => "return".fmt(f), + Self::True => "true".fmt(f), + Self::While => "while".fmt(f), } } } impl std::str::FromStr for Keyword { - type Err = (); + type Err = (); // If an identifier isn't a keyword, that's okay. fn from_str(s: &str) -> Result { Ok(match s { "break" => Self::Break,