Files
revive/crates/solidity/src/yul/lexer/token/lexeme/keyword.rs
T
Cyrill Leutwiler dbb47fd13e experimental: support for debug info (#118)
Signed-off-by: wpt967 <matt.aw@parity.io>
Signed-off-by: xermicus <cyrill@parity.io>
2024-11-22 08:56:09 +01:00

148 lines
4.4 KiB
Rust

//! The keyword lexeme.
use crate::yul::lexer::token::lexeme::literal::boolean::Boolean as BooleanLiteral;
use crate::yul::lexer::token::lexeme::literal::Literal;
use crate::yul::lexer::token::lexeme::Lexeme;
use crate::yul::lexer::token::location::Location;
use crate::yul::lexer::token::Token;
/// The keyword lexeme.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Keyword {
/// The `object` keyword.
Object,
/// The `code` keyword.
Code,
/// The `function` keyword.
Function,
/// The `let` keyword.
Let,
/// The `if` keyword.
If,
/// The `switch` keyword.
Switch,
/// The `case` keyword.
Case,
/// The `default` keyword.
Default,
/// The `for` keyword.
For,
/// The `break` keyword.
Break,
/// The `continue` keyword.
Continue,
/// The `leave` keyword.
Leave,
/// The `true` keyword.
True,
/// The `false` keyword.
False,
/// The `bool` keyword.
Bool,
/// The `int{N}` keyword.
Int(usize),
/// The `uint{N}` keyword.
Uint(usize),
}
impl Keyword {
/// Parses the keyword, returning it as a token.
pub fn parse(input: &str) -> Option<Token> {
let keyword = Self::parse_keyword(input)?;
let lexeme = match BooleanLiteral::try_from(keyword) {
Ok(literal) => Lexeme::Literal(Literal::Boolean(literal)),
Err(keyword) => Lexeme::Keyword(keyword),
};
let length = lexeme.to_string().len();
if length != input.len() {
return None;
}
let length = length
.try_into()
.expect("the YUL should be of reasonable size");
Some(Token::new(Location::new(0, length), lexeme, length))
}
/// Parses the keyword itself.
fn parse_keyword(input: &str) -> Option<Self> {
if !input.starts_with(Self::can_begin) {
return None;
}
let end = input.find(Self::cannot_continue).unwrap_or(input.len());
let input = &input[..end];
if let Some(input) = input.strip_prefix("int") {
if let Ok(bitlength) = input.parse::<usize>() {
return Some(Self::Int(bitlength));
}
}
if let Some(input) = input.strip_prefix("uint") {
if let Ok(bitlength) = input.parse::<usize>() {
return Some(Self::Uint(bitlength));
}
}
Some(match input {
"object" => Self::Object,
"code" => Self::Code,
"function" => Self::Function,
"let" => Self::Let,
"if" => Self::If,
"switch" => Self::Switch,
"case" => Self::Case,
"default" => Self::Default,
"for" => Self::For,
"break" => Self::Break,
"continue" => Self::Continue,
"leave" => Self::Leave,
"true" => Self::True,
"false" => Self::False,
"bool" => Self::Bool,
_ => return None,
})
}
/// Checks whether the character can begin a keyword.
pub fn can_begin(character: char) -> bool {
character.is_alphabetic()
}
/// Checks whether the character can continue a keyword.
pub fn can_continue(character: char) -> bool {
Self::can_begin(character) || character.is_numeric()
}
/// Checks whether the character cannot continue a keyword.
pub fn cannot_continue(character: char) -> bool {
!Self::can_continue(character)
}
}
impl std::fmt::Display for Keyword {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Object => write!(f, "object"),
Self::Code => write!(f, "code"),
Self::Function => write!(f, "function"),
Self::Let => write!(f, "let"),
Self::If => write!(f, "if"),
Self::Switch => write!(f, "switch"),
Self::Case => write!(f, "case"),
Self::Default => write!(f, "default"),
Self::For => write!(f, "for"),
Self::Break => write!(f, "break"),
Self::Continue => write!(f, "continue"),
Self::Leave => write!(f, "leave"),
Self::True => write!(f, "true"),
Self::False => write!(f, "false"),
Self::Bool => write!(f, "bool"),
Self::Int(bitlength) => write!(f, "int{bitlength}"),
Self::Uint(bitlength) => write!(f, "uint{bitlength}"),
}
}
}