use crate::internal::as2::lexer::Lexer;
use crate::internal::as2::lexer::operator::Operator;
use crate::internal::as2::lexer::tokens::{Keyword, QuoteKind, Token, TokenKind};
use crate::internal::span::FileId;
const TEST_FILE_ID: FileId = FileId::new(0);
fn kinds(input: &str) -> Vec<TokenKind> {
Lexer::new(input, TEST_FILE_ID)
.into_vec()
.into_iter()
.map(|t| t.kind)
.collect()
}
fn raws(input: &str) -> Vec<String> {
Lexer::new(input, TEST_FILE_ID)
.into_vec()
.into_iter()
.map(|t| t.raw.to_string())
.collect()
}
#[test]
fn test_all_samples() {
insta::glob!("../../../../../../samples/as2", "**/*.as", |path| {
let src = std::fs::read_to_string(path).expect("failed to read sample");
let tokens = Lexer::new(&src, TEST_FILE_ID).into_vec();
insta::assert_yaml_snapshot!(tokens);
});
}
#[test]
fn test_line_comment() {
let input = "// this is a line comment\n";
assert_eq!(
Lexer::new(input, TEST_FILE_ID).into_vec(),
Vec::<Token>::new()
);
}
#[test]
fn test_empty_line_comment() {
let input = "//";
assert_eq!(
Lexer::new(input, TEST_FILE_ID).into_vec(),
Vec::<Token>::new()
);
}
#[test]
fn test_block_comment() {
let input = "/* this is a block comment */";
assert_eq!(
Lexer::new(input, TEST_FILE_ID).into_vec(),
Vec::<Token>::new()
);
}
#[test]
fn test_non_ending_block_comment() {
let input = "/*";
assert_eq!(
Lexer::new(input, TEST_FILE_ID).into_vec(),
Vec::<Token>::new()
);
}
#[test]
fn test_identifiers_and_keyword() {
assert_eq!(
kinds(
"var x _abc $d Var instanceof new typeof delete in void function return for if else break continue throw try catch finally ifFrameLoaded tellTarget while dynamic extends get implements interface private public set static case switch default class with import"
),
vec![
TokenKind::Keyword(Keyword::Var),
TokenKind::Identifier,
TokenKind::Identifier,
TokenKind::Identifier,
TokenKind::Identifier, TokenKind::Keyword(Keyword::InstanceOf),
TokenKind::Keyword(Keyword::New),
TokenKind::Keyword(Keyword::TypeOf),
TokenKind::Keyword(Keyword::Delete),
TokenKind::Keyword(Keyword::In),
TokenKind::Keyword(Keyword::Void),
TokenKind::Keyword(Keyword::Function),
TokenKind::Keyword(Keyword::Return),
TokenKind::Keyword(Keyword::For),
TokenKind::Keyword(Keyword::If),
TokenKind::Keyword(Keyword::Else),
TokenKind::Keyword(Keyword::Break),
TokenKind::Keyword(Keyword::Continue),
TokenKind::Keyword(Keyword::Throw),
TokenKind::Keyword(Keyword::Try),
TokenKind::Keyword(Keyword::Catch),
TokenKind::Keyword(Keyword::Finally),
TokenKind::Keyword(Keyword::IfFrameLoaded),
TokenKind::Keyword(Keyword::TellTarget),
TokenKind::Keyword(Keyword::While),
TokenKind::Keyword(Keyword::Dynamic),
TokenKind::Keyword(Keyword::Extends),
TokenKind::Keyword(Keyword::Get),
TokenKind::Keyword(Keyword::Implements),
TokenKind::Keyword(Keyword::Interface),
TokenKind::Keyword(Keyword::Private),
TokenKind::Keyword(Keyword::Public),
TokenKind::Keyword(Keyword::Set),
TokenKind::Keyword(Keyword::Static),
TokenKind::Keyword(Keyword::Case),
TokenKind::Keyword(Keyword::Switch),
TokenKind::Keyword(Keyword::Default),
TokenKind::Keyword(Keyword::Class),
TokenKind::Keyword(Keyword::With),
TokenKind::Keyword(Keyword::Import),
]
);
}
#[test]
fn test_legacy_operators() {
assert_eq!(
kinds("eq gt ge lt le ne and not or"),
vec![
TokenKind::Keyword(Keyword::Eq),
TokenKind::Keyword(Keyword::Gt),
TokenKind::Keyword(Keyword::Ge),
TokenKind::Keyword(Keyword::Lt),
TokenKind::Keyword(Keyword::Le),
TokenKind::Keyword(Keyword::Ne),
TokenKind::Keyword(Keyword::And),
TokenKind::Keyword(Keyword::Not),
TokenKind::Keyword(Keyword::Or),
]
);
}
#[test]
fn test_operators_single_and_compound() {
assert_eq!(
kinds("+ = += - / * % ++ -- -= *= /= %= & ~ | >> << >>> ^ &= |= ^= >>= <<= >>>="),
vec![
TokenKind::Operator(Operator::Add),
TokenKind::Operator(Operator::Assign),
TokenKind::Operator(Operator::AddAssign),
TokenKind::Operator(Operator::Sub),
TokenKind::Operator(Operator::Divide),
TokenKind::Operator(Operator::Multiply),
TokenKind::Operator(Operator::Modulo),
TokenKind::Operator(Operator::Increment),
TokenKind::Operator(Operator::Decrement),
TokenKind::Operator(Operator::SubAssign),
TokenKind::Operator(Operator::MultiplyAssign),
TokenKind::Operator(Operator::DivideAssign),
TokenKind::Operator(Operator::ModuloAssign),
TokenKind::Operator(Operator::BitAnd),
TokenKind::Operator(Operator::BitNot),
TokenKind::Operator(Operator::BitOr),
TokenKind::Operator(Operator::BitShiftRight),
TokenKind::Operator(Operator::BitShiftLeft),
TokenKind::Operator(Operator::BitShiftRightUnsigned),
TokenKind::Operator(Operator::BitXor),
TokenKind::Operator(Operator::BitAndAssign),
TokenKind::Operator(Operator::BitOrAssign),
TokenKind::Operator(Operator::BitXorAssign),
TokenKind::Operator(Operator::BitShiftRightAssign),
TokenKind::Operator(Operator::BitShiftLeftAssign),
TokenKind::Operator(Operator::BitShiftRightUnsignedAssign),
]
);
}
#[test]
fn test_equality_operators() {
assert_eq!(
kinds("== != <= >= < > === !=="),
vec![
TokenKind::Operator(Operator::Equal),
TokenKind::Operator(Operator::NotEqual),
TokenKind::Operator(Operator::LessThanEqual),
TokenKind::Operator(Operator::GreaterThanEqual),
TokenKind::Operator(Operator::LessThan),
TokenKind::Operator(Operator::GreaterThan),
TokenKind::Operator(Operator::StrictEqual),
TokenKind::Operator(Operator::StrictNotEqual),
]
);
}
#[test]
fn test_ternary_operator() {
assert_eq!(kinds("?:"), vec![TokenKind::Question, TokenKind::Colon]);
}
#[test]
fn test_logic_operators() {
assert_eq!(
kinds("|| && !"),
vec![
TokenKind::Operator(Operator::LogicalOr),
TokenKind::Operator(Operator::LogicalAnd),
TokenKind::Operator(Operator::LogicalNot),
]
);
}
#[test]
fn test_punctuation_tokens() {
assert_eq!(
kinds("(,) ); {} . []"),
vec![
TokenKind::OpenParen,
TokenKind::Comma,
TokenKind::CloseParen,
TokenKind::CloseParen,
TokenKind::Semicolon,
TokenKind::OpenBrace,
TokenKind::CloseBrace,
TokenKind::Period,
TokenKind::OpenBracket,
TokenKind::CloseBracket,
]
);
}
#[test]
fn test_newlines_variants() {
assert_eq!(kinds("\n"), vec![TokenKind::Newline]);
assert_eq!(kinds("\r\n"), vec![TokenKind::Newline]);
assert_eq!(kinds("\r"), vec![TokenKind::Newline]);
}
#[test]
fn test_string_literal_and_escapes() {
assert_eq!(
kinds("\"hello\""),
vec![TokenKind::String(QuoteKind::Double)]
);
assert_eq!(raws("\"hello\""), vec!["hello".to_string()]);
assert_eq!(kinds("'hello'"), vec![TokenKind::String(QuoteKind::Single)]);
assert_eq!(raws("'hello'"), vec!["hello".to_string()]);
let s = "\"a\\\"b'\\\\c\""; assert_eq!(kinds(s), vec![TokenKind::String(QuoteKind::Double)]);
assert_eq!(raws(s), vec!["a\\\"b'\\\\c".to_string()]);
let s = "\'a\\'b\"\\\\c\'"; assert_eq!(kinds(s), vec![TokenKind::String(QuoteKind::Single)]);
assert_eq!(raws(s), vec!["a\\'b\"\\\\c".to_string()]);
}
#[test]
fn test_mixed_sequence() {
let input = "var x+=y,($z);\r\n";
assert_eq!(
kinds(input),
vec![
TokenKind::Keyword(Keyword::Var),
TokenKind::Identifier,
TokenKind::Operator(Operator::AddAssign),
TokenKind::Identifier,
TokenKind::Comma,
TokenKind::OpenParen,
TokenKind::Identifier,
TokenKind::CloseParen,
TokenKind::Semicolon,
TokenKind::Newline,
]
);
}
#[test]
fn test_single_digit() {
let input = "1";
assert_eq!(kinds(input), vec![TokenKind::Integer]);
assert_eq!(raws(input), vec!["1".to_string()]);
}
#[test]
fn test_float_trailing_dot() {
let input = "1.";
assert_eq!(kinds(input), vec![TokenKind::Float]);
assert_eq!(raws(input), vec!["1.".to_string()]);
}
#[test]
fn test_float_leading_dot() {
let input = ".1";
assert_eq!(kinds(input), vec![TokenKind::Float]);
assert_eq!(raws(input), vec![".1".to_string()]);
}
#[test]
fn test_float() {
let input = "1.2";
assert_eq!(kinds(input), vec![TokenKind::Float]);
assert_eq!(raws(input), vec!["1.2".to_string()]);
}
#[test]
fn test_long_integer_semicolon() {
let input = "1234567890;";
assert_eq!(kinds(input), vec![TokenKind::Integer, TokenKind::Semicolon]);
assert_eq!(raws(input), vec!["1234567890".to_string(), ";".to_string()]);
}
#[test]
fn test_long_float_semicolon() {
let input = "12345.67890;";
assert_eq!(kinds(input), vec![TokenKind::Float, TokenKind::Semicolon]);
assert_eq!(
raws(input),
vec!["12345.67890".to_string(), ";".to_string()]
);
}
#[test]
fn test_hex_integer_semicolon() {
let input = "0x1A2C;";
assert_eq!(kinds(input), vec![TokenKind::Integer, TokenKind::Semicolon]);
assert_eq!(raws(input), vec!["0x1A2C".to_string(), ";".to_string()]);
}
#[test]
fn test_float_exponent_semicolon() {
let input = "1.2e+3;";
assert_eq!(kinds(input), vec![TokenKind::Float, TokenKind::Semicolon]);
assert_eq!(raws(input), vec!["1.2e+3".to_string(), ";".to_string()]);
}
#[test]
fn test_integer_exponent_semicolon() {
let input = "1e-3;";
assert_eq!(kinds(input), vec![TokenKind::Integer, TokenKind::Semicolon]);
assert_eq!(raws(input), vec!["1e-3".to_string(), ";".to_string()]);
}
#[test]
fn test_integer_exponent_no_value() {
let input = "1e;";
assert_eq!(kinds(input), vec![TokenKind::Integer, TokenKind::Semicolon]);
assert_eq!(raws(input), vec!["1e".to_string(), ";".to_string()]);
}
#[test]
fn test_float_exponent_no_digits() {
let input = ".e";
assert_eq!(kinds(input), vec![TokenKind::Period, TokenKind::Identifier]);
assert_eq!(raws(input), vec![".".to_string(), "e".to_string()]);
}
#[test]
fn test_pcode() {
let input = "continue @PCode {xxxxxxx} continue";
assert_eq!(
kinds(input),
vec![
TokenKind::Keyword(Keyword::Continue),
TokenKind::PCode,
TokenKind::Keyword(Keyword::Continue)
]
);
assert_eq!(
raws(input),
vec![
"continue".to_string(),
"xxxxxxx".to_string(),
"continue".to_string()
]
);
}
#[test]
fn test_directive() {
let input = "#include";
assert_eq!(kinds(input), vec![TokenKind::Hash, TokenKind::Identifier]);
assert_eq!(raws(input), vec!["#".to_string(), "include".to_string()]);
}
#[test]
fn test_pcode_nested_braces() {
let input = "continue @PCode {{{}}} continue";
assert_eq!(
kinds(input),
vec![
TokenKind::Keyword(Keyword::Continue),
TokenKind::PCode,
TokenKind::Keyword(Keyword::Continue)
]
);
assert_eq!(
raws(input),
vec![
"continue".to_string(),
"{{}}".to_string(),
"continue".to_string()
]
);
}