use logos::Logos;
use num_derive::{FromPrimitive, ToPrimitive};
use serde::{Deserialize, Serialize};
#[derive(
Clone, Copy, PartialEq, Logos, Debug, FromPrimitive, ToPrimitive, Serialize, Deserialize,
)]
pub enum Token {
#[token("object")]
Object,
#[token("code")]
Code,
#[token("data")]
Data,
#[token("function")]
Function,
#[token("let")]
Let,
#[token("if")]
If,
#[token("switch")]
Switch,
#[token("case")]
Case,
#[token("default")]
Default,
#[token("for")]
For,
#[token("break")]
Break,
#[token("continue")]
Continue,
#[token("leave")]
Leave,
#[token("(")]
ParenOpen,
#[token(")")]
ParenClose,
#[token(r"{")]
BraceOpen,
#[token(r"}")]
BraceClose,
#[token(",")]
Comma,
#[token(":=")]
Assign,
#[token("->")]
Returns,
#[token(":")]
Typed,
#[regex(r"[a-zA-Z_$][a-zA-Z_$0-9.]*")]
Identifier,
#[token("true")]
LiteralTrue,
#[token("false")]
LiteralFalse,
#[regex(r"0x[0-9a-fA-F]+")]
LiteralHex,
#[regex(r"[0-9]+")]
LiteralInt,
#[regex(r#""([^"\r\n\\]|\\.)*""#)]
LiteralString,
#[regex(r#"hex"([0-9a-fA-F][0-9a-fA-F])*""#)]
LiteralStringHex,
#[regex(r#"//[^\n]*"#)]
LineComment,
#[regex(r#"/\*[^*]*\*/"#)]
BlockComment,
#[regex(r"[ \t\n\f]+")]
Whitespace,
#[error]
Error,
}
impl Token {
pub fn is_significant(&self) -> bool {
use Token::*;
match self {
LineComment | BlockComment | Whitespace => false,
_ => true,
}
}
pub fn is_error(&self) -> bool {
use Token::*;
match self {
Error => true,
_ => false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lex_example() {
let example = include_str!("../test/example.yul");
let tokens = Token::lexer(example).collect::<Vec<_>>();
let expected: Vec<Token> =
serde_json::from_str(include_str!("../test/example.tokens.json")).unwrap();
assert_eq!(tokens, expected);
}
#[test]
fn lex_erc20() {
let example = include_str!("../test/erc20.yul");
let tokens = Token::lexer(example).collect::<Vec<_>>();
let expected: Vec<Token> =
serde_json::from_str(include_str!("../test/erc20.tokens.json")).unwrap();
assert_eq!(tokens, expected);
}
}