Token: Add range operators, rename for consistency

This commit is contained in:
John 2023-10-20 17:09:14 -05:00
parent 34525ec77a
commit 1e5f7149d9
6 changed files with 283 additions and 252 deletions

View File

@ -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 = '&' | '|' | '^' ;

View File

@ -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 {

View File

@ -104,53 +104,55 @@ impl<'t> Lexer<'t> {
}
/// Evaluates punctuation rules
pub fn punctuation(&mut self) -> Option<Token> {
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<Token> {
self.bang().or_else(|| self.sub())
self.bang().or_else(|| self.minus())
}
// functions for lexing individual tokens
pub fn invalid(&mut self) -> Option<Token> {
@ -204,11 +206,11 @@ impl<'t> Lexer<'t> {
self.map_rule(|r| r.char(')'), Type::RParen)
}
// compound punctuation
pub fn lsh(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("<<"), Type::Lsh)
pub fn lt_lt(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("<<"), Type::LtLt)
}
pub fn rsh(&mut self) -> Option<Token> {
self.map_rule(|r| r.str(">>"), Type::Rsh)
pub fn gt_gt(&mut self) -> Option<Token> {
self.map_rule(|r| r.str(">>"), Type::GtGt)
}
pub fn amp_amp(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("&&"), Type::AmpAmp)
@ -216,11 +218,11 @@ impl<'t> Lexer<'t> {
pub fn bar_bar(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("||"), Type::BarBar)
}
pub fn not_not(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("!!"), Type::NotNot)
pub fn bang_bang(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("!!"), Type::BangBang)
}
pub fn cat_ear(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("^^"), Type::CatEar)
pub fn xor_xor(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("^^"), Type::XorXor)
}
pub fn eq_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("=="), Type::EqEq)
@ -231,38 +233,44 @@ impl<'t> Lexer<'t> {
pub fn lt_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("<="), Type::LtEq)
}
pub fn not_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("!="), Type::NotEq)
pub fn bang_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("!="), Type::BangEq)
}
pub fn star_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("*="), Type::StarEq)
}
pub fn div_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("/="), Type::DivEq)
pub fn slash_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("/="), Type::SlashEq)
}
pub fn rem_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("%="), Type::RemEq)
}
pub fn add_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("+="), Type::AddEq)
pub fn plus_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("+="), Type::PlusEq)
}
pub fn sub_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("-="), Type::SubEq)
pub fn minus_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("-="), Type::MinusEq)
}
pub fn and_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("&="), Type::AndEq)
pub fn amp_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("&="), Type::AmpEq)
}
pub fn or_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("|="), Type::OrEq)
pub fn bar_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("|="), Type::BarEq)
}
pub fn xor_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("^="), Type::XorEq)
}
pub fn lsh_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("<<="), Type::LshEq)
pub fn lt_lt_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("<<="), Type::LtLtEq)
}
pub fn rsh_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str(">>="), Type::RshEq)
pub fn gt_gt_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str(">>="), Type::GtGtEq)
}
pub fn dot_dot_eq(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("..="), Type::DotDotEq)
}
pub fn dot_dot(&mut self) -> Option<Token> {
self.map_rule(|r| r.str(".."), Type::DotDot)
}
pub fn arrow(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("->"), Type::Arrow)
@ -280,13 +288,13 @@ impl<'t> Lexer<'t> {
pub fn star(&mut self) -> Option<Token> {
self.map_rule(|r| r.char('*'), Type::Star)
}
pub fn div(&mut self) -> Option<Token> {
self.map_rule(|r| r.char('/'), Type::Div)
pub fn slash(&mut self) -> Option<Token> {
self.map_rule(|r| r.char('/'), Type::Slash)
}
pub fn plus(&mut self) -> Option<Token> {
self.map_rule(|r| r.char('+'), Type::Plus)
}
pub fn sub(&mut self) -> Option<Token> {
pub fn minus(&mut self) -> Option<Token> {
self.map_rule(|r| r.char('-'), Type::Minus)
}
pub fn rem(&mut self) -> Option<Token> {

View File

@ -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]

View File

@ -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.

View File

@ -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<Self, Self::Err> {
Ok(match s {
"break" => Self::Break,