use flexar::{lext::Lext, flext::Flext, token_node::Token}; flexar::compiler_error! { [[Define] CompileErrors] (E001) "invalid character": "`", "` is an invalid character"; (E002) "string not closed": "expected `\"` to close string"; } flexar::lexer! { [[TokenType] lext, current, 'cycle] else flexar::compiler_error!((E001, lext.position()) current).throw(); token_types { Slash => "/"; Plus => "+"; LParen => "("; RParen => ")"; EE => "=="; EEE => "==="; EQ => "="; Dot => "."; Colon => ":"; Str(val: String) => val; Int(val: u32) => val; Float(val: f32) => val; } Slash: /; Plus: +; LParen: '('; RParen: ')'; Dot: .; Colon: :; [" \n\t"] >> ({ lext.advance(); lext = lext.spawn(); continue 'cycle; }); // `=` stuff EEE: (= = =); EE: (= =); EQ: =; '"' child { { child.advance() }; set string { String::new() }; rsome current { ck (current, '"') { { child.advance() }; done Str(string); }; { string.push(current) }; }; throw E002(child.spawn().position()); }; ["0123456789"] child { set number { String::new() }; set dot false; rsome (current, 'number) { set matched false; ck (current, ["0123456789"]) { mut matched true; { number.push(current) }; }; ck (current, '.') { if (dot) { done Float(number.parse().unwrap()); }; mut matched true; mut dot true; { number.push(current) }; }; {if !matched {break 'number}}; }; { println!("{number}") }; if (dot) { done Float(number.parse().unwrap()); }; done Int(number.parse().unwrap()); }; } #[test] fn test_single() { let contents = "+ /\n( .:) /"; let tokens = TokenType::tokenize(Lext::new(String::from("example"), contents)); use TokenType as L; assert_tokens(&tokens, &[ L::Plus, L::Slash, L::LParen, L::Dot, L::Colon, L::RParen, L::Slash, ]); } #[test] fn test_multiple() { let contents = "= ==\n=: ====.== ====="; let tokens = TokenType::tokenize(Lext::new(String::from("example"), contents)); use TokenType as L; assert_tokens(&tokens, &[ L::EQ, L::EE, L::EQ, L::Colon, L::EEE, L::EQ, L::Dot, L::EE, L::EEE, L::EE, ]); } #[test] fn test_string() { let contents = "+ /\n:( \"hello world?\"). /"; let tokens = TokenType::tokenize(Lext::new(String::from("example"), contents)); use TokenType as L; assert_tokens(&tokens, &[ L::Plus, L::Slash, L::Colon, L::LParen, L::Str("hello world?".into()), L::RParen, L::Dot, L::Slash, ]); } #[test] fn test_int() { let contents = "+ /\n:( 1234). /"; let tokens = TokenType::tokenize(Lext::new(String::from("example"), contents)); use TokenType as L; assert_tokens(&tokens, &[ L::Plus, L::Slash, L::Colon, L::LParen, L::Int(1234), L::RParen, L::Dot, L::Slash, ]); } #[test] fn test_float() { let contents = "+ /\n:( 12.34). /"; let tokens = TokenType::tokenize(Lext::new(String::from("example"), contents)); use TokenType as L; assert_tokens(&tokens, &[ L::Plus, L::Slash, L::Colon, L::LParen, L::Float(12.34), L::RParen, L::Dot, L::Slash, ]); } fn assert_tokens(tokens: &[Token], expected: &[TokenType]) { tokens.iter() .enumerate() .for_each(|(i, x)| if x.token_type != expected[i] { panic!("Expected: {expected:?}\nGot: {:?}", tokens.iter().map(|x| &x.token_type).collect::>()) }); }